Hello Jakub, I can't approve this patch, but I can confirm that changes are sensible. I verified the structure layout - as far as possible - also with MS' compiler, and can confirm the adjustments.
Cheers, Ka 2018-02-28 1:26 GMT+01:00 Jakub Jelinek <ja...@redhat.com>: > Hi! > > The following patch fixes the reported ms_struct/-mms-bitfields structure > layout issues from PR52991. > > There are multiple issues, two of them introduced by the > https://gcc.gnu.org/ml/gcc-patches/2006-04/msg01064.html -mms-bitfields > revamp from Eric and follow-up fix r114552, the rest has been introduced > later when the known_align < desired_align case has been enabled for the ms > bitfield layout. > > The first 2 hunks fix alignment of packed non-bitfield fields, we can't > ignore all the alignment updates for them, just should use only > desired_align which takes DECL_PACKED into account, rather than > MAX (type_align, desired_align). Similarly, the last hunk in stor-layout.c > makes sure that for DECL_PACKED fields we use BITS_PER_UNIT alignment rather > than the type alignment. > > The rest attempts to unbreak r184409 which enabled known_align < desired_align > case; doing that if rli->prev_field and ms layout is wrong, we first need to > deal with the bitfield packing and if we are within a bitfield word, we > shouldn't do any realignment, only in between them. > > The patch reverts changes to bf-ms-layout{,-2}.c tests done in 2012, which > were done just to match the r184409 changes, and adds 2 new tests. All of > these 4 I've tested (slightly tweaked, so that it compiles with VC) with > the online VC compiler http://rextester.com/l/c_online_compiler_visual . > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2018-02-27 Jakub Jelinek <ja...@redhat.com> > > PR target/52991 > * stor-layout.c (update_alignment_for_field): For > targetm.ms_bitfield_layout_p (rli->t), if !is_bitfield > && !DECL_PACKED (field), do the alignment update, just use > only desired_align instead of MAX (type_align, desired_align) > as the alignment. > (place_field): Don't do known_align < desired_align handling > early if targetm.ms_bitfield_layout_p (rli->t) and rli->prev_field > is non-NULL, instead do it after rli->prev_field handling and > only if not within a bitfield word. For DECL_PACKED (field) > use type_align of BITS_PER_UNIT. > > * gcc.dg/bf-ms-layout.c: Revert 2012-04-26 changes. > * gcc.dg/bf-ms-layout-2.c: Revert 2012-02-23 changes. > * gcc.dg/bf-ms-layout-4.c: New test. > * gcc.dg/bf-ms-layout-5.c: New test. > > --- gcc/stor-layout.c.jj 2018-02-22 14:35:33.135216198 +0100 > +++ gcc/stor-layout.c 2018-02-27 18:56:26.906494801 +0100 > @@ -1038,7 +1038,7 @@ update_alignment_for_field (record_layou > the type, except that for zero-size bitfields this only > applies if there was an immediately prior, nonzero-size > bitfield. (That's the way it is, experimentally.) */ > - if ((!is_bitfield && !DECL_PACKED (field)) > + if (!is_bitfield > || ((DECL_SIZE (field) == NULL_TREE > || !integer_zerop (DECL_SIZE (field))) > ? !DECL_PACKED (field) > @@ -1047,7 +1047,10 @@ update_alignment_for_field (record_layou > && ! integer_zerop (DECL_SIZE (rli->prev_field))))) > { > unsigned int type_align = TYPE_ALIGN (type); > - type_align = MAX (type_align, desired_align); > + if (!is_bitfield && DECL_PACKED (field)) > + type_align = desired_align; > + else > + type_align = MAX (type_align, desired_align); > if (maximum_field_alignment != 0) > type_align = MIN (type_align, maximum_field_alignment); > rli->record_align = MAX (rli->record_align, type_align); > @@ -1303,7 +1306,9 @@ place_field (record_layout_info rli, tre > > /* Does this field automatically have alignment it needs by virtue > of the fields that precede it and the record's own alignment? */ > - if (known_align < desired_align) > + if (known_align < desired_align > + && (! targetm.ms_bitfield_layout_p (rli->t) > + || rli->prev_field == NULL)) > { > /* No, we need to skip space before this field. > Bump the cumulative size to multiple of field alignment. */ > @@ -1331,8 +1336,6 @@ place_field (record_layout_info rli, tre > > if (! TREE_CONSTANT (rli->offset)) > rli->offset_align = desired_align; > - if (targetm.ms_bitfield_layout_p (rli->t)) > - rli->prev_field = NULL; > } > > /* Handle compatibility with PCC. Note that if the record has any > @@ -1448,6 +1451,8 @@ place_field (record_layout_info rli, tre > /* This is a bitfield if it exists. */ > if (rli->prev_field) > { > + bool realign_p = known_align < desired_align; > + > /* If both are bitfields, nonzero, and the same size, this is > the middle of a run. Zero declared size fields are special > and handled as "end of run". (Note: it's nonzero declared > @@ -1481,7 +1486,10 @@ place_field (record_layout_info rli, tre > rli->remaining_in_alignment = typesize - bitsize; > } > else > - rli->remaining_in_alignment -= bitsize; > + { > + rli->remaining_in_alignment -= bitsize; > + realign_p = false; > + } > } > else > { > @@ -1512,6 +1520,31 @@ place_field (record_layout_info rli, tre > rli->prev_field = NULL; > } > > + /* Does this field automatically have alignment it needs by virtue > + of the fields that precede it and the record's own alignment? */ > + if (realign_p) > + { > + /* If the alignment is still within offset_align, just align > + the bit position. */ > + if (desired_align < rli->offset_align) > + rli->bitpos = round_up (rli->bitpos, desired_align); > + else > + { > + /* First adjust OFFSET by the partial bits, then align. */ > + tree d = size_binop (CEIL_DIV_EXPR, rli->bitpos, > + bitsize_unit_node); > + rli->offset = size_binop (PLUS_EXPR, rli->offset, > + fold_convert (sizetype, d)); > + rli->bitpos = bitsize_zero_node; > + > + rli->offset = round_up (rli->offset, > + desired_align / BITS_PER_UNIT); > + } > + > + if (! TREE_CONSTANT (rli->offset)) > + rli->offset_align = desired_align; > + } > + > normalize_rli (rli); > } > > @@ -1530,7 +1563,7 @@ place_field (record_layout_info rli, tre > if (!DECL_BIT_FIELD_TYPE (field) > || (prev_saved != NULL > ? !simple_cst_equal (TYPE_SIZE (type), TYPE_SIZE (prev_type)) > - : !integer_zerop (DECL_SIZE (field)) )) > + : !integer_zerop (DECL_SIZE (field)))) > { > /* Never smaller than a byte for compatibility. */ > unsigned int type_align = BITS_PER_UNIT; > @@ -1555,7 +1588,8 @@ place_field (record_layout_info rli, tre > } > > /* Now align (conventionally) for the new type. */ > - type_align = TYPE_ALIGN (TREE_TYPE (field)); > + if (! DECL_PACKED (field)) > + type_align = TYPE_ALIGN (TREE_TYPE (field)); > > if (maximum_field_alignment != 0) > type_align = MIN (type_align, maximum_field_alignment); > --- gcc/testsuite/gcc.dg/bf-ms-layout.c.jj 2017-06-20 21:38:01.634906200 > +0200 > +++ gcc/testsuite/gcc.dg/bf-ms-layout.c 2018-02-27 18:04:06.923851839 +0100 > @@ -153,27 +153,27 @@ int main(){ > struct ten test_ten; > > #if defined (_TEST_MS_LAYOUT) || defined (_MSC_VER) > - size_t exp_sizeof_one = 8; > - size_t exp_sizeof_two = 12; > + size_t exp_sizeof_one = 12; > + size_t exp_sizeof_two = 16; > size_t exp_sizeof_three =6; > size_t exp_sizeof_four = 8; > size_t exp_sizeof_five = 3; > size_t exp_sizeof_six = 8; > size_t exp_sizeof_seven = 3; > - size_t exp_sizeof_eight = 2; > + size_t exp_sizeof_eight = 4; > size_t exp_sizeof_nine = 8; > - size_t exp_sizeof_ten = 8; > + size_t exp_sizeof_ten = 16; > > - unsigned char exp_one_c = 7; > - unsigned char exp_two_c = 9; > + unsigned char exp_one_c = 8; > + unsigned char exp_two_c = 12; > unsigned char exp_three_c = 4; > unsigned char exp_four_c = 4; > char exp_five_c = 2; > char exp_six_c = 5; > char exp_seven_c = 2; > - char exp_eight_c = 1; > + char exp_eight_c = 2; > char exp_nine_c = 0; > - char exp_ten_c = 1; > + char exp_ten_c = 8; > > #else /* testing -mno-ms-bitfields */ > > --- gcc/testsuite/gcc.dg/bf-ms-layout-2.c.jj 2017-06-20 21:38:02.112900704 > +0200 > +++ gcc/testsuite/gcc.dg/bf-ms-layout-2.c 2018-02-27 18:04:06.923851839 > +0100 > @@ -158,27 +158,27 @@ int main(){ > struct ten test_ten; > > #if defined (_TEST_MS_LAYOUT) || defined (_MSC_VER) > - size_t exp_sizeof_one = 8; > - size_t exp_sizeof_two = 12; > + size_t exp_sizeof_one = 12; > + size_t exp_sizeof_two = 16; > size_t exp_sizeof_three =6; > size_t exp_sizeof_four = 8; > size_t exp_sizeof_five = 3; > size_t exp_sizeof_six = 8; > size_t exp_sizeof_seven = 3; > - size_t exp_sizeof_eight = 2; > + size_t exp_sizeof_eight = 4; > size_t exp_sizeof_nine = 8; > - size_t exp_sizeof_ten = 8; > + size_t exp_sizeof_ten = 16; > > - unsigned char exp_one_c = 7; > - unsigned char exp_two_c = 9; > + unsigned char exp_one_c = 8; > + unsigned char exp_two_c = 12; > unsigned char exp_three_c = 4; > unsigned char exp_four_c = 4; > char exp_five_c = 2; > char exp_six_c = 5; > char exp_seven_c = 2; > - char exp_eight_c = 1; > + char exp_eight_c = 2; > char exp_nine_c = 0; > - char exp_ten_c = 1; > + char exp_ten_c = 8; > > #else /* testing -mno-ms-bitfields */ > > --- gcc/testsuite/gcc.dg/bf-ms-layout-4.c.jj 2018-02-27 18:09:09.544421580 > +0100 > +++ gcc/testsuite/gcc.dg/bf-ms-layout-4.c 2018-02-27 18:18:00.845039925 > +0100 > @@ -0,0 +1,43 @@ > +/* PR target/52991 */ > +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ > + > +#define CHECK(expr) extern char c[(expr) ? 1 : -1] > +#define offsetof(x, y) __builtin_offsetof (x, y) > + > +struct test_sp1 { > + int a; > + short b; > + int c; > + char d; > +} __attribute__((packed,ms_struct)); > + > +CHECK (sizeof (struct test_sp1) == 11); > +CHECK (offsetof (struct test_sp1, a) == 0); > +CHECK (offsetof (struct test_sp1, b) == 4); > +CHECK (offsetof (struct test_sp1, c) == 6); > +CHECK (offsetof (struct test_sp1, d) == 10); > + > +struct test_sp3 { > + int a; > + short b __attribute__((aligned(8))); > + int c; > + char d; > +} __attribute__((packed,ms_struct)); > + > +CHECK (sizeof (struct test_sp3) == 16); > +CHECK (offsetof (struct test_sp3, a) == 0); > +CHECK (offsetof (struct test_sp3, b) == 8); > +CHECK (offsetof (struct test_sp3, c) == 10); > +CHECK (offsetof (struct test_sp3, d) == 14); > + > +struct test_s4 { > + int a; > + short b; > + int c:15; > + char d; > +} __attribute__((ms_struct)); > + > +CHECK (sizeof (struct test_s4) == 16); > +CHECK (offsetof (struct test_s4, a) == 0); > +CHECK (offsetof (struct test_s4, b) == 4); > +CHECK (offsetof (struct test_s4, d) == 12); > --- gcc/testsuite/gcc.dg/bf-ms-layout-5.c.jj 2018-02-27 18:31:24.043753173 > +0100 > +++ gcc/testsuite/gcc.dg/bf-ms-layout-5.c 2018-02-27 18:35:29.825676223 > +0100 > @@ -0,0 +1,45 @@ > +/* PR target/52991 */ > +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ > + > +struct S { > + int a : 2; > + __attribute__((aligned (8))) int b : 2; > + int c : 28; > + __attribute__((aligned (16))) int d : 2; > + int e : 30; > +} __attribute__((ms_struct)); > + > +struct S s; > + > +int > +main () > +{ > + int i; > + if (sizeof (s) != 32) > + __builtin_abort (); > + s.a = -1; > + for (i = 0; i < 32; ++i) > + if (((char *) &s)[i] != (i ? 0 : 3)) > + __builtin_abort (); > + s.a = 0; > + s.b = -1; > + for (i = 0; i < 32; ++i) > + if (((char *) &s)[i] != (i ? 0 : 12)) > + __builtin_abort (); > + s.b = 0; > + s.c = -1; > + for (i = 0; i < 32; ++i) > + if (((signed char *) &s)[i] != (i > 3 ? 0 : (i ? -1 : -16))) > + __builtin_abort (); > + s.c = 0; > + s.d = -1; > + for (i = 0; i < 32; ++i) > + if (((signed char *) &s)[i] != (i == 16 ? 3 : 0)) > + __builtin_abort (); > + s.d = 0; > + s.e = -1; > + for (i = 0; i < 32; ++i) > + if (((signed char *) &s)[i] != ((i < 16 || i > 19) ? 0 : (i == 16 ? -4 : > -1))) > + __builtin_abort (); > + return 0; > +} > > Jakub