Path: csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!.POSTED!not-for-mail From: peter Newsgroups: comp.lang.forth Subject: F>R, FR@ and FR> Float to return stack words Date: Fri, 28 Aug 2026 00:04:28 +0200 Organization: A noiseless patient Spider Lines: 129 Message-ID: <20260828000428.00007e53@tin.it> MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Injection-Date: Thu, 27 Aug 2026 22:04:31 +0000 (UTC) Injection-Info: dont-email.me; logging-data="1881280"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18zV8JOkfi73koc90yzM9/nfdmrhJiDANM="; posting-host="f0b46bcd66052ae8cc5b610ef835aa06" Cancel-Lock: sha1:e5pI5RR3JE1tdN7YspAso31EDU8= sha256:Gs3gZMlXpEpWIssviaibCInYReiAohzrvY8tcZ5Jlm4= sha1:39fqu1q+sKo/IsU+Uryk7vLmNmQ= sha256:TwtH8IllUxlGFFoRKpF6jWR61JtAVuq5pFHugh+8sng= X-Newsreader: Claws Mail 4.4.0 (GTK 3.24.51; x86_64-w64-mingw32) Xref: csiph.com comp.lang.forth:135446 I recently wanted to adapt compelx-kahan.fs, the complex implementation by Julian V. Noble and David N. Williams, to the capabilities of ntf64/lxf64. One thing I wanted to get away from was the Baden-style float locals, fa fb .. and to-fa to-fb .. and the use of temporary buffers. I replaced them with F>R, FR@ and FR>. Moving floats to the return stack. This works well as both stacks are 64 bits. The effect was very good. Taking Z* as an example: Original Z* using 2 temporary buffers : z* (f: x y u v -- x*u-y*v x*v+y*u) ( Uses the algorithm followed by jvn: [x+iy]*[u+iv] = [[x+y]*u - y*[u+v]] + i[[x+y]*u + x*[v-u]] Requires 3 multiplications and 5 additions. ) zdup f+ (f: x y u v u+v) [ fnoname ] literal f! (f: x y u v) fover f- (f: x y u v-u) [ fnoname float+ ] literal f! (f: x y u) frot fdup (f: y u x x) [ fnoname float+ ] literal f@ (f: y u x x v-u) f* [ fnoname float+ ] literal f! (f: y u x) frot fdup (f: u x y y) [ fnoname ] literal f@ (f: u x y y u+v) f* [ fnoname ] literal f! (f: u x y) f+ f* fdup (f: u*[x+y] u*[x+y]) [ fnoname ] literal f@ f- (f: u*[x+y] x*u-y*v) fswap [ fnoname float+ ] literal f@ (f: x*u-y*v u*[x+y] x*[v-u]) f+ ; (f: x*u-y*v x*v+y*u) With more or less direct exchange to using the return stack I got : z* ( f: x y u v -- x*u-y*v x*v+y*u) zdup f+ f>r ( f: x y u v r: u+v) fover f- f>r ( f: x y u r: u+v v-u) frot fdup fr> ( f: y u x x v-u r: u+v) f* ( f: y u x x*'v-u' r: u+v) fr> fswap f>r f>r ( f: y u x r: x*'v-u' u+v) frot fdup fr> ( f: u x y y u+v r: x*'v-u') f* f>r ( f: u x y r: x*'v-u' y*'u+v') f+ f* fdup fr> f- fswap fr> ( f: x*u-y*v u*[x+y] x*[v-u]) f+ ; ( f: x*u-y*v x*v+y*u) The original give the following assembler code seea Z* 0x4291A0 C4C17B584D00 vaddsd xmm1, xmm0, qword ptr [r13] 0x4291A6 C5FB110DD2965D00 vmovsd qword ptr [rel 0xA02880], xmm1 0x4291AE C4C17B5C4500 vsubsd xmm0, xmm0, qword ptr [r13] 0x4291B4 C5FB1105CC965D00 vmovsd qword ptr [rel 0xA02888], xmm0 0x4291BC C5FB1005C4965D00 vmovsd xmm0, qword ptr [rel 0xA02888] 0x4291C4 C4C17B594510 vmulsd xmm0, xmm0, qword ptr [r13+0x10] 0x4291CA C5FB1105B6965D00 vmovsd qword ptr [rel 0xA02888], xmm0 0x4291D2 C5FB1005A6965D00 vmovsd xmm0, qword ptr [rel 0xA02880] 0x4291DA C4C17B594508 vmulsd xmm0, xmm0, qword ptr [r13+0x8] 0x4291E0 C5FB110598965D00 vmovsd qword ptr [rel 0xA02880], xmm0 0x4291E8 C4C17B104508 vmovsd xmm0, qword ptr [r13+0x8] 0x4291EE C4C17B584510 vaddsd xmm0, xmm0, qword ptr [r13+0x10] 0x4291F4 C4C17B594500 vmulsd xmm0, xmm0, qword ptr [r13] 0x4291FA C5FB100D7E965D00 vmovsd xmm1, qword ptr [rel 0xA02880] 0x429202 C5FB5CD1 vsubsd xmm2, xmm0, xmm1 0x429206 C5FB100D7A965D00 vmovsd xmm1, qword ptr [rel 0xA02888] 0x42920E C5F358C8 vaddsd xmm1, xmm1, xmm0 0x429212 C5F310C1 vmovsd xmm0, xmm1, xmm1 0x429216 C4C17B115510 vmovsd qword ptr [r13+0x10], xmm2 0x42921C 4D8D6D10 lea r13, [r13+0x10] 0x429220 C3 ret 129 bytes, 21 instructions ok There are 3 multiplications, 5 add/sub and 8 loads/stores to the buffer The revised version gives seea Z* 0x428A50 C4C17B584D00 vaddsd xmm1, xmm0, qword ptr [r13] 0x428A56 C4C17B5C4500 vsubsd xmm0, xmm0, qword ptr [r13] 0x428A5C C4C17B594510 vmulsd xmm0, xmm0, qword ptr [r13+0x10] 0x428A62 C4C173594D08 vmulsd xmm1, xmm1, qword ptr [r13+0x8] 0x428A68 C4C17B105508 vmovsd xmm2, qword ptr [r13+0x8] 0x428A6E C4C16B585510 vaddsd xmm2, xmm2, qword ptr [r13+0x10] 0x428A74 C4C16B595500 vmulsd xmm2, xmm2, qword ptr [r13] 0x428A7A C5EB5CD9 vsubsd xmm3, xmm2, xmm1 0x428A7E C5FB58C2 vaddsd xmm0, xmm0, xmm2 0x428A82 C4C17B115D10 vmovsd qword ptr [r13+0x10], xmm3 0x428A88 4D8D6D10 lea r13, [r13+0x10] 0x428A8C C3 ret 61 bytes, 12 instructions ok Half the size and all memory loads/stores gone. With the returns stack use I can also do things like : +ulp f>r r> 1+ >r fr> ; ok 0e +ulp e. 5e-324 ok 0e +ulp fh. 0x0.0000000000001p-1022 ok seea +ulp 0x42A260 C4E1F97EC0 vmovq rax, xmm0 0x42A265 48FFC0 inc rax 0x42A268 C4E1F96EC0 vmovq xmm0, rax 0x42A26D C3 ret 14 bytes, 4 instructions ok An alternative I considered was to introduce float locals. It would probably have been more complicated. The result, in the best case, would be equal in the generated code. The problem with locals is the scope, that is to the end of the word. Of course the source would be more readable! I might still implement float locals. What do you have in your system? BR Peter