Discussion:
D! and D@
(too old to reply)
Krishna Myneni
2024-03-22 13:59:24 UTC
Permalink
For typical implementations of 2! and 2@, the storage of double length
numbers in memory do not correspond to the native byte ordering for a
double length number. For these implementations, the high order bits of
the double number are on the top cell of the stack, which is at a lower
memory address. For example,

2variable x

5 s>d .s

0
5
ok

x 2!

x 8 dump \ on a 32-bit little-endian system

A0AE7C0 : 00 00 00 00 05 00 00 00 ok

In the Forth 2012 standard, and in prior standards, the representation
of double numbers on the stack seems to be allowed to be implementation
defined. Thus, on a 32-bit system, the stack order of a 64 bit double
number, the standard does not specify whether the high 32 bits of the
number are on top of the stack or the low 32 bits. Hence, we have the
rationale (A.8.6.1.1140) for the word D>S to abstract the conversion of
a double to single length number (instead of using DROP).

To overcome this issue, we could simply decide that double length
numbers on the stack have a specific ordering corresponding to their
native memory ordering on the system, but this appears to be contrary to
some existing implementations, and it may also break code.

A better way to do this is to explicitly define D! and D@, so that the
native memory storage order is consistent for this type.

For little-endian Forth systems which place the high order cell of the
double number on top of the stack, the definitions would be

: D! ( d a -- ) >r swap r> 2! ;
: D@ ( a -- d ) 2@ swap ;

=== Example ===
5 s>d x d!
ok
x 8 dump

A0AE7C0 : 05 00 00 00 00 00 00 00 ok

x d@ .s
0
5
ok
=== End Example ===

More generally, the problem with the double number word set is that it
attempts to use the same word set for two different types:

1) pairs of cell length numbers
2) double length integers

It would be better to separate the words for these two types, the latter
having prefix of "D" and the former having prefix "2".

--
Krishna Myneni
minforth
2024-03-22 14:32:12 UTC
Permalink
+1

I did this long ago when CPU endianness "violated the Forth standard".

That's also why my stack grows upwards and not downwards on system with
Intel CPUs: double number arithmetic is performed in stack memory, without
popping nybble or byte chunks off for reassembly, and pushing results back
in the "right" order.
Anton Ertl
2024-03-22 17:08:43 UTC
Permalink
Post by Krishna Myneni
In the Forth 2012 standard, and in prior standards, the representation
of double numbers on the stack seems to be allowed to be implementation
defined.
No, the standard defines it:

|3.1.4.1 Double-cell integers
|
|On the stack, the cell containing the most significant part of a
|double-cell integer shall be above the cell containing the least
|significant part.
Post by Krishna Myneni
Thus, on a 32-bit system, the stack order of a 64 bit double
number, the standard does not specify whether the high 32 bits of the
number are on top of the stack or the low 32 bits.
But it does.
Post by Krishna Myneni
Hence, we have the
rationale (A.8.6.1.1140) for the word D>S to abstract the conversion of
a double to single length number (instead of using DROP).
Have your read the rationale? It says:

|There exist number representations, e.g., the sign-magnitude
|representation, where reduction from double- to single-precision
|cannot simply be done with DROP. This word, equivalent to DROP on
|two's complement systems, desensitizes application code to number
|representation and facilitates portability.

So, the rationale says that, if you use the two's-complement
representation of negative numbers (as you do), D>S is equivalent to
DROP.
Post by Krishna Myneni
More generally, the problem with the double number word set is that it
1) pairs of cell length numbers
2) double length integers
Standard Forth has the 2... words that work for any pairs of cells,
whether they represent double numbers or something else. The
double-number wordset includes some of these words. Standard Forth
also has D... words for dealing with double-cell numbers. All these
words are in the DOUBLE or DOUBLE EXT wordset.
Post by Krishna Myneni
It would be better to separate the words for these two types, the latter
having prefix of "D" and the former having prefix "2".
So what would you do with the 2... words that are in the DOUBLE or
DOUBLE EXT wordset?

