mit-scheme-devel
[Top][All Lists]

## Re: fix:lsh signedness

 From: Chris Hanson Subject: Re: fix:lsh signedness Date: Fri, 30 Oct 2020 19:47:17 -0700

I'm in favor of it meaning left shift, since that's what I've always thought it was. I never make assumptions about what it does when shifting a negative number to the right, but that's because I nearly always use it with nonnegative numbers.
On Oct 30, 2020, 4:59 PM -0700, Taylor R Campbell <campbell+mit-scheme@mumble.net>, wrote:
What's (fix:lsh -123 -4) supposed to be?

The obvious choices are -8, 4194296, or 18014398509481976, depending
on whether it computes floor(-123/2^4) = -8 or whether it interprets
-123 as a DATUM_LENGTH-bit string and shifts in zeros giving 4194296 =
#x3ffff8 on 32-bit machines (26-bit fixnums) or 18014398509481976 =
#x3ffffffffffff8 on 64-bit machines (58-bit fixnums).

The name could be read as `logical shift', but the numerical semantics
of logical right shifts depends on the size of a fixnum. The name
could also be read as `left shift', since positive amounts are shifted
left and negative amounts are shifted in the opposite direction.

The history is a little complicated:

- When gjr originally implemented the fixnum-lsh in 1990 (f4af6560),
he implemented logical right shift semantics.

- In some compiler back ends, gjr initially open-coded arithmetic
right shift semantics, but later changed it to logical right shift.

- When Arthur originally documented the fix:lsh procedure in 1991
(bbc428a9), he documented arithmetic right shift semantics.

- Two years later, Chris updated the documentation in 1993 (f7136490)
to reflect what was actually implemented.

- Over the next ten years or so, logical right shift semantics was
also implemented in various compiler back ends.

- In 2009, under the misapprehension that `lsh' meant `left shift' and
not `logical shift' (https://savannah.gnu.org/bugs/?27385), I
`fixed' the i386 and amd64 lap generation rules for fixnum-lsh so
that it implemented arithmetic right shifts instead of logical right
shifts (1f62f5c1).

- ...Except I missed the case of a constant shift amount until a
little under two years ago in a change I didn't actually commit
until just recently (c689398c) while adding open-coding for
integer-shift-left and integer-shift-right (which obviously has
arithmetic right shift semantics since that's the only reasonable
choice for arbitrary-size integers).

So for most of the 30 years of the fix:lsh procedure and fixnum-lsh
primitive, they have implemented logical right shifts. But several
people were confused -- and in the ten years since I `broke' the
semantics, apparently nobody has complained about having arithmetic
right shifts on i386 and amd64.

I'm not sure I've ever seen code that relies on logical right shift
semantics in fix:lsh, and the semantics of such code would be
unusually dependent on the size of a fixnum. And, to be honest, I'm
kind of struggling to imagine why anyone would want logical right
shift semantics for fixnums.

What to do?

1. Forget we ever implemented logical right shifts and make it all
arithmetic right shifts (which means, at this point, just changing
the microcode primitive, really).

2. (a) Fix i386 and amd64 again to implement logical right shifts --
and hope that doesn't break any code in the last decade!
(b) Introduce a new primitive and rtl operator, say fixnum-ash,
that does arithmetic shifts, and adapt the open-coding rules I
just added for integer-shift-left and integer-shift-right to
use it.

3. Something else?