[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