[m-rev.] for review: ensure signed integer arithmetic wraps on overflow in C grades
Julien Fischer
jfischer at opturion.com
Sat May 5 23:26:19 AEST 2018
For review by anyone.
This was discussed on the developers list in April. The changes to the
reference manual I mentioned then will be made separately.
---------------------------
Ensure signed integer arithmetic wraps on overflow in C grades.
Ensure that signed integer addition, subtraction and multiplication always wrap
in C grades. We do this by compiling
X : int + Y : int
as:
(MR_Integer)((MR_Unsigned)X + (MR_Unsigned)Y)
and similarly for the other operations. This brings the C grades into line
with the C# and Jave grades, where this behaviour is required by the respective
language specifications of those target languages.
compiler/llds_out_data.m:
compiler/mlds_to_c.m:
Make the above change.
Julien.
diff --git a/compiler/llds_out_data.m b/compiler/llds_out_data.m
index afae301..70b9ce8 100644
--- a/compiler/llds_out_data.m
+++ b/compiler/llds_out_data.m
@@ -1038,7 +1038,52 @@ output_rval(Info, Rval, !IO) :-
( Op = int_add(IntType), OpStr = "+"
; Op = int_sub(IntType), OpStr = "-"
; Op = int_mul(IntType), OpStr = "*"
- ; Op = int_div(IntType), OpStr = "/"
+ ),
+ (
+ (
+ IntType = int_type_int,
+ SignedType = "MR_Integer",
+ UnsignedType = "MR_Unsigned"
+ ;
+ IntType = int_type_int8,
+ SignedType = "int8_t",
+ UnsignedType = "uint8_t"
+ ;
+ IntType = int_type_int16,
+ SignedType = "int16_t",
+ UnsignedType = "uint16_t"
+ ;
+ IntType = int_type_int32,
+ SignedType = "int32_t",
+ UnsignedType = "uint32_t"
+ ;
+ IntType = int_type_int64,
+ SignedType = "int64_t",
+ UnsignedType = "uint64_t"
+ ),
+ % We used to handle X + (-C) (for constant C) specially, by
+ % converting it to X - C, but we no longer do that since it
+ % would overflow in the case where C == min_int.
+ io.format("(%s)((%s)", [s(SignedType), s(UnsignedType)], !IO),
+ output_rval_as_type(Info, SubRvalA, lt_int(IntType), !IO),
+ io.format(" %s (%s)", [s(OpStr), s(UnsignedType)], !IO),
+ output_rval_as_type(Info, SubRvalB, lt_int(IntType), !IO),
+ io.write_string(")", !IO)
+ ;
+ ( IntType = int_type_uint
+ ; IntType = int_type_uint8
+ ; IntType = int_type_uint16
+ ; IntType = int_type_uint32
+ ; IntType = int_type_uint64
+ ),
+ io.write_string("(", !IO),
+ output_rval_as_type(Info, SubRvalA, lt_int(IntType), !IO),
+ io.format(" %s ", [s(OpStr)], !IO),
+ output_rval_as_type(Info, SubRvalB, lt_int(IntType), !IO),
+ io.write_string(")", !IO)
+ )
+ ;
+ ( Op = int_div(IntType), OpStr = "/"
; Op = int_mod(IntType), OpStr = "%"
; Op = eq(IntType), OpStr = "=="
; Op = ne(IntType), OpStr = "!="
@@ -1091,23 +1136,6 @@ output_rval(Info, Rval, !IO) :-
io.write_string(" ", !IO),
output_rval(Info, SubRvalB, !IO),
io.write_string(")", !IO)
- % else if
- % XXX broken for C == minint
- % (since `NewC = 0 - C' overflows)
- % Op = (+),
- % SubRvalB = const(llconst_int(C)),
- % C < 0
- % then
- % NewOp = (-),
- % NewC = 0 - C,
- % NewSubRvalB = const(llconst_int(NewC)),
- % io.write_string("("),
- % output_rval(SubRvalA),
- % io.write_string(" "),
- % io.write_string(NewOpStr),
- % io.write_string(" "),
- % output_rval(NewSubRvalB),
- % io.write_string(")")
else
io.write_string("(", !IO),
output_rval_as_type(Info, SubRvalA, lt_int(IntType), !IO),
diff --git a/compiler/mlds_to_c.m b/compiler/mlds_to_c.m
index 2e90c51..b103674 100644
--- a/compiler/mlds_to_c.m
+++ b/compiler/mlds_to_c.m
@@ -5134,10 +5134,55 @@ mlds_output_binop(Opts, Op, X, Y, !IO) :-
mlds_output_rval(Opts, Y, !IO),
io.write_string("))", !IO)
;
- ( Op = int_add(_), OpStr = "+"
- ; Op = int_sub(_), OpStr = "-"
- ; Op = int_mul(_), OpStr = "*"
- ; Op = int_div(_), OpStr = "/"
+ ( Op = int_add(IntType), OpStr = "+"
+ ; Op = int_sub(IntType), OpStr = "-"
+ ; Op = int_mul(IntType), OpStr = "*"
+ ),
+ (
+ (
+ IntType = int_type_int,
+ SignedType = "MR_Integer",
+ UnsignedType = "MR_Unsigned"
+ ;
+ IntType = int_type_int8,
+ SignedType = "int8_t",
+ UnsignedType = "uint8_t"
+ ;
+ IntType = int_type_int16,
+ SignedType = "int16_t",
+ UnsignedType = "uint16_t"
+ ;
+ IntType = int_type_int32,
+ SignedType = "int32_t",
+ UnsignedType = "uint32_t"
+ ;
+ IntType = int_type_int64,
+ SignedType = "int64_t",
+ UnsignedType = "uint64_t"
+ ),
+ io.format("(%s)((%s)", [s(SignedType), s(UnsignedType)], !IO),
+ mlds_output_rval_as_op_arg(Opts, X, !IO),
+ io.format(" %s (%s)", [s(OpStr), s(UnsignedType)], !IO),
+ mlds_output_rval_as_op_arg(Opts, Y, !IO),
+ io.write_string(")", !IO)
+ ;
+ ( IntType = int_type_uint
+ ; IntType = int_type_uint8
+ ; IntType = int_type_uint16
+ ; IntType = int_type_uint32
+ ; IntType = int_type_uint64
+ ),
+ % We could treat X + (-const) specially, but we don't.
+ % The reason is documented in the equivalent code in
+ % llds_out_data.m.
+ io.write_string("(", !IO),
+ mlds_output_rval_as_op_arg(Opts, X, !IO),
+ io.format(" %s ", [s(OpStr)], !IO),
+ mlds_output_rval_as_op_arg(Opts, Y, !IO),
+ io.write_string(")", !IO)
+ )
+ ;
+ ( Op = int_div(_), OpStr = "/"
; Op = int_mod(_), OpStr = "%"
; Op = eq(_), OpStr = "=="
; Op = ne(_), OpStr = "!="
More information about the reviews
mailing list