• DLSHIFT and DRSHIFT

    From Krishna Myneni@21:1/5 to All on Tue Mar 26 17:01:53 2024
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior
    thread.

    Tests needed.

    --
    Krishna Myneni


    === Start Code ===

    1 cells 3 lshift constant BITS_PER_CELL
    BITS_PER_CELL 2* constant BITS_PER_DOUBLE

    \ 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 ;

    0 value ubits

    \ u is the number of bits to shift

    : DLSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL > IF
    drop \ high double has been left shifted out
    ubits BITS_PER_CELL - lshift
    0 swap \ new low double
    ELSE
    ubits lshift swap
    dup >r
    ubits msbits or
    r> ubits lshift
    swap
    THEN ;

    : DRSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL > IF
    nip \ low double has been right shifted out
    ubits BITS_PER_CELL - rshift
    0 \ new high double
    ELSE
    swap ubits rshift
    swap dup >r
    ubits lsbits or
    r> ubits rshift
    THEN ;

    === End Code ===

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Krishna Myneni on Tue Mar 26 19:57:49 2024
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior thread.

    Tests needed.

    Just tested DLSHIFT and found weird things going on. Traced the problem
    to LSHIFT.


    kforth64

    1 64 LSHIFT . \ expected to get zero
    1 \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    Gforth does the same thing

    1 64 LSHIFT . 1
    1 65 LSHIFT . 2
    etc.


    We shouldn't have an ambiguous condition here because of some
    idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Krishna Myneni on Tue Mar 26 22:14:04 2024
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior thread.
    ...

    This version fixes the issue with the ambiguity of LSHIFT and RSHIFT,
    and gives the behavior of DLSHIFT and DRSHIFT which I want. Tests
    included below for 32-bit and 64-bit systems.

    --
    KM

    === dshift.4th ===
    \ dshift.4th
    \
    \ Source code definitions of DLSHIFT and DRSHIFT

    1 cells 3 lshift constant BITS_PER_CELL
    BITS_PER_CELL 2* constant BITS_PER_DOUBLE

    \ 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 ;

    0 value ubits

    \ u is the number of bits to shift

    : DLSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL >= IF
    drop \ high double has been left shifted out
    ubits BITS_PER_CELL -
    dup BITS_PER_CELL = IF
    2drop 0 0
    ELSE
    lshift 0 swap
    THEN
    ELSE
    ubits lshift swap
    dup >r
    ubits msbits or
    r> ubits lshift
    swap
    THEN ;

    : DRSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL >= IF
    nip \ low double has been right shifted out
    ubits BITS_PER_CELL -
    dup BITS_PER_CELL = IF
    2drop 0 0
    ELSE
    rshift 0
    THEN
    ELSE
    swap ubits rshift
    swap dup >r
    ubits lsbits or
    r> ubits rshift
    THEN ;

    === End of dshift.4th ===

    Test Code

    === dshift-test.4th ===
    \ dshift-test.4th
    \
    include ans-words \ <-- only for kForth
    include ttester
    include dshift

    HEX

    TESTING DLSHIFT DRSHIFT

    t{ 03 01 BITS_PER_CELL dlshift -> 00 03 }t
    t{ FF 00 BITS_PER_CELL dlshift -> 00 FF }t
    t{ 00 01 BITS_PER_CELL drshift -> 01 00 }t
    t{ 00 FF BITS_PER_CELL drshift -> FF 00 }t
    t{ -1 -1 BITS_PER_DOUBLE dlshift -> 00 00 }t
    t{ -1 -1 BITS_PER_DOUBLE drshift -> 00 00 }t

    BITS_PER_CELL 20 = [IF]
    t{ 03 01 BITS_PER_CELL 1- dlshift -> 80000000 80000001 }t
    t{ 80000000 02 1 dlshift -> 00 05 }t
    t{ 07 03 1 drshift -> 80000003 01 }t
    [THEN]

    BITS_PER_CELL 40 = [IF]
    t{ 03 01 BITS_PER_CELL 1- dlshift -> 8000000000000000 8000000000000001 }t
    t{ 8000000000000000 02 1 dlshift -> 00 05 }t
    t{ 07 03 1 drshift -> 8000000000000003 01 }t
    [THEN]

    DECIMAL

    === end of dshift-test.4th ===

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anton Ertl@21:1/5 to Krishna Myneni on Wed Mar 27 07:53:32 2024
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    1 64 LSHIFT . \ expected to get zero
    1 \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    Gforth does the same thing

    1 64 LSHIFT . 1
    1 65 LSHIFT . 2
    etc.


    We shouldn't have an ambiguous condition here because of some
    idiosyncratic behavior of the SHL instruction!

    On one hand, programmers expect the result of ( n m ) LSHIFT and ( n m
    ) RSHIFT to be 0 when m>=CELL_BITS. As you write:

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.

    OTOH, it's relatively rare to need this, so most computer architects
    have decided not to pay the relatively small hardware cost to produce
    this result, and instead only consider the lower 5 or 6 bits of the
    shift amount. The cost in language implementations is a little higher
    than at the hardware level, and various programming languages,
    including Forth have decided to leave this unspecified (there are also architectures where one bit more is used, and IIRC also hardware (IIRC
    Power) where a result of 0 is guaranteed).

    One interesting case is Java, which specifies the language pretty
    completely in order to make Java write-once-run-everywhere. Java's
    designers chose to go along with the common practice in computer
    architecture <https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.19>:

    |If the promoted type of the left-hand operand is int, then only the
    |five lowest-order bits of the right-hand operand are used as the shift |distance.

    |If the promoted type of the left-hand operand is long, then only the
    |six lowest-order bits of the right-hand operand are used as the shift |distance.

    See also
    <https://forth-standard.org/standard/core/LSHIFT#contribution-335>.

    - 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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From albert@spenarnc.xs4all.nl@21:1/5 to krishna.myneni@ccreweb.org on Wed Mar 27 09:34:25 2024
    In article <utvgki$2ciso$1@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior >thread.

    Tests needed.

    --
    Krishna Myneni


    === Start Code ===

    1 cells 3 lshift constant BITS_PER_CELL
    BITS_PER_CELL 2* constant BITS_PER_DOUBLE

    \ 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 ;

    0 value ubits

    \ u is the number of bits to shift

    : DLSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL > IF
    drop \ high double has been left shifted out
    ubits BITS_PER_CELL - lshift
    0 swap \ new low double
    ELSE
    ubits lshift swap
    dup >r
    ubits msbits or
    r> ubits lshift
    swap
    THEN ;

    : DRSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL > IF
    nip \ low double has been right shifted out
    ubits BITS_PER_CELL - rshift
    0 \ new high double
    ELSE
    swap ubits rshift
    swap dup >r
    ubits lsbits or
    r> ubits rshift
    THEN ;

    === End Code ===

    These words should be in assembler anyway.
    So a rigorous testset is more valuable than a supposedly
    standard implementation.

    Groetjes Albert
    --
    Don't praise the day before the evening. One swallow doesn't make spring.
    You must not say "hey" before you have crossed the bridge. Don't sell the
    hide of the bear until you shot it. Better one bird in the hand than ten in
    the air. First gain is a cat purring. - the Wise from Antrim -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Ruvim on Wed Mar 27 07:28:05 2024
    On 3/27/24 06:26, Ruvim wrote:
    On 2024-03-27 04:57, Krishna Myneni wrote:
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number
    left shift and right shift), over full shift range, per discussion in
    prior thread.

    Tests needed.

    Just tested DLSHIFT and found weird things going on. Traced the
    problem to LSHIFT.


    kforth64

    1 64 LSHIFT .  \ expected to get zero
    1              \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    [...]
    We shouldn't have an ambiguous condition here because of some
    idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.

    Ideally — yes.

    My rationale (see [1]) is that for any `x` and `u`, the result of a
    single shift of `x` by `u` bits should always be equivalent to `u`
    sequential shifts by 1 bit.


    I really think it is a bad idea to have UB in the spec of LSHIFT and
    RSHIFT due to the arbitrariness of low level shift operations at the
    hardware level. Here we have a chance to remove that UB and guarantee that

    1 BITS_PER_CELL LSHIFT returns zero
    and
    1 BITS_PER_CELL RSHIFT returns zero

    so that the expected result for a shift operation on the cell operand
    does not have UB.

    Efficiency because of extra instructions needed to implement this
    guarantee are not even worth bothering about -- we are not C.

    One would also expect the following two expressions to be consistent

    1 64 LSHIFT .

    and

    : TEST2* 1 64 0 DO 2* LOOP . ;
    TEST2*

    Currently, on some systems (kForth and Gforth), we get,

    1 64 LSHIFT . \ gives 1
    TEST2* \ gives 0

    For system implementers to ensure LSHIFT uses 6 bits of the shift count
    would be trivial and should not break past code provided that code did
    not use specific behavior which was called out as undefined behavior in
    the standard.

    If we get enough common practice in systems to have LSHIFT and RSHIFT
    behave in a consistent and expected manner, then it can be standardized.
    The important thing is to avoid nonsense in the language spec because of low-level hardware choices.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to albert@spenarnc.xs4all.nl on Wed Mar 27 08:24:56 2024
    On 3/27/24 03:34, albert@spenarnc.xs4all.nl wrote:
    In article <utvgki$2ciso$1@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior
    thread.

    Tests needed.

    ...

    These words should be in assembler anyway.
    So a rigorous testset is more valuable than a supposedly
    standard implementation.

    There is no standard implementation -- DLSHIFT and DRSHIFT are not
    standard words. What I meant by "standard source definitions" is that
    the Forth level definitions only use Forth standard words.

    Tests for my latest revision are provided.

    --
    KM

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Anton Ertl on Wed Mar 27 08:21:47 2024
    On 3/27/24 02:53, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    1 64 LSHIFT . \ expected to get zero
    1 \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    ...

    One interesting case is Java, which specifies the language pretty
    completely in order to make Java write-once-run-everywhere. Java's
    designers chose to go along with the common practice in computer
    architecture <https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.19>:

    |If the promoted type of the left-hand operand is int, then only the
    |five lowest-order bits of the right-hand operand are used as the shift |distance.

    |If the promoted type of the left-hand operand is long, then only the
    |six lowest-order bits of the right-hand operand are used as the shift |distance.


    For Forth, it would seem reasonable and natural to guarantee that the
    number of bits in the shift count which are honored are enough to
    represent the data stack width in bits. This would ensure that

    1 u LSHIFT

    and

    -1 u RSHIFT

    would be zero for u >= BITS_PER_CELL.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to dxf on Wed Mar 27 10:44:10 2024
    On 3/27/24 08:57, dxf wrote:
    On 27/03/2024 10:26 pm, Ruvim wrote:
    On 2024-03-27 04:57, Krishna Myneni wrote:
    [...]
    We shouldn't have an ambiguous condition here because of some idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.

    Ideally — yes.

    My rationale (see [1]) is that for any `x` and `u`, the result of a single shift of `x` by `u` bits should always be equivalent to `u` sequential shifts by 1 bit.

    But neither the standard nor implementations follow this idea.

    The same occurred with 2/ and 2 / . Those who saw Forth as a language wanted consistent results; whereas those who saw Forth as a toolkit said give us what
    the hardware provides.


    If one needs the machine shift instructions, they should be using the
    Forth assembler to write the word in which it is needed. The language specification has no justification (that I can see) for undefined
    behavior for the LSHIFT and RSHIFT instructions.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Ruvim on Wed Mar 27 10:33:17 2024
    On 3/27/24 09:56, Ruvim wrote:
    On 2024-03-27 07:14, Krishna Myneni wrote:
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number
    left shift and right shift), over full shift range, per discussion in
    prior thread.
    ...
    ...

    I wrote a simpler implementation a long time ago. The file
    "double-shift.fth" below is a translation from [2] using different names
    for constants.


    === "double-shift.fth"

    :NONAME 0 -1 BEGIN DUP WHILE SWAP 1+ SWAP 1 RSHIFT REPEAT DROP ; EXECUTE CONSTANT BITS-PER-CELL

    BITS-PER-CELL 1-      CONSTANT MAX-FOR-SHIFT1
    BITS-PER-CELL 2* 1-   CONSTANT MAX-FOR-SHIFT2

    : (DLSHIFT) ( xd1 u -- xd2 )
      ( x.lo x.hi  u )
      TUCK LSHIFT >R
      2DUP NEGATE BITS-PER-CELL + RSHIFT >R
      LSHIFT 2R> OR
    ;
    : DLSHIFT ( xd1 u -- xd2 )
      DUP 0= IF  DROP EXIT THEN
      DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
      DUP MAX-FOR-SHIFT1 U> IF  NIP BITS-PER-CELL - LSHIFT 0 SWAP EXIT THEN
      (DLSHIFT)
    ;
    : (DRSHIFT) ( xd1 u -- xd2 )
      ( x.lo x.hi  u )
      2DUP RSHIFT >R
      TUCK NEGATE BITS-PER-CELL + LSHIFT >R
      RSHIFT R> OR R>
    ;
    : DRSHIFT ( xd1 u -- xd2 )
      DUP 0= IF  DROP EXIT THEN
      DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
      DUP MAX-FOR-SHIFT1 U> IF  >R NIP R> BITS-PER-CELL - RSHIFT 0 EXIT THEN
      (DRSHIFT)
    ;

    === End of "double-shift.fth"


    Does it succeed on all of the tests I gave?

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bernd Linsel@21:1/5 to All on Wed Mar 27 19:48:56 2024
    T24gMjcuMDMuMjAyNCAxMzoyOCwgS3Jpc2huYSBNeW5lbmkgd3JvdGU6DQo+IA0KPiBJIHJl YWxseSB0aGluayBpdCBpcyBhIGJhZCBpZGVhIHRvIGhhdmUgVUIgaW4gdGhlIHNwZWMgb2Yg TFNISUZUIGFuZCANCj4gUlNISUZUIGR1ZSB0byB0aGUgYXJiaXRyYXJpbmVzcyBvZiBsb3cg bGV2ZWwgc2hpZnQgb3BlcmF0aW9ucyBhdCB0aGUgDQogPiBoYXJkd2FyZSBsZXZlbC4NCg0K SXQncyBub3QgVUIsIGl0IGlzIElCIGFuZCB0aHVzIGl0IHNob3VsZCBiZSByZXF1aXJlZCB0 aGF0IGFuIGltcGxlbWVudGVyIA0KZG9jdW1lbnRzIHRoZSByZXNwZWN0aXZlIGJlaGF2aW91 ciBvZiB0aGVpciBzeXN0ZW0uDQoNCiA+IEhlcmUgd2UgaGF2ZSBhIGNoYW5jZSB0byByZW1v dmUgdGhhdCBVQiBhbmQgZ3VhcmFudGVlIHRoYXQ+DQo+IDEgQklUU19QRVJfQ0VMTCBMU0hJ RlTCoCByZXR1cm5zIHplcm8NCj4gYW5kDQo+IDEgQklUU19QRVJfQ0VMTCBSU0hJRlTCoCBy ZXR1cm5zIHplcm8NCj4gDQo+IHNvIHRoYXQgdGhlIGV4cGVjdGVkIHJlc3VsdCBmb3IgYSBz aGlmdCBvcGVyYXRpb24gb24gdGhlIGNlbGwgb3BlcmFuZCANCj4gZG9lcyBub3QgaGF2ZSBV Qi4NCj4gDQo+IEVmZmljaWVuY3kgYmVjYXVzZSBvZiBleHRyYSBpbnN0cnVjdGlvbnMgbmVl ZGVkIHRvIGltcGxlbWVudCB0aGlzIA0KPiBndWFyYW50ZWUgYXJlIG5vdCBldmVuIHdvcnRo IGJvdGhlcmluZyBhYm91dCAtLSB3ZSBhcmUgbm90IEMuDQoNCkZvcnRoIGRvZXMgY2FyZSBh Ym91dCBlZmZpY2llbmN5LiBPdGhlcndpc2UgeW91IGNvdWxkIGVsaW1pbmF0ZSBvdmVyIHRo ZSANCmhhbGYgb2YgdGhlIGFtYmlndW91cyBjb25kaXRpb25zIGluIHRoZSBGb3J0aCBzdGFu ZGFyZCB0aGF0IG9ubHkgYXJpc2UgDQpmcm9tIHRoZSBmYWN0IHRoYXQgaGFyZHdhcmUgcGxh dGZvcm1zIGRpZmZlciBpbiB0aGVpciBiZWhhdmlvdXIuDQoNCltzbmlwXQ0KDQpGb3IgdGhl IHJhcmUgc2l0dWF0aW9uIHRoYXQgYSB2YXJpYWJsZSBzaGlmdCBjb3VudCBpcyBuZWVkZWQs IGFuZCBpcyBub3QgDQpwZXIgc2UgcmVzdHJpY3RlZCB0byAwLi5BRERSRVNTLVVOSVQtQklU UyAtIDEsIHlvdSBjYW4gYWx3YXlzIHdyaXRlIGVpdGhlcg0KDQowIE1BWCAgIFMiIEFERFJF U1MtVU5JVC1CSVRTIiAxLSBNSU4gICBMU0hJRlQgKCBvciBSU0hJRlQpDQoNCm9yDQoNCkRV UCAwPCBJTlZFUlQgSUYgICBEVVAgUyIgQUREUkVTUy1VTklULUJJVFMiIDwgSUYgIExTSElG VCAoIG9yIFJTSElGVCkNCkVMU0UgKCB3aGF0ZXZlciB0byBkbyBpZiBzaGlmdC1hbW91bnQg PCAwKQ0KRUxTRSAoIHdoYXRldmVyIHRvIGRvIGlmIHNoaWZ0LWFtb3VudCA+PSBjZWxsIHdp ZHRoKQ0KVEhFTiBUSEVODQoNCm9yIHNpbXBseQ0KDQpEVVAgMDwgQUJPUlQiIHNoaWZ0IGFt b3VudCBsZXNzIHRoYW4gMCINCkRVUCBTIiBBRERSRVNTLVVOSVQtQklUUyIgMS0gPiBBQk9S VCIgc2hpZnQgYW1vdW50IGdyZWF0ZXIvZXF1YWwgY2VsbCB3aWR0aCkNCkxTSElGVCAoIG9y IFJTSElGVCkNCg0KDQoNCk5COiBUaGUgYmVoYXZpb3VyIG9mIG1vc3QgcHJvY2Vzc29ycyB0 byBvbmx5IHJlZ2FyZCB0aGUgNSBvciA2IExTQnMgaXMgDQp1c2VmdWwgZm9yIGV4cHJlc3Np b25zIGxpa2UgLTEgNjQgPG4+IC0gTFNISUZUIHRvIHByb2R1Y2UgYml0IG1hc2tzLCANCnRo ZXNlIGNhbiBzaW1wbHkgYmUgZXhwcmVzc2VkIGFzIDxuPiBORUdBVEUgTFNISUZUICh3aXRo IGFuIA0KZW52aXJvbm1lbnRhbCBkZXBlbmRlbmN5IG9uIHByb2Nlc3NvcnMgdGhhdCBiZWhh dmUgdGhpcyB3YXkpLg0KDQoNCi0tIA0KQmVybmQgTGluc2VsDQo=

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anton Ertl@21:1/5 to Krishna Myneni on Wed Mar 27 18:46:10 2024
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    I really think it is a bad idea to have UB in the spec of LSHIFT and
    RSHIFT due to the arbitrariness of low level shift operations at the
    hardware level. Here we have a chance to remove that UB and guarantee that

    1 BITS_PER_CELL LSHIFT returns zero
    and
    1 BITS_PER_CELL RSHIFT returns zero

    so that the expected result for a shift operation on the cell operand
    does not have UB.

    I guess you mean the ambiguous condition in the specification of
    LSHIFT and RSHIFT, which is more like implementation-defined behaviour
    in some other languages (and the advocates of undefined behaviour make
    a lot of wind about the difference between implementation-defined and undefined).

    Well, if you want to see this happen, you have to convince some Forth
    system implementors, so common practice moves in the direction you
    prefer, and once that is done, make a proposal.

    You could point out that the extra cost of the check is only incurred
    for shifts with non-constant shift amounts, and if you could provide
    data on the frequency of constant and non-constant shift amounts, this
    might help convince system implementors. Of course, for commercial implementors, you may get the usual answer that their customers have
    not complained to them, but if you don't try, you can't win.

    Efficiency because of extra instructions needed to implement this
    guarantee are not even worth bothering about -- we are not C.

    I am sure someone can produce some saying by Chuck Moore that
    contradicts this attitude. Sure, Forth is not C, but it's just as performance-conscious.

    - 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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bernd Linsel@21:1/5 to albert@spenarnc.xs4all.nl on Wed Mar 27 19:50:46 2024
    On 27.03.2024 09:34, albert@spenarnc.xs4all.nl wrote:
    These words should be in assembler anyway.

    +1

    --
    Bernd Linsel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Anton Ertl on Wed Mar 27 14:54:36 2024
    On 3/27/24 13:46, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    I really think it is a bad idea to have UB in the spec of LSHIFT and
    RSHIFT due to the arbitrariness of low level shift operations at the
    hardware level. Here we have a chance to remove that UB and guarantee that >>
    1 BITS_PER_CELL LSHIFT returns zero
    and
    1 BITS_PER_CELL RSHIFT returns zero

    so that the expected result for a shift operation on the cell operand
    does not have UB.

    I guess you mean the ambiguous condition in the specification of
    LSHIFT and RSHIFT, which is more like implementation-defined behaviour
    in some other languages (and the advocates of undefined behaviour make
    a lot of wind about the difference between implementation-defined and undefined).

    I have to admit that the distinction between mapping "ambiguous
    condition" to IB vs UB escapes me.


    Well, if you want to see this happen, you have to convince some Forth
    system implementors, so common practice moves in the direction you
    prefer, and once that is done, make a proposal.


    Sure. I would start with modifying LSHIFT and RSHIFT in my own Forth
    systems. The revisions would still be consistent with the standard.

    You could point out that the extra cost of the check is only incurred
    for shifts with non-constant shift amounts, and if you could provide
    data on the frequency of constant and non-constant shift amounts, this
    might help convince system implementors. Of course, for commercial implementors, you may get the usual answer that their customers have
    not complained to them, but if you don't try, you can't win.

    Efficiency because of extra instructions needed to implement this
    guarantee are not even worth bothering about -- we are not C.

    I am sure someone can produce some saying by Chuck Moore that
    contradicts this attitude. Sure, Forth is not C, but it's just as performance-conscious.


    My meaning was that I expect the performance change to be negligible. Of course, we have to implement and test to check this.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Ruvim on Wed Mar 27 14:49:02 2024
    On 3/27/24 11:36, Ruvim wrote:

    === "double-shift.fth"

    :NONAME 0 -1 BEGIN DUP WHILE SWAP 1+ SWAP 1 RSHIFT REPEAT DROP ; EXECUTE >>> CONSTANT BITS-PER-CELL

    BITS-PER-CELL 1-      CONSTANT MAX-FOR-SHIFT1
    BITS-PER-CELL 2* 1-   CONSTANT MAX-FOR-SHIFT2

    : (DLSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       TUCK LSHIFT >R
       2DUP NEGATE BITS-PER-CELL + RSHIFT >R
       LSHIFT 2R> OR
    ;
    : DLSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  NIP BITS-PER-CELL - LSHIFT 0 SWAP EXIT THEN >>>    (DLSHIFT)
    ;
    : (DRSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       2DUP RSHIFT >R
       TUCK NEGATE BITS-PER-CELL + LSHIFT >R
       RSHIFT R> OR R>
    ;
    : DRSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  >R NIP R> BITS-PER-CELL - RSHIFT 0 EXIT
    THEN
       (DRSHIFT)
    ;

    === End of "double-shift.fth"


    Does it succeed on all of the tests I gave?

    Of course, I checked — it succeed your tests.



    Thanks.

    -- KM

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From minforth@21:1/5 to All on Thu Mar 28 08:06:15 2024
    May I ask for what you need these double cell shifts?

    I know of some crypto routines, but these require even much wider cell sizes.

    Another example: in my field pseudo random number generators are common technique.
    However PRNGs are closely related to prime numbers and they often require rotations of sub-cell chunks (linear feedback shift registers).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anton Ertl@21:1/5 to Krishna Myneni on Thu Mar 28 08:49:43 2024
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    On 3/27/24 13:46, Anton Ertl wrote:
    You could point out that the extra cost of the check is only incurred
    for shifts with non-constant shift amounts, and if you could provide
    data on the frequency of constant and non-constant shift amounts, this
    might help convince system implementors.

    Here's some data about the occurences in the Gforth image:

    Non-constant shift amount:
    2 lshift
    1 rshift
    0 arshift

    Constant shift amount:
    18 lit lshift
    41 lit rshift
    0 lit arshift

    Produced by inserting superinstructions for the constant shifts,
    rebuilding Gforth, and then

    gforth-fast --ss-states=0 --print-prims -e bye

    - 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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to minforth on Thu Mar 28 08:10:46 2024
    On 3/28/24 03:06, minforth wrote:
    May I ask for what you need these double cell shifts?


    I'm interested in writing a portable IEEE 754 quad precision arithmetic
    library in Forth. The significands are 113 bits long, with implied bit included. To perform addition or subtraction between two quad precision numbers, the two significands have to be aligned using the difference in
    their base 2 exponents (15 bit exponents). This requires a relative
    shift of the two significands across a 128-bit representation of the two numbers being added/subtracted. On a 64-bit system, we can use double
    cell shifts to accomplish this.


    I know of some crypto routines, but these require even much wider cell
    sizes.

    Another example: in my field pseudo random number generators are common technique.
    However PRNGs are closely related to prime numbers and they often require rotations of sub-cell chunks (linear feedback shift registers).

    I'm sure there are a lot of other uses that I don't know about. Shifts registers came up during our previous discussion on SHA512 implementations.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to dxf on Thu Mar 28 08:38:07 2024
    On 3/28/24 06:29, dxf wrote:
    On 28/03/2024 2:44 am, Krishna Myneni wrote:
    On 3/27/24 08:57, dxf wrote:
    On 27/03/2024 10:26 pm, Ruvim wrote:
    On 2024-03-27 04:57, Krishna Myneni wrote:
    [...]
    We shouldn't have an ambiguous condition here because of some idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits. >>>>
    Ideally — yes.

    My rationale (see [1]) is that for any `x` and `u`, the result of a single shift of `x` by `u` bits should always be equivalent to `u` sequential shifts by 1 bit.

    But neither the standard nor implementations follow this idea.

    The same occurred with 2/ and 2 / .  Those who saw Forth as a language wanted
    consistent results; whereas those who saw Forth as a toolkit said give us what
    the hardware provides.


    If one needs the machine shift instructions, they should be using the Forth assembler to write the word in which it is needed. The language specification has no justification (that I can see) for undefined behavior for the LSHIFT and RSHIFT
    instructions.

    Some 40 years ago Intel told their customers there's no justification for shifting
    a full cell of bits. ANS told the same thing to forthers.



    This really isn't an issue with the processor design -- they're under
    more severe constraints in what they can put in the hardware. The
    desired behavior can be achieved in software.

    When I first started programming in Forth, I appreciated the fact that
    it was close to the hardware. As processor speed and memory size and the complexity of my programs grew, and the need to share them as well, the cleanliness and portability of the language became more important.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From minforth@21:1/5 to Krishna Myneni on Thu Mar 28 14:25:45 2024
    Krishna Myneni wrote:

    On 3/28/24 03:06, minforth wrote:
    May I ask for what you need these double cell shifts?


    I'm interested in writing a portable IEEE 754 quad precision arithmetic library in Forth.

    Respect! Scaling is a basic fp operation indeed.

    You can test against libquadmath. For inspiration, browsing its source code might be of interest: https://codebrowser.dev/glibc/glibc/sysdeps/ieee754/float128/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Anton Ertl on Fri Mar 29 08:12:36 2024
    On 3/28/24 03:49, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    On 3/27/24 13:46, Anton Ertl wrote:
    You could point out that the extra cost of the check is only incurred
    for shifts with non-constant shift amounts, and if you could provide
    data on the frequency of constant and non-constant shift amounts, this
    might help convince system implementors.

    Here's some data about the occurences in the Gforth image:

    Non-constant shift amount:
    2 lshift
    1 rshift
    0 arshift

    Constant shift amount:
    18 lit lshift
    41 lit rshift
    0 lit arshift

    ...

    Checking the Forth code base which I use, I find ~ 100:1 ratio between
    uses of constant shift amount to non-constant shifts. The existing
    instances of non-constant shifts are comparable to yours: two in number
    theory programs e.g., finding an exact fraction for a floating point
    number, and one use in the assembler.

    I don't know what to conclude from this other than the kind of
    application development I have been doing favors one over the other. The
    large number of constant shifts have to do with defining constants,
    largely for data acquisition interfaces.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Hans Bezemer on Fri Mar 29 09:34:55 2024
    On 3/29/24 09:32, Hans Bezemer wrote:
    On 27-03-2024 20:49, Krishna Myneni wrote:
    On 3/27/24 11:36, Ruvim wrote:

    === "double-shift.fth"

    :NONAME 0 -1 BEGIN DUP WHILE SWAP 1+ SWAP 1 RSHIFT REPEAT DROP ;
    EXECUTE
    CONSTANT BITS-PER-CELL

    BITS-PER-CELL 1-      CONSTANT MAX-FOR-SHIFT1
    BITS-PER-CELL 2* 1-   CONSTANT MAX-FOR-SHIFT2

    : (DLSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       TUCK LSHIFT >R
       2DUP NEGATE BITS-PER-CELL + RSHIFT >R
       LSHIFT 2R> OR
    ;
    : DLSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  NIP BITS-PER-CELL - LSHIFT 0 SWAP EXIT >>>>> THEN
       (DLSHIFT)
    ;
    : (DRSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       2DUP RSHIFT >R
       TUCK NEGATE BITS-PER-CELL + LSHIFT >R
       RSHIFT R> OR R>
    ;
    : DRSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  >R NIP R> BITS-PER-CELL - RSHIFT 0
    EXIT THEN
       (DRSHIFT)
    ;

    === End of "double-shift.fth"

    Can't make it any shorter than this. And no idea what happens with less robust LSHIFT or RSHIFT implementations. CELL-BITS should be most
    obvious, : SPIN SWAP ROT ; should fix most porting issues, replace ;THEN
    with EXIT THEN. It passes all tests.

    : dlshift
      dup 0> 0= if drop ;then
      >r over 0 invert cell-bits r@ - dup >r lshift and r> rshift swap
      r@ lshift or swap r> lshift swap
    ;

    : drshift
      dup 0> 0= if drop ;then
      >r dup 0 invert cell-bits r@ - dup >r rshift and r> lshift swap
      r@ rshift spin r> rshift or swap
    ;


    Thanks! I have updated LSHIFT and RSHIFT in kForth-32 and kForth-64 to
    handle shift count >= BITS_PER_CELL to give the expected answer (0).

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Krishna Myneni on Fri Mar 29 09:41:08 2024
    On 3/26/24 19:57, Krishna Myneni wrote:
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior
    thread.

    Tests needed.

    Just tested DLSHIFT and found weird things going on. Traced the problem
    to LSHIFT.


    kforth64

    1 64 LSHIFT .  \ expected to get zero
    1              \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    Gforth does the same thing

    1 64 LSHIFT .  1
    1 65 LSHIFT .  2
    etc.


    We shouldn't have an ambiguous condition here because of some
    idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.


    I have revised LSHIFT and RSHIFT in kForth-32 and kForth-64 to give
    expected results for shift count >= BITS_PER_CELL (still have to update kForth-Win32). Some test code to check that these words behave as expected:

    1 CELLS 8 * constant BITS_PER_CELL

    : test-lshift ( -- )
    BITS_PER_CELL 6 + 0 DO
    I 2 .R 2 SPACES
    1 I LSHIFT
    BINARY BITS_PER_CELL U.R CR DECIMAL
    LOOP ;

    : test-rshift ( -- )
    1 BITS_PER_CELL 1- LSHIFT
    BITS_PER_CELL 6 + 0 DO
    I 2 .R 2 SPACES
    DUP I RSHIFT
    BINARY BITS_PER_CELL U.R CR DECIMAL
    LOOP DROP ;

    TEST-LSHIFT ( on 32-bit system )
    0 1
    1 10
    2 100
    3 1000
    4 10000
    5 100000
    6 1000000
    7 10000000
    8 100000000
    9 1000000000
    10 10000000000
    11 100000000000
    12 1000000000000
    13 10000000000000
    14 100000000000000
    15 1000000000000000
    16 10000000000000000
    17 100000000000000000
    18 1000000000000000000
    19 10000000000000000000
    20 100000000000000000000
    21 1000000000000000000000
    22 10000000000000000000000
    23 100000000000000000000000
    24 1000000000000000000000000
    25 10000000000000000000000000
    26 100000000000000000000000000
    27 1000000000000000000000000000
    28 10000000000000000000000000000
    29 100000000000000000000000000000
    30 1000000000000000000000000000000
    31 10000000000000000000000000000000
    32 0
    33 0
    34 0
    35 0
    36 0
    37 0
    ok
    TEST-RSHIFT ( on 32-bit system )
    0 10000000000000000000000000000000
    1 1000000000000000000000000000000
    2 100000000000000000000000000000
    3 10000000000000000000000000000
    4 1000000000000000000000000000
    5 100000000000000000000000000
    6 10000000000000000000000000
    7 1000000000000000000000000
    8 100000000000000000000000
    9 10000000000000000000000
    10 1000000000000000000000
    11 100000000000000000000
    12 10000000000000000000
    13 1000000000000000000
    14 100000000000000000
    15 10000000000000000
    16 1000000000000000
    17 100000000000000
    18 10000000000000
    19 1000000000000
    20 100000000000
    21 10000000000
    22 1000000000
    23 100000000
    24 10000000
    25 1000000
    26 100000
    27 10000
    28 1000
    29 100
    30 10
    31 1
    32 0
    33 0
    34 0
    35 0
    36 0
    37 0
    ok

    Similar displays for 64-bit systems.

    --
    KM

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anton Ertl@21:1/5 to Krishna Myneni on Fri Mar 29 16:55:32 2024
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    On 3/28/24 03:49, Anton Ertl wrote:
    Here's some data about the occurences in the Gforth image:

    Non-constant shift amount:
    2 lshift
    1 rshift
    0 arshift

    Constant shift amount:
    18 lit lshift
    41 lit rshift
    0 lit arshift

    ...

    Checking the Forth code base which I use, I find ~ 100:1 ratio between
    uses of constant shift amount to non-constant shifts. The existing
    instances of non-constant shifts are comparable to yours: two in number >theory programs e.g., finding an exact fraction for a floating point
    number, and one use in the assembler.

    I don't know what to conclude from this other than the kind of
    application development I have been doing favors one over the other.

    It shows that Forth systems that support special code generation for
    operations with constants (probably all native-code systems, as well
    as Gforth) would be able to generate the same code in the vast
    majority of cases even with the change you propose. Only in the few non-constant cases a few extra instructions would be needed.

    - 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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Anton Ertl on Sat Mar 30 07:58:34 2024
    On 3/29/24 11:55, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    On 3/28/24 03:49, Anton Ertl wrote:
    Here's some data about the occurences in the Gforth image:

    Non-constant shift amount:
    2 lshift
    1 rshift
    0 arshift

    Constant shift amount:
    18 lit lshift
    41 lit rshift
    0 lit arshift

    ...

    Checking the Forth code base which I use, I find ~ 100:1 ratio between
    uses of constant shift amount to non-constant shifts. The existing
    instances of non-constant shifts are comparable to yours: two in number
    theory programs e.g., finding an exact fraction for a floating point
    number, and one use in the assembler.

    I don't know what to conclude from this other than the kind of
    application development I have been doing favors one over the other.

    It shows that Forth systems that support special code generation for operations with constants (probably all native-code systems, as well
    as Gforth) would be able to generate the same code in the vast
    majority of cases even with the change you propose. Only in the few non-constant cases a few extra instructions would be needed.


    Ah, so optimizing Forth compilers can do a compile-time check for
    literal shifts and not have to insert instructions for compare and
    branch e.g., my new implementation of LSHIFT in kforth64

    (from vm64-common.s)

    .equ MAX_SHIFT_COUNT, WSIZE*8-1

    L_lshift:
    LDSP
    DROP
    mov (%rbx), %rcx
    cmp $MAX_SHIFT_COUNT, %rcx
    jbe lshift1
    movq $0, WSIZE(%rbx)
    NEXT
    lshift1:
    shlq %cl, WSIZE(%rbx)
    NEXT


    The older version was:

    L_lshift:
    LDSP
    DROP
    mov (%rbx), %rcx
    shlq %cl, WSIZE(%rbx)
    NEXT

    Similarly for RSHIFT.

    --
    KM

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anton Ertl@21:1/5 to Krishna Myneni on Sat Mar 30 17:29:04 2024
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    Ah, so optimizing Forth compilers can do a compile-time check for
    literal shifts and not have to insert instructions for compare and
    branch

    Yes.

    - 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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From minforth@21:1/5 to dxf on Mon Apr 1 08:03:56 2024
    dxf wrote:

    While your double-shift algorithm produces the correct results (not shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me. That an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a result of 0,
    I for one find problematic. IMO it were better that RSHIFT/LSHIFT should fail than
    do this.

    Doesn't make sense during fp number addition/subtraction.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From albert@spenarnc.xs4all.nl@21:1/5 to bl1-thispartdoesnotbelonghere@gmx.c on Mon Apr 1 11:35:05 2024
    In article <uu1pmo$305br$1@dont-email.me>,
    Bernd Linsel <bl1-thispartdoesnotbelonghere@gmx.com> wrote:
    On 27.03.2024 13:28, Krishna Myneni wrote:

    I really think it is a bad idea to have UB in the spec of LSHIFT and
    RSHIFT due to the arbitrariness of low level shift operations at the
    hardware level.

    It's not UB, it is IB and thus it should be required that an implementer >documents the respective behaviour of their system.

    Here we have a chance to remove that UB and guarantee that>
    1 BITS_PER_CELL LSHIFT  returns zero
    and
    1 BITS_PER_CELL RSHIFT  returns zero

    so that the expected result for a shift operation on the cell operand
    does not have UB.

    Efficiency because of extra instructions needed to implement this
    guarantee are not even worth bothering about -- we are not C.

    Forth does care about efficiency. Otherwise you could eliminate over the
    half of the ambiguous conditions in the Forth standard that only arise
    from the fact that hardware platforms differ in their behaviour.

    [snip]

    For the rare situation that a variable shift count is needed, and is not
    per se restricted to 0..ADDRESS-UNIT-BITS - 1, you can always write either

    0 MAX S" ADDRESS-UNIT-BITS" 1- MIN LSHIFT ( or RSHIFT)

    or

    DUP 0< INVERT IF DUP S" ADDRESS-UNIT-BITS" < IF LSHIFT ( or RSHIFT)
    ELSE ( whatever to do if shift-amount < 0)
    ELSE ( whatever to do if shift-amount >= cell width)
    THEN THEN

    or simply

    DUP 0< ABORT" shift amount less than 0"
    DUP S" ADDRESS-UNIT-BITS" 1- > ABORT" shift amount greater/equal cell width) >LSHIFT ( or RSHIFT)

    I hate ABORT in this context. Are you sure that you want to shut down
    the nuclear power plant in this situation?


    NB: The behaviour of most processors to only regard the 5 or 6 LSBs is
    useful for expressions like -1 64 <n> - LSHIFT to produce bit masks,
    these can simply be expressed as <n> NEGATE LSHIFT (with an
    environmental dependency on processors that behave this way).


    --
    Bernd Linsel
    --
    Don't praise the day before the evening. One swallow doesn't make spring.
    You must not say "hey" before you have crossed the bridge. Don't sell the
    hide of the bear until you shot it. Better one bird in the hand than ten in
    the air. First gain is a cat purring. - the Wise from Antrim -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anton Ertl@21:1/5 to albert@spenarnc.xs4all.nl on Mon Apr 1 09:56:59 2024
    albert@spenarnc.xs4all.nl writes:
    In article <uu1pmo$305br$1@dont-email.me>,
    Bernd Linsel <bl1-thispartdoesnotbelonghere@gmx.com> wrote:
    NB: The behaviour of most processors to only regard the 5 or 6 LSBs is >>useful for expressions like -1 64 <n> - LSHIFT to produce bit masks,
    these can simply be expressed as <n> NEGATE LSHIFT (with an
    environmental dependency on processors that behave this way).

    Let's see:

    -1 64 2 - lshift hex. $C000000000000000 ok
    -1 64 1 - lshift hex. $8000000000000000 ok
    -1 64 0 - lshift hex. $FFFFFFFFFFFFFFFF ok

    I have my doubts that somebody performing such a computation intends
    to produce the last result. A result of 0 is more likely to be
    intended. Of course, there is some chance that providing a zero <n>
    for that computation is not intended, which may be a justification for everybody involved to produce arbitrary results in that case.

    Anyway, given 64-bt cells, the standard LSHIFT and twos-complement
    arithmetic (which is assumed by the "-1" above already), one can
    express the intention as follows:

    : gen-mask1 ( n -- x )
    \ produce -1 if <n>=0
    negate 63 and -1 swap lshift ;

    : gen-mask2 ( n -- x )
    \ produce 0 if <n>=0
    64 swap - dup 64 u< if
    -1 swap lshift
    else
    drop 0
    then ;

    : gen-mask3 ( n -- x )
    \ throw if <n>=0
    64 swap - dup 64 u< 0= -24 and throw -1 swap lshift ;

    And similarly for machine code. So, if GEN-MASK1 is intended, even an
    LSHIFT that produces 0 for larger shift counts is only one instruction
    away. So it is unlikely that the computer architects decided to look
    at only the LSB bits for that purpose.

    BTW, I ignore base64-encoded postings.

    - 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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Hans Bezemer on Mon Apr 1 19:56:52 2024
    On 4/1/24 10:18, Hans Bezemer wrote:
    ...
    The only viable alternative is:

    : DLSHIFT  ( xd1 n -- xd2)     0 ?do d2* loop ;
    : DRSHIFT  ( xd1 n -- xd2)     0 ?do d2/ loop ;


    DRSHIFT cannot be coded with D2/ which is an arithmetic right shift,
    i.e. it preserves the sign bit. DRSHIFT has to pad from the left with
    zero bits.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to dxf on Mon Apr 1 20:35:12 2024
    On 4/1/24 04:21, dxf wrote:
    On 1/04/2024 7:03 pm, minforth wrote:
    dxf wrote:

    While your double-shift algorithm produces the correct results (not shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me.  That an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a result of 0,
    I for one find problematic.  IMO it were better that RSHIFT/LSHIFT should fail than
    do this.

    Doesn't make sense during fp number addition/subtraction.

    Example?


    First, there is no negative shift count argument for LSHIFT RSHIFT
    DLSHIFT or DRSHIFT . The arguments are unsigned.

    For an ieee 754 double precision number, there is an effective distance
    of 53 bits between the most significant bit and the least significant
    bit. On a 32-bit system, consider adding 1.0e0 to the number 1.0e10.

    The ieee-754 unbiased base 2 exponents for the two floating point
    arguments are 0 (for 1.0e0) and 33 (for 1.0e10). This means that adding
    the two 53-bit significands using two double numbers (two 64-bit numbers
    on a 32 bit system) requires a relative right shift of 33 bits for the
    argument 1.0e0.

    Here are the bit patterns for the two significands, along with their
    base 2 exponents:

    21098765432109876543210987654321098765432109876543210 10010101000000101111100100000000000000000000000000000 33 10000000000000000000000000000000000000000000000000000 00

    There are 53 bits in each significand, and the 53rd bit is always an
    implied 1. To add these, we can use 33 DRSHIFT on the one argument to
    align the significands and add the two double length numbers to obtain
    the new significand.

    For ieee 754 quad precision, there are 113 bits in the significand, so
    relative shifts can be as large as 112 bits for addition and subtraction.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to Hans Bezemer on Tue Apr 2 06:33:46 2024
    On 4/2/24 03:56, Hans Bezemer wrote:
    On 02-04-2024 02:56, Krishna Myneni wrote:
    On 4/1/24 10:18, Hans Bezemer wrote:
    ...
    The only viable alternative is:

    : DLSHIFT  ( xd1 n -- xd2)     0 ?do d2* loop ;
    : DRSHIFT  ( xd1 n -- xd2)     0 ?do d2/ loop ;


    DRSHIFT cannot be coded with D2/ which is an arithmetic right shift,
    i.e. it preserves the sign bit. DRSHIFT has to pad from the left with
    zero bits.

    True, but if you know my coding style - this is not it. And it is acknowledged as such in the source:

    \ DXForth MISC.SCR, Copyright Ed, 2011-03-25
    \ Albert van der Horst, Thursday 09 April 2015 19:57:13, c.l.f

    So it's not uncommon to define it like this. Apart from that - "D2/" is
    not a standardized word - so it can mean anything. Although I do agree
    with you that your definition is the most likely one.

    Hans Bezemer

    D2/ is a standardized word, since ANS Forth:

    8.6.1.1100
    D2/
    “d-two-slash”
    DOUBLE
    ( xd1 – – xd2 )
    xd2 is the result of shifting xd1 one bit toward the least-significant
    bit, leaving the most-significant bit unchanged.

    --
    KM

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anton Ertl@21:1/5 to dxf on Thu Apr 4 16:27:25 2024
    dxf <dxforth@gmail.com> writes:
    That led to this Jan 1992 message:

    https://groups.google.com/g/comp.lang.forth/c/DqrKMIiyLWc/m/1XUyYBaHyfYJ

    I found the last posting in this thread most fitting:

    |Andrew Scott
    |Jan 13, 1992, 9:32:24 PM
    |
    |John Hayes writes:
    The bidirectional shift operator is probably a result of the parsimony
    of Forth philosophy; why have two operators when one will do.
    |
    |I thought part of the Forth philosophy was exactly the *opposite*. We |wouldn't have words like 1+ or 0< if efficiency wasn't regarded as more |important than a small set of consistent words.

    - 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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From albert@spenarnc.xs4all.nl@21:1/5 to dxforth@gmail.com on Fri Apr 12 10:27:49 2024
    In article <66188ab1$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote:
    On 12/04/2024 1:11 am, albert@spenarnc.xs4all.nl wrote:

    While others indulge in endless discussions about DRSHIFT
    I thought to attempt some literate programming.

    It didn't prompt you to test your own implementation?

    ( D0= D0<> D0< D= D< D- M+ DRSHIFT DLSHIFT DU< ) \ AvdH B6Mar22

    : DLSHIFT >R SWAP DUP R@ LSHIFT SWAP 8 CELLS R@ - RSHIFT ROT R>
    LSHIFT OR ;

    : DRSHIFT >R DUP R@ RSHIFT SWAP 8 CELLS R@ - LSHIFT ROT R>
    RSHIFT OR SWAP ;

    0 4 d. 17179869184 ok
    0 4 0 drshift d. 17179869188 ok

    4 0 d. 4 ok
    4 0 0 dlshift d. 17179869188 ok


    Good catch! Shifting over 8 CELLS is an ambiguous condition.
    insert
    DUP 0= IF EXIT THEN
    in front of the code.
    --
    Don't praise the day before the evening. One swallow doesn't make spring.
    You must not say "hey" before you have crossed the bridge. Don't sell the
    hide of the bear until you shot it. Better one bird in the hand than ten in
    the air. First gain is a cat purring. - the Wise from Antrim -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From mhx@21:1/5 to Krishna Myneni on Sat Apr 13 13:54:54 2024
    Krishna Myneni wrote:
    [..]
    Just tested DLSHIFT and found weird things going on. Traced the problem
    to LSHIFT.
    [..]
    1 64 LSHIFT . \ expected to get zero
    1 \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    Interesting. Apparently this was changed somewhere in
    the course of time, as my local version of the spec. says:

    LSHIFT CORE
    ( u1 u -- u2 )
    Perform a logical shift of u bit-places on u1, giving u2. Shift the bits
    n places toward the most significant bit. Put zero into the places
    "uncovered" by the shift. When u is greater than or equal to the number
    of bits in a cell, u2 wraps around.

    Fortunately, this is exactly what AMD/Intel hardware does, and leads to

    FORTH> 1 64 lshift . 1 ok

    -marcel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Krishna Myneni@21:1/5 to mhx on Sat Apr 13 18:29:42 2024
    On 4/13/24 08:54, mhx wrote:
    Krishna Myneni wrote:
    [..]
    Just tested DLSHIFT and found weird things going on. Traced the
    problem to LSHIFT.
    [..]
    1 64 LSHIFT .  \ expected to get zero
    1              \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    Interesting. Apparently this was changed somewhere in
    the course of time, as my local version of the spec. says:

    LSHIFT                                                                 CORE
        ( u1 u -- u2 )
        Perform a logical shift of u bit-places on u1, giving u2. Shift the bits
        n places toward the most significant bit. Put zero into the places
        "uncovered" by the shift. When u is greater than or equal to the number
        of bits in a cell, u2 wraps around.

    Fortunately, this is exactly what AMD/Intel hardware does, and leads to

    FORTH> 1 64 lshift . 1  ok

    -marcel

    The spec for LSHIFT which I posted is the same as the one in Forth-94
    (ANS Forth), so yours must have come from an earlier standard, or it
    just mirrors the SHL instruction spec for x86/x86_64. IMO the language
    spec shouldn't be tied to the behavior of a processor machine level
    instruction on a specific processor family.

    Also, I don't see what good a wrap-around shift is when u is greater
    than or equal to the bits in a cell. In what algorithm would you use
    such an operation? Bit operations such as a linear shift register where
    the bits drop off in the direction of the shift, or a bit rotation
    within a cell with an arbitrary number seem to be more useful.

    --
    Krishna

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From albert@spenarnc.xs4all.nl@21:1/5 to dxforth@gmail.com on Sun Apr 14 13:06:12 2024
    In article <661a5369$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote:
    On 12/04/2024 6:27 pm, albert@spenarnc.xs4all.nl wrote:
    In article <66188ab1$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote:
    On 12/04/2024 1:11 am, albert@spenarnc.xs4all.nl wrote:

    While others indulge in endless discussions about DRSHIFT
    I thought to attempt some literate programming.

    It didn't prompt you to test your own implementation?

    ( D0= D0<> D0< D= D< D- M+ DRSHIFT DLSHIFT DU< ) \ AvdH B6Mar22

    : DLSHIFT >R SWAP DUP R@ LSHIFT SWAP 8 CELLS R@ - RSHIFT ROT R>
    LSHIFT OR ;

    : DRSHIFT >R DUP R@ RSHIFT SWAP 8 CELLS R@ - LSHIFT ROT R>
    RSHIFT OR SWAP ;

    0 4 d. 17179869184 ok
    0 4 0 drshift d. 17179869188 ok

    4 0 d. 4 ok
    4 0 0 dlshift d. 17179869188 ok


    Good catch! Shifting over 8 CELLS is an ambiguous condition.
    insert
    DUP 0= IF EXIT THEN
    in front of the code.

    That handles the specific case '0 shift' but the ambiguous condition
    you mention arises again here:

    HEX
    03 01 8 cells dlshift .( Expected: 00 03 Got: ) swap u. u. cr
    FF 00 8 cells dlshift .( Expected: 00 FF Got: ) swap u. u. cr
    00 01 8 cells drshift .( Expected: 01 00 Got: ) swap u. u. cr
    00 FF 8 cells drshift .( Expected: FF 00 Got: ) swap u. u. cr
    DECIMAL

    You are right. Totally annoyed with this. Changed the library to

    : DLSHIFT 0 ?DO 2DUP D+ LOOP ;

    : DRSHIFT 0 ?DO 2 UDM/MOD ROT DROP LOOP ;


    Groetjes Albert
    --
    Don't praise the day before the evening. One swallow doesn't make spring.
    You must not say "hey" before you have crossed the bridge. Don't sell the
    hide of the bear until you shot it. Better one bird in the hand than ten in
    the air. First gain is a cat purring. - the Wise from Antrim -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)