[m-rev.] for review: fix float field structure padding/packing problems
Peter Wang
novalazy at gmail.com
Mon Dec 5 17:50:36 AEDT 2011
Can someone apply this and test with MSVC and MinGW?
I've only tested the single precision floats on 64-bit Linux part.
Would it be worth avoiding the C extensions when
sizeof(MR_Float) == sizeof(MR_Word)? That can't be evaluated by the C
preprocessor, though.
---
Branches: main
Fix bug #240 and bug #211. When MR_Float is wider than MR_Word, the C compiler
may introduce padding for the structure field following the MR_Float. When
MR_Float is narrower than MR_Word the C compiler may pack consecutive MR_Float
fields. In both cases the C structure layout does not match what was intended
by the Mercury compiler.
runtime/mercury_float.h:
Add a typedef `MR_Float_Aligned' which forces word alignment using
C extensions provided by gcc/clang/MSVC.
compiler/llds_out_global.m:
compiler/mlds_to_c.m:
Use `MR_Float_Aligned' in place of `MR_Float' in structure definitions.
tests/hard_coded/Mercury.options:
tests/hard_coded/Mmakefile:
tests/hard_coded/bug240.exp:
tests/hard_coded/bug240.m:
Add test case.
diff --git a/compiler/llds_out_global.m b/compiler/llds_out_global.m
index 0807291..85a253f 100644
--- a/compiler/llds_out_global.m
+++ b/compiler/llds_out_global.m
@@ -516,7 +516,12 @@ common_group_get_rvals(common_cell_ungrouped_arg(_, Rval)) = [Rval].
output_cons_arg_types([], _, _, !IO).
output_cons_arg_types([Type | Types], Indent, ArgNum, !IO) :-
io.write_string(Indent, !IO),
- output_llds_type(Type, !IO),
+ ( Type = lt_float ->
+ % Ensure float structure members are word-aligned.
+ io.write_string("MR_Float_Aligned", !IO)
+ ;
+ output_llds_type(Type, !IO)
+ ),
io.write_string(" f", !IO),
io.write_int(ArgNum, !IO),
io.write_string(";\n", !IO),
diff --git a/compiler/mlds_to_c.m b/compiler/mlds_to_c.m
index e1add26..6999ee5 100644
--- a/compiler/mlds_to_c.m
+++ b/compiler/mlds_to_c.m
@@ -1583,7 +1583,12 @@ mlds_output_scalar_cell_group_struct_defn(Opts, Indent, MangledModuleName,
mlds_output_scalar_cell_group_struct_field(Opts, Indent, FieldType,
Num, Num + 1, !IO) :-
mlds_indent(Indent, !IO),
- mlds_output_type_prefix(Opts, FieldType, !IO),
+ ( FieldType = mlds_native_float_type ->
+ % Ensure float structure members are word-aligned.
+ io.write_string("MR_Float_Aligned", !IO)
+ ;
+ mlds_output_type_prefix(Opts, FieldType, !IO)
+ ),
io.format(" f%d;\n", [i(Num)], !IO).
:- pred mlds_output_scalar_cell_group_type_and_name(mlds_to_c_opts::in,
diff --git a/runtime/mercury_float.h b/runtime/mercury_float.h
index 049477f..28d5728 100644
--- a/runtime/mercury_float.h
+++ b/runtime/mercury_float.h
@@ -29,6 +29,21 @@
#define MR_FLOAT_WORDS ((sizeof(MR_Float) + sizeof(MR_Word) - 1) \
/ sizeof(MR_Word))
+ /*
+ ** MR_Float_Aligned is a word-aligned version of MR_Float. This is necessary
+ ** when MR_Float is single precision on a 64-bit platform to avoid packing
+ ** consecutive float fields, or when MR_Float is double precision on some
+ ** 32-bit platforms (e.g. Win32) to avoid introducing padding.
+ */
+#if defined(MR_GNUC) || defined(MR_CLANG)
+ typedef MR_Float MR_Float_Aligned __attribute__((aligned(sizeof(MR_Word))));
+#elif defined(MR_MSVC)
+ typedef _declspec(align(sizeof(MR_Word))) MR_Float MR_Float_Aligned;
+#else
+ /* Hope for the best. */
+ typedef MR_Float MR_Float_Aligned;
+#endif
+
#ifdef MR_BOXED_FLOAT
#define MR_word_to_float(w) (* (MR_Float *) (w))
diff --git a/tests/hard_coded/Mercury.options b/tests/hard_coded/Mercury.options
index 2e6cb07..28f1613 100644
--- a/tests/hard_coded/Mercury.options
+++ b/tests/hard_coded/Mercury.options
@@ -10,6 +10,7 @@ MCFLAGS-bigtest = --intermodule-optimization -O3
MCFLAGS-boyer = --infer-all
MCFLAGS-bug103 = --optimize-constructor-last-call
MCFLAGS-bug160 = -w --optimize-peep-mkword
+MCFLAGS-bug240 = -O1
MCFLAGS-checked_nondet_tailcall = --checked-nondet-tailcalls
MCFLAGS-checked_nondet_tailcall_noinline = --checked-nondet-tailcalls --no-inlining
MCFLAGS-cc_and_non_cc_test = --no-inlining
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 3d2a2dc..07db8d3 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -18,6 +18,7 @@ ORDINARY_PROGS= \
brace \
bug103 \
bug160 \
+ bug240 \
builtin_inst_rename \
c_write_string \
calendar_test \
diff --git a/tests/hard_coded/bug240.exp b/tests/hard_coded/bug240.exp
new file mode 100644
index 0000000..b858b82
--- /dev/null
+++ b/tests/hard_coded/bug240.exp
@@ -0,0 +1,6 @@
+123.0
+456.0
+789
+123.0
+456.0
+789
diff --git a/tests/hard_coded/bug240.m b/tests/hard_coded/bug240.m
new file mode 100644
index 0000000..16ea1e7
--- /dev/null
+++ b/tests/hard_coded/bug240.m
@@ -0,0 +1,49 @@
+% Regression test for bug #240 and bug #211.
+% When a structure definition has a MR_Float member the C compiler could lay
+% the structure out differently from that which is expected by the Mercury
+% compiler.
+
+:- module bug240.
+
+:- interface.
+
+:- import_module io.
+
+:- type t
+ ---> a(int)
+ ; b(int)
+ ; c(int)
+ ; d(int)
+ ; fc(float, float, int).
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+main(!IO) :-
+ X = fc(123.0, 456.0, 789),
+ write_fc(X, !IO),
+ Z = mkfc(123.0, 456.0, 789),
+ write_fc(Z, !IO).
+
+:- func mkfc(float::in, float::in, int::in) =
+ (t::out(bound(fc(ground, ground, ground)))) is det.
+
+:- pragma no_inline(mkfc/3).
+
+mkfc(F1, F2, I) = G :-
+ G = fc(F1, F2, I).
+
+:- pred write_fc(t::in(bound(fc(ground, ground, ground))), io::di, io::uo)
+ is det.
+
+:- pragma no_inline(write_fc/3).
+
+write_fc(X, !IO) :-
+ X = fc(Y1, Y2, Y3),
+ io.write(Y1, !IO),
+ io.nl(!IO),
+ io.write(Y2, !IO),
+ io.nl(!IO),
+ io.write(Y3, !IO),
+ io.nl(!IO).
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list