I don't think that moving words between wordsets has benefits that
exceed the costs.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: https://forth-standard.org/
EuroForth 2023: https://euro.theforth.net/2023
Krishna Myneni
2024-03-22 20:13:28 UTC
Permalink
Post by Anton Ertl
Post by Krishna Myneni
In the Forth 2012 standard, and in prior standards, the representation
of double numbers on the stack seems to be allowed to be implementation
defined.
|3.1.4.1 Double-cell integers
|
|On the stack, the cell containing the most significant part of a
|double-cell integer shall be above the cell containing the least
|significant part.
Ok. I did not look in the earlier part of the standard, only the section
dealing with the double number word set.
Post by Anton Ertl
Post by Krishna Myneni
Thus, on a 32-bit system, the stack order of a 64 bit double
number, the standard does not specify whether the high 32 bits of the
number are on top of the stack or the low 32 bits.
But it does.
...
Post by Anton Ertl
Post by Krishna Myneni
More generally, the problem with the double number word set is that it
1) pairs of cell length numbers
2) double length integers
Standard Forth has the 2... words that work for any pairs of cells,
whether they represent double numbers or something else. The
double-number wordset includes some of these words. Standard Forth
also has D... words for dealing with double-cell numbers. All these
words are in the DOUBLE or DOUBLE EXT wordset.
Yes, 2! and 2@ words work, but as I've pointed out, the storage for
double length numbers isn't consistent with the expected native storage
on a little endian system in which the stack grows towards lower
addresses. The 2! and 2@ words are better suited for dealing with pairs
of cell length numbers.
Post by Anton Ertl
Post by Krishna Myneni
It would be better to separate the words for these two types, the latter
having prefix of "D" and the former having prefix "2".
So what would you do with the 2... words that are in the DOUBLE or
DOUBLE EXT wordset?
I would place the 2... words into the Core Extensions word set.
dxf
2024-03-23 00:35:15 UTC
Permalink
Post by Anton Ertl
Post by Krishna Myneni
More generally, the problem with the double number word set is that it
1) pairs of cell length numbers
2) double length integers
Standard Forth has the 2... words that work for any pairs of cells,
whether they represent double numbers or something else.  The
double-number wordset includes some of these words.  Standard Forth
also has D... words for dealing with double-cell numbers.  All these
words are in the DOUBLE or DOUBLE EXT wordset.
An implementation could have D@ D! but it doesn't gain much and use is
restricted to fetching/storing. Anything involving mixed math will need
2@ 2! as it guarantees high-cell on top. When I've needed endianness,
perversely it was 'big endian'.
Anton Ertl
2024-03-23 06:28:36 UTC
Permalink
Post by Krishna Myneni
double length numbers isn't consistent with the expected native storage
on a little endian system in which the stack grows towards lower
addresses.
Let's see:

|6.1.0310 2! ( x1 x2 a-addr -- )
|
|Store the cell pair x1 x2 at a-addr, with x2 at a-addr and x1 at the
|next consecutive cell.

If an in-memory stack grows towards lower addresses, x2 is at the
lower address on the stack and also in memory, whereas x1 is at the
higher address on the stack and also in memory. So there is
consistency in this order.

The order corresponds to cell-wise big-endian, which is not consistent
with the byte-wise little-endian order that has won in the byte order
wars. However, I have not experienced problems from this lack of
consistency.

As for DUMP, there are people who argue for big-endian because the
byte dumps are more in line with the way we write arabic numbers in
our left-to-write script (the arabs have a right-to-left script but
also have the most significant digit leftmost). An option is to have
cell dumps, and then the big-endian cell order for doubles has a
consistent left-to-right digit order for both doubles and cells.

