[m-dev.] for review: change semantics of integer shifts
Simon Taylor
stayl at cs.mu.OZ.AU
Fri Mar 19 14:50:16 AEDT 1999
> This looks much better this time.
> However, I have some suggestions about the library documentation.
> The comment about tests/hard_coded/shift_test.m is
> a dangling comment, since tests/hard_coded/shift_test.m
> does not exist and is not added by this change.
See below.
Estimated hours taken: 1
Change the bit shift functions to perform checking to avoid
implementation defined behaviour.
library/int.m:
Add checking to `int:<<' and `int:>>'.
compiler/code_util.m:
Replace `int:<<' and `int:>>' with `int:unchecked_left_shift' and
`int:unchecked_right_shift' in the builtin table.
NEWS:
Mention the changes to int.m.
tests/hard_coded/Mmakefile:
tests/hard_coded/shift_test.m:
tests/hard_coded/shift_test.exp:
Test the shift functions.
Index: library/int.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/int.m,v
retrieving revision 1.52
diff -u -u -r1.52 int.m
--- int.m 1998/01/23 12:33:19 1.52
+++ int.m 1999/03/19 03:41:38
@@ -1,14 +1,18 @@
%---------------------------------------------------------------------------%
-% Copyright (C) 1994-1997 The University of Melbourne.
+% Copyright (C) 1994-1999 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB in the Mercury distribution.
%---------------------------------------------------------------------------%
%
-% int - some predicates for dealing with machine-size integer numbers.
-%
+% File: int.m.
% Main authors: conway, fjh.
% Stability: medium.
%
+% Predicates and functions for dealing with machine-size integer numbers.
+%
+% The predicates and functions in this module do not check for overflow.
+% The behaviour of a computation for which overflow occurs is undefined.
+%
%-----------------------------------------------------------------------------%
:- module int.
@@ -106,14 +110,34 @@
:- func int rem int = int.
:- mode in rem in = uo is det.
- % left shift
+ % Left shift.
+ % X << Y returns X "left shifted" by Y bits.
+ % To be precise, if Y is negative, the result is
+ % X div (2^(-Y)), otherwise the result is X * (2^Y).
:- func int << int = int.
:- mode in << in = uo is det.
- % (arithmetic) right shift
+ % unchecked_left_shift(X, Y) is the same as X << Y
+ % except that the behaviour is undefined if Y is negative,
+ % or greater than or equal to the result of `int__bits_per_int/1'.
+ % It will typically be implemented more efficiently than X << Y.
+:- func unchecked_left_shift(int, int) = int.
+:- mode unchecked_left_shift(in, in) = uo is det.
+
+ % Right shift.
+ % X >> Y returns X "arithmetic right shifted" by Y bits.
+ % To be precise, if Y is negative, the result is
+ % X * (2^(-Y)), otherwise the result is X div (2^Y).
:- func int >> int = int.
:- mode in >> in = uo is det.
+ % unchecked_right_shift(X, Y) is the same as X >> Y
+ % except that the behaviour is undefined if Y is negative,
+ % or greater than or equal to the result of `int__bits_per_int/1'.
+ % It will typically be implemented more efficiently than X >> Y.
+:- func unchecked_right_shift(int, int) = int.
+:- mode unchecked_right_shift(in, in) = uo is det.
+
% bitwise and
:- func int /\ int = int.
:- mode in /\ in = uo is det.
@@ -220,6 +244,51 @@
).
X mod Y = X - (X div Y) * Y.
+
+ % XXX This definition is here for bootstrapping.
+ % After the corresponding change to the compiler is installed,
+ % the compiler will ignore this clause, and will internally replace
+ % the body of unchecked_left_shift with a `recursive' call.
+ % See make_hlds:add_builtin.
+unchecked_left_shift(X, Y) = X << Y.
+
+X << Y = Z :-
+ int__bits_per_int(IntBits),
+ ( Y >= 0 ->
+ ( Y >= IntBits ->
+ Z = 0
+ ;
+ Z = unchecked_left_shift(X, Y)
+ )
+ ;
+ ( Y =< -IntBits ->
+ Z = (if X >= 0 then 0 else -1)
+ ;
+ Z = unchecked_right_shift(X, -Y)
+ )
+ ).
+
+ % XXX This definition is here for bootstrapping.
+ % See the comment for unchecked_left_shift.
+unchecked_right_shift(X, Y) = X >> Y.
+
+ % Note: this assumes two's complement arithmetic.
+ % tests/hard_coded/shift_test.m will fail if this is not the case.
+X >> Y = Z :-
+ int__bits_per_int(IntBits),
+ ( Y >= 0 ->
+ ( Y >= IntBits ->
+ Z = (if X >= 0 then 0 else -1)
+ ;
+ Z = unchecked_right_shift(X, Y)
+ )
+ ;
+ ( Y =< -IntBits ->
+ Z = 0
+ ;
+ Z = unchecked_left_shift(X, -Y)
+ )
+ ).
int__abs(Num, Abs) :-
(
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/staff/zs/imp/tests/hard_coded/Mmakefile,v
retrieving revision 1.51
diff -u -u -r1.51 Mmakefile
--- Mmakefile 1999/02/08 23:36:46 1.51
+++ Mmakefile 1999/03/16 00:55:43
@@ -80,6 +80,7 @@
reverse_arith \
rnd \
rtc_bug \
+ shift_test \
space \
string_alignment \
string_loop \
Index: tests/hard_coded/shift_test.exp
===================================================================
RCS file: shift_test.exp
diff -N shift_test.exp
--- /dev/null Fri Mar 19 14:39:39 1999
+++ shift_test.exp Thu Mar 18 12:14:00 1999
@@ -0,0 +1,18 @@
+64 << 2 = 256 (256)
+-64 << 2 = -256 (-256)
+64 << -2 = 16 (16)
+-64 << -2 = -16 (-16)
+64 << 256 = 0 (0)
+64 << -256 = 0 (0)
+-64 << 256 = 0 (0)
+-64 << -256 = -1 (-1)
+64 >> 2 = 16 (16)
+-64 >> 2 = -16 (-16)
+64 >> -2 = 256 (256)
+-64 >> -2 = -256 (-256)
+64 >> 256 = 0 (0)
+64 >> -256 = 0 (0)
+-64 >> 256 = -1 (-1)
+-64 >> -256 = 0 (0)
+64 unchecked_left_shift 2 = 256 (256)
+-64 unchecked_right_shift 2 = -16 (-16)
Index: tests/hard_coded/shift_test.m
===================================================================
RCS file: shift_test.m
diff -N shift_test.m
--- /dev/null Fri Mar 19 14:39:39 1999
+++ shift_test.m Thu Mar 18 12:15:40 1999
@@ -0,0 +1,45 @@
+% test the handling of `>>', `<<', unchecked_left_shift
+% and unchecked_right_shift.
+
+:- module shift_test.
+:- interface.
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+:- import_module int, list, string.
+
+main -->
+ shift_test((<<), "<<", 64, 2, 256),
+ shift_test((<<), "<<", -64, 2, -256),
+ shift_test((<<), "<<", 64, -2, 16),
+ shift_test((<<), "<<", -64, -2, -16),
+ shift_test((<<), "<<", 64, 256, 0),
+ shift_test((<<), "<<", 64, -256, 0),
+ shift_test((<<), "<<", -64, 256, 0),
+ shift_test((<<), "<<", -64, -256, -1),
+
+ shift_test((>>), ">>", 64, 2, 16),
+ shift_test((>>), ">>", -64, 2, -16),
+ shift_test((>>), ">>", 64, -2, 256),
+ shift_test((>>), ">>", -64, -2, -256),
+ shift_test((>>), ">>", 64, 256, 0),
+ shift_test((>>), ">>", 64, -256, 0),
+ shift_test((>>), ">>", -64, 256, -1),
+ shift_test((>>), ">>", -64, -256, 0),
+
+ shift_test(unchecked_left_shift, "unchecked_left_shift",
+ 64, 2, 256),
+ shift_test(unchecked_right_shift, "unchecked_right_shift",
+ -64, 2, -16).
+
+:- pred shift_test((func(int, int) = int)::(func(in, in) = out is det),
+ string::in, int::in, int::in, int::in,
+ io__state::di, io__state::uo) is det.
+
+shift_test(Func, FuncName, Left, Right, Result) -->
+ io__format("%d %s %d = %d (%d)\n",
+ [i(Left), s(FuncName), i(Right),
+ i(Func(Left, Right)), i(Result)]).
+
More information about the developers
mailing list