Bit shifts
Jose E. Marchesi
jemarch@gnu.org
Wed Feb 4 10:18:03 GMT 2026
> Hello people.
>
>
> As James already noticed, the existing implementation of the standard
> bit shifting operators SHR and SHL just uses the same C semantics, and
> also it is broken.
>
> The Revised Report defines the following semantics for the operators.
> Note that below I use the notation c[N] to mean the Nth bit in c, but we
> know bits values cannot be sliced like that.
>
> op SHL = (bits a, int b) bits:
> if ABS b <= bits_width
> then bits c := a;
> to ABS b
Note that there are no loop iterations if b = 0 (the implicit counter in
the loop gets initialized to 1). In that case the value is returned
intact as expected.
The correspondin implementation is:
/* Rotate the bits in BITS according to the value of SHIFT:
- If ABS(SHIFT) => bits_width, the operation is a nop.
- If SHIFT is positive, BITS gets shifted SHIFT bits to the right.
- If SHIFT is negative, BITS gets shifted ABS(SHIFT) bits to the left.
*/
tree
a68_bits_shift (tree shift, tree bits)
{
shift = save_expr (shift);
bits = save_expr (bits);
tree shift_type = TREE_TYPE (shift);
tree bits_type = TREE_TYPE (bits);
tree abs_shift = save_expr (fold_build1 (ABS_EXPR, TREE_TYPE (shift), shift));
tree shifted_right = fold_build2 (RSHIFT_EXPR, bits_type, bits, abs_shift);
tree shifted_left = fold_build2 (LSHIFT_EXPR, bits_type, bits, abs_shift);
tree shifted_bits = fold_build3 (COND_EXPR, TREE_TYPE (bits),
fold_build2 (GE_EXPR, shift_type,
shift, build_zero_cst (shift_type)),
shifted_right, shifted_left);
return fold_build3 (COND_EXPR,
TREE_TYPE (bits),
fold_build2 (LT_EXPR, TREE_TYPE (abs_shift),
abs_shift, a68_bits_width (bits_type)),
shifted_bits, bits);
}
The resulting GENERIC tree has no undefined behavior whatsoever. It
also runs Jame's testscase properly.
> do if b > 0
> then for i from 2 to bits_width
> do c[i-1] := c[i] od;
> c[bits_width] := false
> else
> for i from bits_width by -1 to 2
> do c[i] := c[i-1] od;
> c[1] := false
> fi
> od;
> c
> fi;
>
> op SHR = (bits x, int n) bits: x SHL -n;
>
>> From the above, we see that:
>
> 1. The shift count is signed. It's sign determines the direction of
> shifting, meaning that SHR by a negative count is a left shift, and a
> SHL by a negative count is a right shift.
>
> 2. Attempting to shift by more than the width of the bits value, in
> either direction, is a no-op. No run-time error nor undefined.
>
> 3. We don't have signed shifting and its associated problems in Algol
> 68, because `bits' values do not have signedness. The resulting bits
> (conceptually a multiple of booleans) will be interpreted when/if the
> operator ABS is applied to it, resulting in a signed integral value
> which may be negative, but none of that is of relevance in
> unconverted `bits' values.
>
> I am fixing the implementation of these operators in ga68 in order to
> follow these semantics, document it in the manual and adding a few
> tests.
>
> Salud!
More information about the Algol68
mailing list