With byte dumps of little-endian cell data, there is also the
inconsistency of having each byte left-to-right and each cell bytewise
right-to-left. Not a real problem, but if you want consistency ...

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: https://forth-standard.org/
EuroForth 2023: https://euro.theforth.net/2023
minforth
2024-03-23 08:31:04 UTC
Permalink
Post by Krishna Myneni
double length numbers isn't consistent with the expected native storage
on a little endian system in which the stack grows towards lower
of cell length numbers.
I stumbled over another issue: when working with external libraries you
can't pass (unsigned) long long arguments/results without pre/post processing.
Anton Ertl
2024-03-23 17:44:59 UTC
Permalink
Post by minforth
I stumbled over another issue: when working with external libraries you
can't pass (unsigned) long long arguments/results without pre/post processing.
For direct arguments for calling C functions, there are lots of other
pitfalls. In particular, in general, you don't know the actual type
of the C argument: It can be, say, long on one platform and long long
on another. And C long long tends to be 64 bits whether Forth
double-cells are 64 bits or 128 bits.

So Gforth's C interface lets you specify the Forth types for calling a
C function; the C types are taken from the C declaraction (typically
in a .h file), and the interface converts between the two.

Another issue is C struct fields. Again, the actual C type of the
field may differ between platforms, and the correspondence between the
Forth and C types may also differ between platforms. I think that the
proper solution for that problem is value-flavoured fields, but at
least for now the Gforth C interface does not include this AFAIK.

In any case, if you want to access a 64-bit value in native byte order
on a system that may be a 32-bit system, Gforth (development) has:

|xd@ ( c-addr – ud ) gforth-1.0 “x-d-fetch”
|
|ud is the zero-extended 64-bit value stored at c_addr.
|
|xd! ( ud c-addr – ) gforth-1.0 “x-d-store”
|
|Store the bottom 64 bits of ud at c_addr.

This seems to be the kind of words you are looking for.

Interestingly, when we discussed memory-access words in the Forth200x
meeting last September, I presented the Gforth solution
<https://gforth.org/manual/Special-Memory-Accesses.html>, and was
given the task to make a proposal, based on these words, except that
the committee did not want to have the XD... words in the proposal.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: https://forth-standard.org/
EuroForth 2023: https://euro.theforth.net/2023
Krishna Myneni
2024-03-23 19:13:34 UTC
Permalink
On 3/22/24 08:59, Krishna Myneni wrote:
...
Post by Krishna Myneni
For little-endian Forth systems which place the high order cell of the
double number on top of the stack, the definitions would be
: D! ( d a -- ) >r swap r> 2! ;
...
Post by Krishna Myneni
More generally, the problem with the double number word set is that it
1) pairs of cell length numbers
2) double length integers
It would be better to separate the words for these two types, the latter
having prefix of "D" and the former having prefix "2".
On a possibly related note, standard Forth has D2* and D2/ but not
DLSHIFT and DRSHIFT. These are double number, non-arithmetic, left shift
and right shift words with a specified number of bits to shift.

D2* is the same as 1 DLSHIFT

but

D2/ is the same as 1 DRSHIFT only for positive double numbers

I had need for DLSHIFT and DRSHIFT recently, and this is what I came up
with.

\ u is the number of bits to shift
1 cells 8 * constant BITS_PER_CELL
0 value ubits

: DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
dup 0= IF drop EXIT THEN
BITS_PER_CELL min to ubits
ubits lshift swap
dup >r ubits msbits or
r> ubits lshift swap ;

: DRSHIFT ( ud u -- ud2 )
dup 0= IF drop EXIT THEN
BITS_PER_CELL min to ubits
swap ubits rshift
swap dup >r ubits lsbits or
r> ubits rshift ;

With x86, it should be possible to write efficient versions of DLSHIFT
and DRSHIFT using SHLD and SHRD instructions.

--
Krishna Myneni
Krishna Myneni
2024-03-23 19:16:18 UTC
Permalink
On 3/23/24 14:13, Krishna Myneni wrote:
...
Post by Krishna Myneni
I had need for DLSHIFT and DRSHIFT recently, and this is what I came up
with.
\ u is the number of bits to shift
1 cells 8 * constant BITS_PER_CELL
0 value ubits
: DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
    dup 0= IF drop EXIT THEN
    BITS_PER_CELL min to ubits
    ubits lshift swap
    dup >r ubits msbits or
    r> ubits lshift swap ;
: DRSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_CELL min to ubits
    swap ubits rshift
    swap dup >r ubits lsbits or
    r> ubits rshift ;
