Under Linux on ARM64 trying to set machine stack pointer to
value which is not divisible by 16 leads to error. AFAICS this
means that in default setting machine stack pointer is not
usable as as Forth user stack pointer or return stack pointer.
I wonder what Forth implementation do? Do they use different
registers as user and return stack pointer? Maybe they use
machine stack pointer for control and locals? Or maybe some
system magic removes the restriction?
On Thu, 3 Sep 2026 20:51:14 -0000 (UTC)
antispam@fricas.org (Waldek Hebisch) wrote:
Under Linux on ARM64 trying to set machine stack pointer to
value which is not divisible by 16 leads to error. AFAICS this
means that in default setting machine stack pointer is not
usable as as Forth user stack pointer or return stack pointer.
I wonder what Forth implementation do? Do they use different
registers as user and return stack pointer? Maybe they use
machine stack pointer for control and locals? Or maybe some
system magic removes the restriction?
Here is the register assignments for the token VM I wrote for
ARM64 for lxf 64
/*
VM8 assembler based aarch64 vm for lxf64 Forth
Copyright 2020 Peter FElth
Register usage
X19 ip vm instruction pointer
x20 TOP top of stack cached in x20
x21 sp vm stack pointer
x22 rp vm return stack pointer
x23 fp vm floating point stack pointer
x24 lp vm local stack pointer
x25 idx loop index of innermost loop
x26 limit loop limit of innermost loop
x27 address of jump table
d8 FTOP top of float stack cached in d8
sequence to nest to next opcode is RELOAD
ldrb w0, [x19], 1 load opcode byte at ip, advance ip by 1
ldr x2, [x27, x0, lsl 3] load address of machine code from jmptable+opcode*8
br x2 jump to next machine code
*/
There are just 2 calls in the hole VM, in these cases 2 registers are
pushed to maintain 16 byte alignment.
You can avoid the 16 byte alignment by using a register other then sp
for the processor stack. My tests showed this code to be about 30% slower
in execution speed.
BR
Peter
In article <20260904073311.00003526@tin.it>,
peter <peter.noreply@tin.it> wrote:
On Thu, 3 Sep 2026 20:51:14 -0000 (UTC)
antispam@fricas.org (Waldek Hebisch) wrote:
Under Linux on ARM64 trying to set machine stack pointer to
value which is not divisible by 16 leads to error. AFAICS this
means that in default setting machine stack pointer is not
usable as as Forth user stack pointer or return stack pointer.
I wonder what Forth implementation do? Do they use different
registers as user and return stack pointer? Maybe they use
machine stack pointer for control and locals? Or maybe some
system magic removes the restriction?
Here is the register assignments for the token VM I wrote for
ARM64 for lxf 64
/*
VM8 assembler based aarch64 vm for lxf64 Forth
Copyright 2020 Peter F|nlth
Register usage
X19 ip vm instruction pointer
x20 TOP top of stack cached in x20
x21 sp vm stack pointer
x22 rp vm return stack pointer
x23 fp vm floating point stack pointer
x24 lp vm local stack pointer
x25 idx loop index of innermost loop
x26 limit loop limit of innermost loop
x27 address of jump table
d8 FTOP top of float stack cached in d8
sequence to nest to next opcode is RELOAD
ldrb w0, [x19], 1 load opcode byte at ip, advance ip by 1
ldr x2, [x27, x0, lsl 3] load address of machine code from jmptable+opcode*8
br x2 jump to next machine code
*/
There are just 2 calls in the hole VM, in these cases 2 registers are >>pushed to maintain 16 byte alignment.
You can avoid the 16 byte alignment by using a register other then sp
for the processor stack. My tests showed this code to be about 30% slower >>in execution speed.
The problem you have is unrelated to linux, but more a c-compatibility.
With my assembler Forth I have no problem in linux.
All system calls are done via SVC and filling registers X0, X1 X2 X3 X4 etc. The stack pointer SP plays no role in the whole Forth, it is arbitrarily mapped to R13. I could map SPO to x21 equally well.
albert@spenarnc.xs4all.nl wrote:
In article <20260904073311.00003526@tin.it>,
peter <peter.noreply@tin.it> wrote:
On Thu, 3 Sep 2026 20:51:14 -0000 (UTC)
antispam@fricas.org (Waldek Hebisch) wrote:
Under Linux on ARM64 trying to set machine stack pointer to
value which is not divisible by 16 leads to error. AFAICS this
means that in default setting machine stack pointer is not
usable as as Forth user stack pointer or return stack pointer.
I wonder what Forth implementation do? Do they use different
registers as user and return stack pointer? Maybe they use
machine stack pointer for control and locals? Or maybe some
system magic removes the restriction?
Here is the register assignments for the token VM I wrote for
ARM64 for lxf 64
/*
VM8 assembler based aarch64 vm for lxf64 Forth
Copyright 2020 Peter FElth
Register usage
X19 ip vm instruction pointer
x20 TOP top of stack cached in x20
x21 sp vm stack pointer
x22 rp vm return stack pointer
x23 fp vm floating point stack pointer
x24 lp vm local stack pointer
x25 idx loop index of innermost loop
x26 limit loop limit of innermost loop
x27 address of jump table
d8 FTOP top of float stack cached in d8
sequence to nest to next opcode is RELOAD
ldrb w0, [x19], 1 load opcode byte at ip, advance ip by 1
ldr x2, [x27, x0, lsl 3] load address of machine code from jmptable+opcode*8
br x2 jump to next machine code
*/
There are just 2 calls in the hole VM, in these cases 2 registers are >>pushed to maintain 16 byte alignment.
You can avoid the 16 byte alignment by using a register other then sp
for the processor stack. My tests showed this code to be about 30% slower >>in execution speed.
The problem you have is unrelated to linux, but more a c-compatibility.
With my assembler Forth I have no problem in linux.
All system calls are done via SVC and filling registers X0, X1 X2 X3 X4 etc.
The stack pointer SP plays no role in the whole Forth, it is arbitrarily mapped to R13. I could map SPO to x21 equally well.
I wrote "machine stack pointer" (or if you prefer register number 31)
because it is special on ARM64. Of course, Forth can use a different register, but not using machine stack pointer is a waste. C
compatibility makes this waste more painful, because there are
only 11 registers not touched by C. For traditional Forth
implementations this is enough, but I am looking at generating
machine code.
r r> r@ can be done withstp xzr, x20, [sp, -16]!
On Thu, 3 Sep 2026 20:51:14 -0000 (UTC)
antispam@fricas.org (Waldek Hebisch) wrote:
Under Linux on ARM64 trying to set machine stack pointer to
value which is not divisible by 16 leads to error. AFAICS this
means that in default setting machine stack pointer is not
usable as as Forth user stack pointer or return stack pointer.
I wonder what Forth implementation do? Do they use different
registers as user and return stack pointer? Maybe they use
machine stack pointer for control and locals? Or maybe some
system magic removes the restriction?
Here is the register assignments for the token VM I wrote for
ARM64 for lxf 64
/*
VM8 assembler based aarch64 vm for lxf64 Forth
Copyright 2020 Peter F|nlth
Register usage
X19 ip vm instruction pointer
x20 TOP top of stack cached in x20
x21 sp vm stack pointer
x22 rp vm return stack pointer
x23 fp vm floating point stack pointer
x24 lp vm local stack pointer
x25 idx loop index of innermost loop
x26 limit loop limit of innermost loop
x27 address of jump table
d8 FTOP top of float stack cached in d8
sequence to nest to next opcode is RELOAD
ldrb w0, [x19], 1 load opcode byte at ip, advance ip by 1
ldr x2, [x27, x0, lsl 3] load address of machine code from jmptable+opcode*8
br x2 jump to next machine code
*/
There are just 2 calls in the hole VM, in these cases 2 registers are
pushed to maintain 16 byte alignment.
You can avoid the 16 byte alignment by using a register other then sp
for the processor stack. My tests showed this code to be about 30% slower
in execution speed.
peter <peter.noreply@tin.it> wrote:
On Thu, 3 Sep 2026 20:51:14 -0000 (UTC)
antispam@fricas.org (Waldek Hebisch) wrote:
Under Linux on ARM64 trying to set machine stack pointer to
value which is not divisible by 16 leads to error. AFAICS this
means that in default setting machine stack pointer is not
usable as as Forth user stack pointer or return stack pointer.
I wonder what Forth implementation do? Do they use different
registers as user and return stack pointer? Maybe they use
machine stack pointer for control and locals? Or maybe some
system magic removes the restriction?
Here is the register assignments for the token VM I wrote for
ARM64 for lxf 64
/*
VM8 assembler based aarch64 vm for lxf64 Forth
Copyright 2020 Peter FElth
Register usage
X19 ip vm instruction pointer
x20 TOP top of stack cached in x20
x21 sp vm stack pointer
x22 rp vm return stack pointer
x23 fp vm floating point stack pointer
x24 lp vm local stack pointer
x25 idx loop index of innermost loop
x26 limit loop limit of innermost loop
x27 address of jump table
d8 FTOP top of float stack cached in d8
sequence to nest to next opcode is RELOAD
ldrb w0, [x19], 1 load opcode byte at ip, advance ip by 1
ldr x2, [x27, x0, lsl 3] load address of machine code from jmptable+opcode*8
br x2 jump to next machine code
*/
There are just 2 calls in the hole VM, in these cases 2 registers are pushed to maintain 16 byte alignment.
You can avoid the 16 byte alignment by using a register other then sp
for the processor stack. My tests showed this code to be about 30% slower in execution speed.
What do you compare? Token threaded code to traditional threaded
code using memory addresses?
On ARM64 calls have range +-128MB relative. So if the program code
does not exceed 128MB, then subroutine threaded code is smaller
than traditional threaded code and probably quite a bit faster.
Drawback is that non-leaf words need to push and pop return
address from the machine stack, using 16 bytes of stack space.
albert@spenarnc.xs4all.nl wrote:
I wrote "machine stack pointer" (or if you prefer register number 31)
because it is special on ARM64. Of course, Forth can use a different >register, but not using machine stack pointer is a waste. C
compatibility makes this waste more painful, because there are
only 11 registers not touched by C. For traditional Forth
implementations this is enough, but I am looking at generating
machine code.
Waldek Hebisch--
there are only 11 registers not touched by C.
antispam@fricas.org (Waldek Hebisch) writes:
there are only 11 registers not touched by C.
I missed some parts of this thread but why would a C compiler leave 11 registers untouched? Usually a compiler with register allocation will
use all the registers, unless you ask it to reserve some for other
purposes.
| Sysop: | Amessyroom |
|---|---|
| Location: | Fayetteville, NC |
| Users: | 74 |
| Nodes: | 6 (0 / 6) |
| Uptime: | 123:48:21 |
| Calls: | 1,194 |
| Files: | 1,352 |
| Messages: | 290,603 |