[m-rev.] for review: Don't cast int32/uint32 to MR_Word in foreign code input assignments.
Peter Wang
novalazy at gmail.com
Thu Oct 1 15:45:31 AEST 2026
On Thu, 01 Oct 2026 14:35:44 +1000 "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:
>
>
> On Thu, 1 Oct 2026 14:13:29 +1000, Peter Wang <novalazy at gmail.com> wrote:
> > This fixes gcc warnings on 64-bit platforms of the form:
> >
> > warning: overflow in conversion from ‘long long unsigned int’ to
> > ‘int32_t’ {aka ‘int’} changes value from ‘18446744071562067968’ to
> > ‘-2147483648’ [-Woverflow]
> >
> > for the generated code:
> >
> > I32 = ((MR_Word) INT32_MIN);
> >
> > compiler/llds_out_instr.m:
> > In output_foreign_proc_inputs, output int32/uint32 input values
> > without a cast to MR_Word.
>
> For this to work by design instead of by accident, we have to ensure that
> the type of the integer we output here is the same as, or at least is
> automatically castable to, the declared type of the foreign language
> variable representing that input arg. That type is decided by whatever
> code sets the third field of the foreign_proc_arg_decl given to
> output_foreign_proc_decls, which is not in that file. You should find
> that code, and add a link to it here.
Do you mean the 2nd field of foreign_proc_arg_decl?
That code is in make_foreign_proc_decl:
(
BoxPolicy = bp_native_if_possible,
OrigTypeString = exported_type_to_c_string(ModuleInfo, OrigType)
;
BoxPolicy = bp_always_boxed,
OrigTypeString = "MR_Word"
),
ArgDecl = foreign_proc_arg_decl(OrigType, OrigTypeString, ArgName),
exported_type_to_c_string calls exported_builtin_type_to_c_string
which returns the C types for the fixed sized integer types.
> I am surprised that we do not treat 8 and 16 bit ints/uints the same way
> we now treat 32 and 64 bit. Why? If writing them out as lt_word is fine,
> there should be a comment explaining *why* it is fine.
You're right, 8- and 16-bit ints have the same issue.
Here is an updated patch.
Peter
---
Don't cast fixed sized int values to MR_Word in foreign code input assignments.
This fixes gcc warnings of the form:
warning: overflow in conversion from ‘long long unsigned int’ to
‘int32_t’ {aka ‘int’} changes value from ‘18446744071562067968’ to
‘-2147483648’ [-Woverflow]
for the generated code:
I32 = ((MR_Word) INT32_MIN);
compiler/llds_out_instr.m:
In output_foreign_proc_inputs, output fixed sized integers
without a cast to MR_Word.
hard_coded/Mmakefile:
hard_coded/foreign_proc_min_int.exp:
hard_coded/foreign_proc_min_int.m:
Add test case.
diff --git a/compiler/llds_out_instr.m b/compiler/llds_out_instr.m
index 9eb99e26af..53507f959e 100644
--- a/compiler/llds_out_instr.m
+++ b/compiler/llds_out_instr.m
@@ -2010,23 +2010,36 @@ output_foreign_proc_input(Info, Stream, Input, !IO) :-
BuiltinType = builtin_type_float,
output_rval_as_type(Info, Rval, lt_float, Stream, !IO)
;
- BuiltinType = builtin_type_int(int_type_int64),
- output_rval_as_type(Info, Rval,
- lt_int(int_type_int64), Stream, !IO)
- ;
- BuiltinType = builtin_type_int(int_type_uint64),
- output_rval_as_type(Info, Rval,
- lt_int(int_type_uint64), Stream, !IO)
+ (
+ BuiltinType = builtin_type_int(int_type_int8),
+ DesiredType = lt_int(int_type_int8)
+ ;
+ BuiltinType = builtin_type_int(int_type_uint8),
+ DesiredType = lt_int(int_type_uint8)
+ ;
+ BuiltinType = builtin_type_int(int_type_int16),
+ DesiredType = lt_int(int_type_int16)
+ ;
+ BuiltinType = builtin_type_int(int_type_uint16),
+ DesiredType = lt_int(int_type_uint16)
+ ;
+ BuiltinType = builtin_type_int(int_type_int32),
+ DesiredType = lt_int(int_type_int32)
+ ;
+ BuiltinType = builtin_type_int(int_type_uint32),
+ DesiredType = lt_int(int_type_uint32)
+ ;
+ BuiltinType = builtin_type_int(int_type_int64),
+ DesiredType = lt_int(int_type_int64)
+ ;
+ BuiltinType = builtin_type_int(int_type_uint64),
+ DesiredType = lt_int(int_type_uint64)
+ ),
+ output_rval_as_type(Info, Rval, DesiredType, Stream, !IO)
;
( BuiltinType = builtin_type_char
; BuiltinType = builtin_type_int(int_type_int)
; BuiltinType = builtin_type_int(int_type_uint)
- ; BuiltinType = builtin_type_int(int_type_int8)
- ; BuiltinType = builtin_type_int(int_type_uint8)
- ; BuiltinType = builtin_type_int(int_type_int16)
- ; BuiltinType = builtin_type_int(int_type_uint16)
- ; BuiltinType = builtin_type_int(int_type_int32)
- ; BuiltinType = builtin_type_int(int_type_uint32)
),
output_rval_as_type(Info, Rval, lt_word, Stream, !IO)
)
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 4c79a5275c..b8e39798d9 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -171,6 +171,7 @@ ORDINARY_PROGS = \
foreign_enum_switch \
foreign_import_module \
foreign_name_mutable \
+ foreign_proc_min_int \
foreign_type_1 \
foreign_type_2 \
foreign_type_3 \
diff --git a/tests/hard_coded/foreign_proc_min_int.exp b/tests/hard_coded/foreign_proc_min_int.exp
new file mode 100644
index 0000000000..49d467d6bf
--- /dev/null
+++ b/tests/hard_coded/foreign_proc_min_int.exp
@@ -0,0 +1,3 @@
+-128
+-32768
+-2147483648
diff --git a/tests/hard_coded/foreign_proc_min_int.m b/tests/hard_coded/foreign_proc_min_int.m
new file mode 100644
index 0000000000..708e1bbda0
--- /dev/null
+++ b/tests/hard_coded/foreign_proc_min_int.m
@@ -0,0 +1,71 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+
+:- module foreign_proc_min_int.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module int8.
+:- import_module int16.
+:- import_module int32.
+:- import_module int64.
+
+main(!IO) :-
+ I8 = cast_int8(-128_i8),
+ io.print_line(I8, !IO),
+
+ I16 = cast_int16(-32768_i16),
+ io.print_line(I16, !IO),
+
+ I32 = cast_int32(-2147483648_i32),
+ io.print_line(I32, !IO).
+
+%---------------------------------------------------------------------------%
+
+:- func cast_int8(int8) = int64.
+
+:- pragma foreign_proc("C",
+ cast_int8(I8::in) = (I64::out),
+ [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+ does_not_affect_liveness],
+"
+ I64 = (int64_t) I8;
+").
+
+cast_int8(I) = int64.from_int(int8.cast_to_int(I)).
+
+%---------------------------------------------------------------------------%
+
+:- func cast_int16(int16) = int64.
+
+:- pragma foreign_proc("C",
+ cast_int16(I16::in) = (I64::out),
+ [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+ does_not_affect_liveness],
+"
+ I64 = (int64_t) I16;
+").
+
+cast_int16(I) = int64.from_int(int16.cast_to_int(I)).
+
+%---------------------------------------------------------------------------%
+
+:- func cast_int32(int32) = int64.
+
+:- pragma foreign_proc("C",
+ cast_int32(I32::in) = (I64::out),
+ [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+ does_not_affect_liveness],
+"
+ I64 = (int64_t) I32;
+").
+
+cast_int32(I) = int64.from_int(int32.cast_to_int(I)).
+
+%---------------------------------------------------------------------------%
--
2.54.0
More information about the reviews
mailing list