With x86, it should be possible to write efficient versions of DLSHIFT
and DRSHIFT using SHLD and SHRD instructions.
I left out the definitions of MSBITS and LSBITS (shown below):

Return the u least significant bits of cell value u1
\ as the most significant bits of u2
: lsbits ( u1 u -- u2 )
BITS_PER_CELL min
BITS_PER_CELL - negate
lshift ;

\ Return the u most significant bits of cell value u1
\ as the least significant bits of u2
: msbits ( u1 u -- u2 )
BITS_PER_CELL min
BITS_PER_CELL - negate
rshift ;

--
KM
Krishna Myneni
2024-03-24 01:47:07 UTC
Permalink
...
Post by Krishna Myneni
I had need for DLSHIFT and DRSHIFT recently, and this is what I came
up with.
\ u is the number of bits to shift
1 cells 8 * constant BITS_PER_CELL
0 value ubits
: DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
     dup 0= IF drop EXIT THEN
     BITS_PER_CELL min to ubits
     ubits lshift swap
     dup >r ubits msbits or
     r> ubits lshift swap ;
: DRSHIFT ( ud u -- ud2 )
     dup 0= IF drop EXIT THEN
     BITS_PER_CELL min to ubits
     swap ubits rshift
     swap dup >r ubits lsbits or
     r> ubits rshift ;
With x86, it should be possible to write efficient versions of DLSHIFT
and DRSHIFT using SHLD and SHRD instructions.
 Return the u least significant bits of cell value u1
\ as the most significant bits of u2
: lsbits ( u1 u -- u2 )
    BITS_PER_CELL min
    BITS_PER_CELL - negate
    lshift ;
\ Return the u most significant bits of cell value u1
\ as the least significant bits of u2
: msbits ( u1 u -- u2 )
    BITS_PER_CELL min
    BITS_PER_CELL - negate
    rshift ;
Just realized that these versions of DRSHIFT and DLSHIFT are limited to
shift of 0 bits -- 1 cell width in bits, rather than the general shift
count of 0 bits -- 2 cells width in bits. They have to be modified for
general use on double length numbers. Of course one can write the
general shifts in terms of these by applying them twice if needed.

--
Krishna
dxf
2024-03-24 02:18:38 UTC
Permalink
...
I had need for DLSHIFT and DRSHIFT recently, and this is what I came up with.
\ u is the number of bits to shift
1 cells 8 * constant BITS_PER_CELL
0 value ubits
: DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
     dup 0= IF drop EXIT THEN
     BITS_PER_CELL min to ubits
     ubits lshift swap
     dup >r ubits msbits or
     r> ubits lshift swap ;
: DRSHIFT ( ud u -- ud2 )
     dup 0= IF drop EXIT THEN
     BITS_PER_CELL min to ubits
     swap ubits rshift
     swap dup >r ubits lsbits or
     r> ubits rshift ;
With x86, it should be possible to write efficient versions of DLSHIFT and DRSHIFT using SHLD and SHRD instructions.
  Return the u least significant bits of cell value u1
\ as the most significant bits of u2
: lsbits ( u1 u -- u2 )
     BITS_PER_CELL min
     BITS_PER_CELL - negate
     lshift ;
\ Return the u most significant bits of cell value u1
\ as the least significant bits of u2
: msbits ( u1 u -- u2 )
     BITS_PER_CELL min
     BITS_PER_CELL - negate
     rshift ;
Just realized that these versions of DRSHIFT and DLSHIFT are limited to shift of 0 bits -- 1 cell width in bits, rather than the general shift count of 0 bits -- 2 cells width in bits. They have to be modified for general use on double length numbers. Of course one can write the general shifts in terms of these by applying them twice if needed.
Indeed. I was expecting:

: DLSHIFT ( ud u -- ud2 ) 0 ?DO D2* LOOP ;

DRSHIFT would require DU2/

