Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.forth > #135258

Re: Code generation, in particular for iForth

From marcel hendrix <mhx@iae.nl>
Newsgroups comp.lang.forth
Subject Re: Code generation, in particular for iForth
Date 2026-07-24 18:06 +0200
Organization A noiseless patient Spider
Message-ID <11402j3$3a1dk$1@dont-email.me> (permalink)
References <2026Jul24.082234@mips.complang.tuwien.ac.at>

Show all headers | View raw


On 7/24/2026 8:22 AM, Anton Ertl wrote:
> Paul Curtis has a code generator for his Forth implementation that is
> much more sophisticated than what I have seen on other Forth
> implementations.  He asked me about the other Forth implementations,
> which resulted in me investigating iForth. 
[..]> Now on to iForth (using iForth-5.1-mini, which is quite old; if the
> code generation has changed substantially in the meantime, my results
> may be outdated):
> 
> iForth uses RSP as data-stack pointer, RBP as return-stack pointer,
> and in the canonical representation at definition boundaries all stack
> items are in memory.  iForth disassembles
[..]> - anton

Some comments.

The R-stack is used as the data stack to make the interface to
the OS / C server easier. It is a requirement that Forth can call
C and C can call Forth without too many restrictions.

iForth tokenizes words (when not larger than a certain size).
On definition, words are recursively expanded. This process stops
prematurely when input/output is detected. There is no need to
try and make I/O fast: it is limited by the OS interface anyway.

The fact that a word is present in the kernel ( like "+" ) is no
guarantee that that code is actually used in new words.
The kernel code for "+" has to be there so that it is possible to
use " ' + " interpretively.
The compiler breaks down kernel words to the smallest possible
primitive sequence (i.e. it looks at the type of arguments).

FORTH> : square dup * ;  ' square idis
$01455680  : square
$0145568A  pop           rbx
$0145568B  imul          rbx, rbx
$0145568F  push          rbx
$01455690  ;

FORTH> : ^4 square square ; ' ^4 idis
$01457F00  : ^4
$01457F0A  pop           rbx
$01457F0B  imul          rbx, rbx
$01457F0F  imul          rbx, rbx
$01457F13  push          rbx
$01457F14  ;

FORTH> : test 33 ^4 . ;  ok
FORTH> see test
Flags: ANSI
$01457F80  : test
$01457F8A  push          $00121881 d#
$01457F8F  jmp           .+10 ( $0124A102 ) offset NEAR

FORTH> : ^4+square+33  ^4 square 33 + ; see ^4+square+33
Flags: TOKENIZE, ANSI
: ^4+square+33  [trashed] [trashed] 33 + ;  ok

FORTH> : ttest 33 ^4+square+33 . ; see ttest
Flags: ANSI
$01458040  : ttest
$0145804A  mov           r8, $00000147:747C7122 q#
$01458054  push          r8
$01458056  jmp           .+10 ( $0124A102 ) offset NEAR
$0145805B  ;

A call to a word normally skips the first 10 bytes of the code (the
epilog cancels the intro).
Thus "jmp .+10" means "call ." .

FORTH> 8 VALUE input  : tttest input  ^4+square+33 dup + . ; see tttest
Flags: ANSI
$014588C0  : tttest
$014588CA  mov           rbx, $01458480 qword-offset
$014588D1  imul          rbx, $01458480 qword-offset
$014588D9  imul          rbx, rbx
$014588DD  imul          rbx, rbx
$014588E1  lea           rdi, [rbx #33 +] qword
$014588E5  lea           rax, [rbx #33 +] qword
$014588E9  lea           rbx, [rax rdi*1] qword
$014588ED  push          rbx
$014588EE  jmp           .+10 ( $0124A102 ) offset NEAR
$014588F3  ;

FORTH> : 2in ( a b -- c ) + ;  ok
FORTH> : t1 33 44 2in drop ;  ok
FORTH> : t2 input dup 2in ;  ok

When there are no memory references, sometimes code can be
optimized away completely:

FORTH> see t1
Flags: TOKENIZE, ANSI
: t1  33 44 [trashed] DROP ;  ok
FORTH> ' t1 idis
$01458A00  : t1
$01458A0A  ;

When there *are* memory references, iForth refetches the data as
it could have been changed by a different process or I/O operation.

FORTH> ' t2 idis
$01458A80  : t2
$01458A8A  mov           rbx, $01458480 qword-offset
$01458A91  add           rbx, $01458480 qword-offset
$01458A98  push          rbx
$01458A99  ;

There is no real register analysis. The assembler tries to match
certain patterns for which a nice binary code sequence is known:

FORTH> create ape 1 , 2 , 3 ,  ok
FORTH> : t4 ape swap cells + @ ; ' t4 idis
$014593C0  : t4
$014593CA  pop           rbx
$014593CB  push          [rbx*8 $01458F80 +] qword
$014593D2  ;

FORTH> : t5 t4 drop ; ' t5 idis
$01459440  : t5
$0145944A  pop           rbx
$0145944B  ;

-marcel

Back to comp.lang.forth | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Code generation, in particular for iForth anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-07-24 06:22 +0000
  Re: Code generation, in particular for iForth albert@SPENARNC.XS4ALL.NL - 2026-07-24 13:43 +0200
  Re: Code generation, in particular for iForth Hans Bezemer <the.beez.speaks@gmail.com> - 2026-07-24 16:05 +0200
  Re: Code generation, in particular for iForth marcel hendrix <mhx@iae.nl> - 2026-07-24 18:06 +0200
  Re: Code generation, in particular for iForth Paul Rubin <no.email@nospam.invalid> - 2026-07-24 15:58 -0700
    Re: Code generation, in particular for iForth anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-07-25 04:21 +0000
  Re: Code generation, in particular for iForth albert@SPENARNC.XS4ALL.NL - 2026-07-25 15:47 +0200
  Re: Code generation, in particular for iForth antispam@fricas.org (Waldek Hebisch) - 2026-07-25 19:28 +0000

csiph-web