[m-dev.] for review: change semantics of integer shifts

Simon Taylor stayl at cs.mu.OZ.AU
Thu Mar 18 12:55:58 AEDT 1999


Estimated hours taken: 1

Change the bit shift operators 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.

Index: NEWS
===================================================================
RCS file: /home/mercury1/repository/mercury/NEWS,v
retrieving revision 1.136
diff -u -u -r1.136 NEWS
--- NEWS	1999/03/18 01:27:38	1.136
+++ NEWS	1999/03/18 01:36:08
@@ -51,6 +51,14 @@
 	float__min_exponent/1,
 	float__max_exponent/1.
 
+* The implementations of `int:>>/2' and `int:<</2' have been changed to define
+  the results for negative shift counts and shift counts greater than the
+  word size.
+
+  For efficiency, we also provide the functions `int:unchecked_left_shift/2'
+  and `int:unchecked_right_shift/2' that, like the previous implementations
+  of `int:>>/2' and `int:<</2', do not check for these cases.
+
 * The extras distribution now includes support for dynamic linking.
 
   The interface is based on the C functions dlopen(), dlsym(), and co.,
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/18 01:47:02
@@ -106,14 +106,50 @@
 :- func int rem int = int.
 :- mode in rem in = uo is det.
 
-	% left shift
+	% X << Y returns X left shifted by Y bits. 
+	%
+	% If Y is negative, X >> -Y is returned.
+	%
+	% If Y is greater than or equal to the
+	% result of `int__bits_per_int/1', 0 is returned.
+	% Vacated bit positions are filled with 0-bits.
 :- func int << int = int.
 :- mode in  << in  = uo  is det.
 
-	% (arithmetic) right shift
+	% unchecked_left_shift(X, Y) returns X left shifted by Y bits 
+	% using the C `<<' operator.
+	%
+	% Vacated bit positions are filled with 0-bits.
+	% 
+	% The result is implementation defined if Y is negative,
+	% or is greater than or equal to the result of `int__bits_per_int/1'.
+:- func unchecked_left_shift(int, int) = int.
+:- mode unchecked_left_shift(in, in) = uo is det.
+
+	% X >> Y returns X (arithmetic) right shifted by Y bits.
+	%
+	% If Y is negative, X << -Y is returned.
+	%
+	% Otherwise, the vacated bit positions are filled with 1-bits if
+	% X is negative or 0-bits if X is positive.
+	% Note: this assumes two's complement arithmetic.
+	% tests/hard_coded/shift_test.m will fail if this is not the case.
 :- func int >> int = int.
 :- mode in  >> in  = uo  is det.
 
+	% unchecked_right_shift(X, Y) returns X (arithmetic) right shifted
+	% by Y bits using the C '>>' operator.
+	%
+	% Vacated bit positions are filled with 1-bits if
+	% X is negative or 0-bits if X is positive.
+	% Note: this assumes two's complement arithmetic.
+	% tests/hard_coded/shift_test.m will fail if this is not the case.
+	%
+	% The result is implementation defined if Y is negative,
+	% or is greater than or equal to the result of `int__bits_per_int/1'.
+:- 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 +256,49 @@
 	).
 
 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.
+
+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: compiler/code_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_util.m,v
retrieving revision 1.104
diff -u -u -r1.104 code_util.m
--- code_util.m	1998/11/24 03:56:57	1.104
+++ code_util.m	1999/03/12 00:29:53
@@ -434,11 +434,11 @@
 	no, yes(Z - binop((mod), var(X), var(Y)))).
 code_util__translate_builtin_2("int", "builtin_left_shift", 0, [X, Y, Z],
 	no, yes(Z - binop((<<), var(X), var(Y)))).
-code_util__translate_builtin_2("int", "<<", 0, [X, Y, Z],
+code_util__translate_builtin_2("int", "unchecked_left_shift", 0, [X, Y, Z],
 	no, yes(Z - binop((<<), var(X), var(Y)))).
 code_util__translate_builtin_2("int", "builtin_right_shift", 0, [X, Y, Z],
 	no, yes(Z - binop((>>), var(X), var(Y)))).
-code_util__translate_builtin_2("int", ">>", 0, [X, Y, Z],
+code_util__translate_builtin_2("int", "unchecked_right_shift", 0, [X, Y, Z],
 	no, yes(Z - binop((>>), var(X), var(Y)))).
 code_util__translate_builtin_2("int", "builtin_bit_and", 0, [X, Y, Z],
 	no, yes(Z - binop((&), var(X), var(Y)))).






More information about the developers mailing list