Similarly missing from Standards was U2/ (the basis of RSHIFT).
Krishna Myneni
2024-03-24 13:04:06 UTC
Permalink
Post by dxf
...
I had need for DLSHIFT and DRSHIFT recently, and this is what I came up with.
\ u is the number of bits to shift
1 cells 8 * constant BITS_PER_CELL
0 value ubits
: DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
     dup 0= IF drop EXIT THEN
     BITS_PER_CELL min to ubits
     ubits lshift swap
     dup >r ubits msbits or
     r> ubits lshift swap ;
: DRSHIFT ( ud u -- ud2 )
     dup 0= IF drop EXIT THEN
     BITS_PER_CELL min to ubits
     swap ubits rshift
     swap dup >r ubits lsbits or
     r> ubits rshift ;
With x86, it should be possible to write efficient versions of DLSHIFT and DRSHIFT using SHLD and SHRD instructions.
  Return the u least significant bits of cell value u1
\ as the most significant bits of u2
: lsbits ( u1 u -- u2 )
     BITS_PER_CELL min
     BITS_PER_CELL - negate
     lshift ;
\ Return the u most significant bits of cell value u1
\ as the least significant bits of u2
: msbits ( u1 u -- u2 )
     BITS_PER_CELL min
     BITS_PER_CELL - negate
     rshift ;
Just realized that these versions of DRSHIFT and DLSHIFT are limited to shift of 0 bits -- 1 cell width in bits, rather than the general shift count of 0 bits -- 2 cells width in bits. They have to be modified for general use on double length numbers. Of course one can write the general shifts in terms of these by applying them twice if needed.
: DLSHIFT ( ud u -- ud2 ) 0 ?DO D2* LOOP ;
I had considered coding D2* with a loop using D2* but thought it would
be faster to do it with LSHIFT and RSHIFT. In the end I will implement
it as an intrinsic word in assembly, using the SHLD instruction.
Post by dxf
DRSHIFT would require DU2/
Yes, but SHRD is more efficient, if it is available.

--
KM
dxf
2024-03-24 14:12:14 UTC
Permalink
Post by dxf
...
I had need for DLSHIFT and DRSHIFT recently, and this is what I came up with.
\ u is the number of bits to shift
1 cells 8 * constant BITS_PER_CELL
0 value ubits
: DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
      dup 0= IF drop EXIT THEN
      BITS_PER_CELL min to ubits
      ubits lshift swap
      dup >r ubits msbits or
      r> ubits lshift swap ;
: DRSHIFT ( ud u -- ud2 )
      dup 0= IF drop EXIT THEN
      BITS_PER_CELL min to ubits
      swap ubits rshift
      swap dup >r ubits lsbits or
      r> ubits rshift ;
With x86, it should be possible to write efficient versions of DLSHIFT and DRSHIFT using SHLD and SHRD instructions.
   Return the u least significant bits of cell value u1
\ as the most significant bits of u2
: lsbits ( u1 u -- u2 )
      BITS_PER_CELL min
      BITS_PER_CELL - negate
      lshift ;
\ Return the u most significant bits of cell value u1
\ as the least significant bits of u2
: msbits ( u1 u -- u2 )
      BITS_PER_CELL min
      BITS_PER_CELL - negate
      rshift ;
