[m-rev.] for review: fix float field structure padding/packing problems
Peter Wang
novalazy at gmail.com
Tue Dec 6 17:24:24 AEDT 2011
On Tue, 6 Dec 2011 10:32:19 +1100, Peter Wang <novalazy at gmail.com> wrote:
> On 2011-12-06, Julien Fischer <juliensf at csse.unimelb.edu.au> wrote:
> >
> > By itself the above does not work with MSVC. We also need to pass the -Zp4
> > as a flag to cl, then the test case works.
>
> Thanks. It looks like __declspec(align) didn't do what I thought
> and is actually unnecessary here.
On second thought, it would probably be necessary for single precision
floats on Win64.
The following is again untested on MSVC. Tested with clang.
---
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.
A test case was committed earlier.
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.
Output #pragma pack directives around scalar cell group structures.
This is for MSVC.
compiler/c_util.m:
Add helper predicates to output #pragma pack directives for MSVC.
runtime/mercury_conf.h.in:
Define MR_BYTES_PER_WORD. The necessary code in configure.in already
exists.
diff --git a/compiler/c_util.m b/compiler/c_util.m
index a8d2bb8..087e5fc 100644
--- a/compiler/c_util.m
+++ b/compiler/c_util.m
@@ -168,6 +168,15 @@
io::di, io::uo) is det.
%-----------------------------------------------------------------------------%
+
+ % Output #pragma pack directives to change the packing alignment value
+ % for MSVC.
+ %
+:- pred output_pragma_pack_push(io::di, io::uo) is det.
+
+:- pred output_pragma_pack_pop(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
%
% Utility predicates for working with C code
%
@@ -631,6 +640,24 @@ convert_bool_to_string(yes) = "yes".
%-----------------------------------------------------------------------------%
+ % We could hide these blocks behind macros using the __pragma keyword
+ % introduced in MSVC 9 (2008):
+ %
+ % #define MR_PRAGMA_PACK_PUSH __pragma(pack(push, MR_BYTES_PER_WORD))
+ % #define MR_PRAGMA_PACK_POP __pragma(pack(pop))
+ %
+output_pragma_pack_push(!IO) :-
+ io.write_string("\n#ifdef MR_MSVC\n", !IO),
+ io.write_string("#pragma pack(push, MR_BYTES_PER_WORD)\n", !IO),
+ io.write_string("#endif\n", !IO).
+
+output_pragma_pack_pop(!IO) :-
+ io.write_string("#ifdef MR_MSVC\n", !IO),
+ io.write_string("#pragma pack(pop)\n", !IO),
+ io.write_string("#endif\n", !IO).
+
+%-----------------------------------------------------------------------------%
+
is_valid_c_identifier(S) :-
string.index(S, 0, Start),
char.is_alpha_or_underscore(Start),
diff --git a/compiler/llds_out_global.m b/compiler/llds_out_global.m
index 0807291..cc1b092 100644
--- a/compiler/llds_out_global.m
+++ b/compiler/llds_out_global.m
@@ -416,6 +416,7 @@ output_common_type_defn(TypeNum, CellType, !DeclSet, !IO) :-
( decl_set_is_member(TypeDeclId, !.DeclSet) ->
true
;
+ output_pragma_pack_push(!IO),
io.write_string("struct ", !IO),
output_common_cell_type_name(TypeNum, !IO),
io.write_string(" {\n", !IO),
@@ -427,6 +428,7 @@ output_common_type_defn(TypeNum, CellType, !DeclSet, !IO) :-
output_cons_arg_group_types(ArgGroups, "\t", 1, !IO)
),
io.write_string("};\n", !IO),
+ output_pragma_pack_pop(!IO),
decl_set_insert(TypeDeclId, !DeclSet)
).
@@ -516,7 +518,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..8e1bed0 100644
--- a/compiler/mlds_to_c.m
+++ b/compiler/mlds_to_c.m
@@ -1569,13 +1569,14 @@ mlds_output_scalar_cell_group_decl(Opts, Indent, MangledModuleName,
mlds_output_scalar_cell_group_struct_defn(Opts, Indent, MangledModuleName,
TypeRawNum, ElemTypes, !IO) :-
- mlds_indent(Indent, !IO),
- io.format("\nstruct %s_scalar_cell_group_%d {\n",
+ output_pragma_pack_push(!IO),
+ io.format("struct %s_scalar_cell_group_%d {\n",
[s(MangledModuleName), i(TypeRawNum)], !IO),
list.foldl2(mlds_output_scalar_cell_group_struct_field(Opts, Indent + 1),
ElemTypes, 1, _, !IO),
mlds_indent(Indent, !IO),
- io.write_string("};\n", !IO).
+ io.write_string("};\n", !IO),
+ output_pragma_pack_pop(!IO).
:- pred mlds_output_scalar_cell_group_struct_field(mlds_to_c_opts::in,
indent::in, mlds_type::in, int::in, int::out, io::di, io::uo) is det.
@@ -1583,7 +1584,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_conf.h.in b/runtime/mercury_conf.h.in
index 2707687..1fc14e1 100644
--- a/runtime/mercury_conf.h.in
+++ b/runtime/mercury_conf.h.in
@@ -48,6 +48,11 @@
*/
#undef MR_WORD_TYPE
+/*
+** MR_BYTES_PER_WORD: the number of bytes per MR_WORD_TYPE.
+*/
+#undef MR_BYTES_PER_WORD
+
/*
** MR_INTEGER_LENGTH_MODIFIER: the printf() length modifier for a MR_Integer.
*/
diff --git a/runtime/mercury_float.h b/runtime/mercury_float.h
index 049477f..d600045 100644
--- a/runtime/mercury_float.h
+++ b/runtime/mercury_float.h
@@ -29,6 +29,23 @@
#define MR_FLOAT_WORDS ((sizeof(MR_Float) + sizeof(MR_Word) - 1) \
/ sizeof(MR_Word))
+ /*
+ ** MR_Float_Aligned and #pragma pack are used convince the C compiler to lay
+ ** out structures containing MR_Float members as expected by the Mercury
+ ** compiler, without additional padding or packing.
+ **
+ ** For MSVC, __declspec(align) only increases alignment, e.g. for single
+ ** precision floats on 64-bit platforms. #pragma pack is required to
+ ** reduce packing size, e.g. double precision floats on 32-bit platform.
+ */
+#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_BYTES_PER_WORD))) MR_Float MR_Float_Aligned;
+#else
+ typedef MR_Float MR_Float_Aligned;
+#endif
+
#ifdef MR_BOXED_FLOAT
#define MR_word_to_float(w) (* (MR_Float *) (w))
--------------------------------------------------------------------------
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