Just realized that these versions of DRSHIFT and DLSHIFT are limited to shift of 0 bits -- 1 cell width in bits, rather than the general shift count of 0 bits -- 2 cells width in bits. They have to be modified for general use on double length numbers. Of course one can write the general shifts in terms of these by applying them twice if needed.
: DLSHIFT ( ud u -- ud2 ) 0 ?DO D2* LOOP ;
I had considered coding D2* with a loop using D2* but thought it would be faster to do it with LSHIFT and RSHIFT. In the end I will implement it as an intrinsic word in assembly, using the SHLD instruction.
Post by dxf
DRSHIFT would require DU2/
Yes, but SHRD is more efficient, if it is available.
Those are implementation details. Ideally one would have both words - one bit shift and
multiple bit shift. To use 2* to shift one way, and 1 RSHIFT to shift the other seemed
incongruous so I implemented U2/ . The latter also happened to be shorter/faster.
Anton Ertl
2024-03-24 07:37:40 UTC
Permalink
Post by Krishna Myneni
On a possibly related note, standard Forth has D2* and D2/ but not
DLSHIFT and DRSHIFT. These are double number, non-arithmetic, left shift
and right shift words with a specified number of bits to shift.
Gforth has DLSHIFT, DRSHIFT, and DARSHIFT (the latter works on signed
doubles). They are used exactly 0 times in the Gforth image. There
are uses in the cross-compiler (for building 64-bit images on 32-bit
machines) and in MINOS2.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: https://forth-standard.org/
EuroForth 2023: https://euro.theforth.net/2023
mhx
2024-03-24 09:16:10 UTC
Permalink
Post by Anton Ertl
Gforth has DLSHIFT, DRSHIFT, and DARSHIFT (the latter works on signed
doubles). They are used exactly 0 times in the Gforth image. There
are uses in the cross-compiler (for building 64-bit images on 32-bit
machines) and in MINOS2.
I appear not to have an equivalent for DARSHIFT (maybe coded in
high-level somewhere), but the other two appear in my examples (some
13,225 files in total) :

Searching for: DLSHIFT
D:\dfwforth\examples\bignum\lperfect.frt(351): : d2^x ( n -- d ) 1. ROT
D:\dfwforth\examples\ctpuzzle\ctpuzzle.frt(598): 1. BLOECKE DLSHIFT
D:\dfwforth\examples\ctpuzzle\ctpuzzle.frt(599): 1. BLOECKE #32 - DLSHIF
D:\dfwforth\examples\ctpuzzle\ctpuzzle.frt(638): :NONAME #64 0 ?DO 1. I
D:\dfwforth\examples\digsound\3drums.frt(181): x TLoupe DLSHIFT Xmax 2*
D:\dfwforth\examples\euler\euler162.frt(56): : SOLUTIONS ( -- ud ) 0. #1
D:\dfwforth\examples\euler\euler22.frt(69): #12 MIN DUP >R 0 ?DO C@+ 1+
D:\dfwforth\examples\euler\euler22.frt(70): hash #12 R> - 5 * DLSHIFT n
D:\dfwforth\examples\fermat\perfect2.frt(89): : d2^x ( n -- d ) 1. ROT
D:\dfwforth\examples\graphics\turtle.frt(314): step U>D #19 DLSHIFT ( 0
D:\dfwforth\examples\misc\lzwpack.frt(106): /bits 8 - DLSHIFT SWAP
D:\dfwforth\examples\misc\lzwpack.frt(126): /bits 8 DO 8 DLSHIFT SWAP
D:\dfwforth\examples\misc\mullen4.frt(102): >R 3 DLSHIFT
D:\dfwforth\examples\misc\mullen4.frt(113): 3 DLSHIFT
D:\dfwforth\examples\misc\pentoalbert.frt(109): \ : DLSHIFT >R SWAP DU
D:\dfwforth\examples\mix\compat.frt(83): : DLSHIFT ( d1 n -- d2 n )
D:\dfwforth\examples\mix\compat.frt(84): ABORT" DLSHIFT : make your home
D:\dfwforth\examples\mix\mix.frt(810): U>D [ /bytes /bits * ] LITERAL DL
D:\dfwforth\examples\mix\mix.frt(938): CALC-ADDR ABS 11 MOD /bits * DLSH
D:\dfwforth\examples\mix\mix.frt(951): 2SWAP S> DLSHIFT DOR USPLIT10
D:\dfwforth\examples\mix\mix.frt(956): 2DUP [ 10 /bits * ] LITERAL S - D
D:\dfwforth\examples\mix\mix.frt(1874): U>D [ /bytes /bits * ] LITERAL D
D:\dfwforth\examples\numeric\cubicsine.frt(58): : d4* 2 DLSHIFT ;
D:\dfwforth\examples\numeric\cubicsine.frt(61): : d16* 4 DLSHIFT ;
D:\dfwforth\examples\shoot-2001-06-05\bench\meteor\mmeteor.frt(186): 0.
D:\dfwforth\examples\sod64\cross.frt(211): U>D OPSHIFT @ DLSHIFT
D:\dfwforth\examples\sod64\cross.frt(225): "HEADER OVER C, 1 DLSHIFT
D:\dfwforth\examples\sod64\longhand.frt(44): -- Use DLSHIFT32 with shift
D:\dfwforth\examples\sod64\longhand.frt(48): QuotientLow 1 DLSHIFT32
D:\dfwforth\examples\sod64\longhand.frt(49): QuotientHigh 1 DLSHIFT32 SW
D:\dfwforth\examples\sod64\longhand.frt(50): Remainder 1 DLSHIFT32 SW
D:\dfwforth\examples\sod64\sod64.frt(242): : DO_LSHIFT 2POPR DROP DLSHI
D:\dfwforth\examples\threads\pipid2.frt(23): \ : DLSHIFT 0 ?DO D2* LO
D:\dfwforth\examples\threads\pipid2.frt(132): 3 DLSHIFT
D:\dfwforth\examples\threads\pipidch.frt(223): : *10 ( d -- 10*d ) 2DUP
D:\dfwforth\examples\threads\pipidchm.frt(225): : *10 ( d -- 10*d ) 2DUP
D:\dfwforth\examples\threads\pipidn.frt(24): \ : DLSHIFT 0 ?DO D2* LO
D:\dfwforth\examples\threads\pipidn.frt(147): : *10 ( d -- 10*d ) 2DUP D
D:\dfwforth\include\bignum.frt(411): @- U>D places DLSHIFT carry U>D D
D:\dfwforth\include\hexfloat.frt(74): [ELSE] : lshiftnum ( n -- ) the
D:\dfwforth\include\hexfloat.frt(75): : dl1shift ( u32lo1 u32hi1 n -- u3
D:\dfwforth\include\hexfloat.frt(197): ELSE OVER C@ #16 DIGIT? IF U>D
D:\dfwforth\include\hexfloat.frt(205): BEGIN #bits #want < WHILE 4 DLS
D:\dfwforth\include\intfft.frt(73): re2 im1 M* re1 im2 M* D+ #SHIFTER D
D:\dfwforth\include\intfft.frt(74): re1 re2 M* im1 im2 M* D- #SHIFTER D
D:\dfwforth\include\intfft.frt(152): M* #SHIFTER DLSHIFT NIP
D:\dfwforth\include\miscutil.frt(1090): : _int ( ud1 -- ud2 ) 2 DL
D:\dfwforth\include\miscutil.frt(1091): : _sxint ( ud1 -- ud2 ) 2 DL
D:\dfwforth\include\miscutil.frt(1092): : _double ( ud1 -- ud2 ) 2 DL
D:\dfwforth\include\miscutil.frt(1093): : _float ( ud1 -- ud2 ) 2 DL
D:\dfwforth\include\miscutil.frt(2001): >R 2 DLSHIFT R>
D:\dfwforth\include\quads.frt(87): ss IF ss DLSHIFT
D:\dfwforth\include\quads.frt(90): ss DLSHIFT low-dividend 2!
Found 53 occurrence(s) in 26 file(s), 1252 ms

Searching for: DRSHIFT
D:\dfwforth\examples\ctpuzzle\ctpuzzle.frt(963): p BLOECKE #32 - DRSHIFT
D:\dfwforth\examples\ctpuzzle\ctpuzzle.frt(989): p BLOECKE DRSHIFT DROP
D:\dfwforth\examples\euler\euler22.frt(74): CR #12 0 DO name #11 I - 5
D:\dfwforth\examples\misc\floatemu.frt(45): 1 DRSHIFT ;
D:\dfwforth\examples\misc\floatemu.frt(49): >R DUP 2@ R> DRSHIFT
D:\dfwforth\examples\misc\lzwpack.frt(113): 8 DRSHIFT
D:\dfwforth\examples\misc\lzwpack.frt(130): /bits 8 - DRSHIFT
D:\dfwforth\examples\misc\mullen4.frt(77): 3 DRSHIFT R> ;
D:\dfwforth\examples\misc\pentoalbert.frt(108): \ : DRSHIFT 2DUP RSHIF
D:\dfwforth\examples\misc\pentoalbert.frt(212): WHILE SWAP HEIGHT DRSHI
D:\dfwforth\examples\mix\compat.frt(86): : DRSHIFT ( d1 n -- d2 n )
D:\dfwforth\examples\mix\compat.frt(87): ABORT" DRSHIFT : make your home
D:\dfwforth\examples\mix\mix.frt(926): [ /bytes /bits * ] LITERAL DRSHIF
D:\dfwforth\examples\mix\mix.frt(942): CALC-ADDR ABS 11 MOD /bits * DRSH
D:\dfwforth\examples\mix\mix.frt(950): 2DUP [ 10 /bits * ] LITERAL S - D
D:\dfwforth\examples\mix\mix.frt(957): 2SWAP S> DRSHIFT DOR USPLIT10
D:\dfwforth\examples\sod64\cross.frt(243): OVER 1 AND 0= ABORT" Instruct
D:\dfwforth\examples\sod64\cross.frt(256): 5 DRSHIFT
D:\dfwforth\examples\sod64\sod64.frt(243): : DO_RSHIFT 2POPR DROP DRSHI
D:\dfwforth\examples\sod64\sod64.frt(332): ir 1 DRSHIFT TO ir
D:\dfwforth\examples\sod64\sod64.frt(335): ir 5 DRSHIFT TO ir
D:\dfwforth\examples\sod64\sod64.frt(388): ir 1 DRSHIFT TO ir
D:\dfwforth\examples\sod64\sod64.frt(392): ir 5 DRSHIFT TO ir
D:\dfwforth\include\bignum.frt(433): @+ 0 SWAP places DRSHIFT 0 carry
D:\dfwforth\include\hexfloat.frt(78): S> DRSHIFT R> U>D D+ ; PRIVATE
D:\dfwforth\include\hexfloat.frt(81): S> DRSHIFT R> U>D D+ ; PRIVATE
D:\dfwforth\include\hexfloat.frt(90): 1 OF #12 DRSHIFT # ENDOF
D:\dfwforth\include\hexfloat.frt(91): 2 OF 8 DRSHIFT # # ENDOF
D:\dfwforth\include\hexfloat.frt(92): 3 OF 4 DRSHIFT # # # ENDOF
D:\dfwforth\include\miscutil.frt(1106): 2 DRSHIFT
D:\dfwforth\include\miscutil.frt(1146): 2 DRSHIFT
D:\dfwforth\include\miscutil.frt(1974): \ UM+ 1 DRSHIFT
D:\dfwforth\include\miscutil.frt(2015): 2DUP 1 DRSHIFT DROP
D:\dfwforth\include\miscutil.frt(2019): U+. 1 DRSHIFT DROP
D:\dfwforth\include\quads.frt(52): : DU2/ 1 DRSHIFT ;
D:\dfwforth\include\quads.frt(88): 2OVER cell-size 2* ss - DRSHIFT D+
D:\dfwforth\include\quads.frt(120): r0 2@ m 2@ D- ss DRSHIFT
Found 37 occurrence(s) in 14 file(s), 7388 ms

-marcel
Krishna Myneni
2024-03-24 13:08:39 UTC
Permalink
Post by Anton Ertl
Post by Krishna Myneni
On a possibly related note, standard Forth has D2* and D2/ but not
DLSHIFT and DRSHIFT. These are double number, non-arithmetic, left shift
and right shift words with a specified number of bits to shift.
Gforth has DLSHIFT, DRSHIFT, and DARSHIFT (the latter works on signed
doubles). They are used exactly 0 times in the Gforth image. There
are uses in the cross-compiler (for building 64-bit images on 32-bit
machines) and in MINOS2.
I'm considering writing a portable IEEE 754-compatible quad-precision
floating point arithmetic module in Forth, along the lines of the C++
package QPFloat [1]. For a 64-bit Forth, DLSHIFT and DRSHIFT are useful
primitives.

--
Krishna
Loading...