This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] IA-32 bitfields (take 3)
On Tue, Aug 06, 2002 at 05:26:50PM -0700, Richard Henderson wrote:
> On Tue, Aug 06, 2002 at 06:40:12PM -0400, Jakub Jelinek wrote:
> > As I misused ADJUST_FIELD_ALIGN instead of
> > creating new ADJUST_FIELD_TYPE_ALIGN or something, ADJUST_FIELD_ALIGN
> > will see in this case that DECL_USER_ALIGN is set on the field and bail out,
>
> Perhaps this is fixable by giving ADJUST_FIELD_ALIGN
> the type itself? I.e. where you have
>
> + if (! TYPE_USER_ALIGN (type))
> + type_align = ADJUST_FIELD_ALIGN (field, type_align);
>
> instead have
>
> type_align = ADJUST_FIELD_ALIGN (type, type_align)
Good idea.
This is what I'm bootstrapping ATM.
It will have visible changes on PPC too, particularly with stuff like:
struct A
{
char a;
double b __attribute__((aligned (8)));
char c;
};
but IMHO that's a good thing, user alignment needs to be honored.
2002-08-05 Jakub Jelinek <jakub@redhat.com>
Richard Henderson <rth@redhat.com>
* stor-layout.c (place_union_field): Apply ADJUST_FIELD_ALIGN
to type_align when PCC_BITFIELD_TYPE_MATTERS.
(place_field): Likewise.
* config/i386/i386.c (x86_field_alignment): Don't check
TARGET_ALIGN_DOUBLE for the second time.
If field is a type, use TYPE_USER_ALIGN and the type itself
instead of TREE_TYPE (field).
Apply min for all MODE_INT and MODE_CLASS_INT modes.
* config/rs6000/rs6000.c (rs6000_field_alignment): New.
* config/rs6000/rs6000-protos.h (rs6000_field_alignment): New
prototype.
* config/rs6000/aix.h (ADJUST_FIELD_ALIGN): Use it.
* config/rs6000/darwin.h (ADJUST_FIELD_ALIGN): Likewise.
* config/rs6000/linux64.h (ADJUST_FIELD_ALIGN): Likewise.
* config/rs6000/sysv4.h (ADJUST_FIELD_ALIGN): Handle if field is
a type.
* gcc.dg/i386-bitfield1.c: New test.
* g++.dg/abi/bitfield3.C: New test.
--- gcc/stor-layout.c.jj 2002-04-15 14:42:51.000000000 +0200
+++ gcc/stor-layout.c 2002-08-07 10:11:12.000000000 +0200
@@ -683,10 +683,13 @@ place_union_field (rli, field)
entire union to have `int' alignment. */
if (PCC_BITFIELD_TYPE_MATTERS && DECL_BIT_FIELD_TYPE (field))
{
- rli->record_align = MAX (rli->record_align,
- TYPE_ALIGN (TREE_TYPE (field)));
- rli->unpadded_align = MAX (rli->unpadded_align,
- TYPE_ALIGN (TREE_TYPE (field)));
+ unsigned int type_align = TYPE_ALIGN (TREE_TYPE (field));
+
+#ifdef ADJUST_FIELD_ALIGN
+ type_align = ADJUST_FIELD_ALIGN (TREE_TYPE (field), type_align);
+#endif
+ rli->record_align = MAX (rli->record_align, type_align);
+ rli->unpadded_align = MAX (rli->unpadded_align, type_align);
}
#endif
@@ -827,6 +830,10 @@ place_field (rli, field)
{
unsigned int type_align = TYPE_ALIGN (type);
+#ifdef ADJUST_FIELD_ALIGN
+ type_align = ADJUST_FIELD_ALIGN (type, type_align);
+#endif
+
if (maximum_field_alignment != 0)
type_align = MIN (type_align, maximum_field_alignment);
else if (DECL_PACKED (field))
@@ -915,6 +922,10 @@ place_field (rli, field)
HOST_WIDE_INT offset = tree_low_cst (rli->offset, 0);
HOST_WIDE_INT bit_offset = tree_low_cst (rli->bitpos, 0);
+#ifdef ADJUST_FIELD_ALIGN
+ type_align = ADJUST_FIELD_ALIGN (type, type_align);
+#endif
+
/* A bit field may not span more units of alignment of its type
than its type itself. Advance to next boundary if necessary. */
if ((((offset * BITS_PER_UNIT + bit_offset + field_size +
@@ -944,6 +955,10 @@ place_field (rli, field)
HOST_WIDE_INT offset = tree_low_cst (rli->offset, 0);
HOST_WIDE_INT bit_offset = tree_low_cst (rli->bitpos, 0);
+#ifdef ADJUST_FIELD_ALIGN
+ type_align = ADJUST_FIELD_ALIGN (type, type_align);
+#endif
+
if (maximum_field_alignment != 0)
type_align = MIN (type_align, maximum_field_alignment);
/* ??? This test is opposite the test in the containing if
--- gcc/config/i386/i386.c.jj 2002-07-27 01:31:05.000000000 +0200
+++ gcc/config/i386/i386.c 2002-08-07 10:16:02.000000000 +0200
@@ -12640,14 +12640,27 @@ x86_field_alignment (field, computed)
int computed;
{
enum machine_mode mode;
- if (TARGET_64BIT || DECL_USER_ALIGN (field) || TARGET_ALIGN_DOUBLE)
+ tree type;
+
+ if (TARGET_64BIT || TARGET_ALIGN_DOUBLE)
return computed;
- mode = TYPE_MODE (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
- ? get_inner_array_type (field) : TREE_TYPE (field));
- if ((mode == DFmode || mode == DCmode
- || mode == DImode || mode == CDImode)
- && !TARGET_ALIGN_DOUBLE)
+ if (TYPE_P (field))
+ {
+ type = field;
+ if (TYPE_USER_ALIGN (type))
+ return computed;
+ }
+ else
+ {
+ if (DECL_USER_ALIGN (field))
+ return computed;
+ type = TREE_TYPE (field);
+ }
+ mode = TYPE_MODE (TREE_CODE (type) == ARRAY_TYPE
+ ? get_inner_array_type (type) : type);
+ if (mode == DFmode || mode == DCmode
+ || GET_MODE_CLASS (mode) == MODE_INT
+ || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
return MIN (32, computed);
return computed;
}
-
--- gcc/config/rs6000/rs6000.c.jj 2002-05-25 00:01:52.000000000 +0200
+++ gcc/config/rs6000/rs6000.c 2002-08-07 10:22:06.000000000 +0200
@@ -11534,3 +11534,30 @@ xcoff_asm_named_section (name, flags)
fprintf (asm_out_file, "\t.csect %s\n", name);
}
#endif
+
+int
+rs6000_field_alignment (field, computed)
+ tree field;
+ int computed;
+{
+ enum machine_mode mode;
+ tree type;
+
+ if (TYPE_P (field))
+ {
+ type = field;
+ if (TYPE_USER_ALIGN (type))
+ return computed;
+ }
+ else
+ {
+ if (DECL_USER_ALIGN (field))
+ return computed;
+ type = TREE_TYPE (field);
+ }
+ mode = TYPE_MODE (TREE_CODE (type) == ARRAY_TYPE
+ ? get_inner_array_type (type) : type);
+ if (mode == DFmode)
+ return MIN (32, computed);
+ return computed;
+}
--- gcc/config/rs6000/rs6000-protos.h.jj 2002-02-19 11:13:34.000000000 +0100
+++ gcc/config/rs6000/rs6000-protos.h 2002-08-07 10:22:40.000000000 +0200
@@ -147,6 +147,7 @@ extern void output_mi_thunk PARAMS ((FIL
extern void rs6000_encode_section_info PARAMS ((tree));
extern void rs6000_select_section PARAMS ((tree, int));
extern void rs6000_unique_section PARAMS ((tree, int));
+extern int rs6000_field_alignment PARAMS ((tree, int));
#ifdef ARGS_SIZE_RTX
/* expr.h defines ARGS_SIZE_RTX and `enum direction' */
extern enum direction function_arg_padding PARAMS ((enum machine_mode, tree));
--- gcc/config/rs6000/aix.h.jj 2002-03-18 23:23:52.000000000 +0100
+++ gcc/config/rs6000/aix.h 2002-08-07 10:23:52.000000000 +0200
@@ -105,10 +105,7 @@ Boston, MA 02111-1307, USA. */
/* AIX word-aligns FP doubles but doubleword-aligns 64-bit ints. */
#define ADJUST_FIELD_ALIGN(FIELD, COMPUTED) \
- (TYPE_MODE (TREE_CODE (TREE_TYPE (FIELD)) == ARRAY_TYPE \
- ? get_inner_array_type (FIELD) \
- : TREE_TYPE (FIELD)) == DFmode \
- ? MIN ((COMPUTED), 32) : (COMPUTED))
+ rs6000_field_alignment ((FIELD), (COMPUTED))
/* AIX increases natural record alignment to doubleword if the first
field is an FP double while the FP fields remain word aligned. */
--- gcc/config/rs6000/darwin.h.jj 2002-05-03 19:25:51.000000000 +0200
+++ gcc/config/rs6000/darwin.h 2002-08-07 10:24:47.000000000 +0200
@@ -207,10 +207,7 @@ Boston, MA 02111-1307, USA. */
/* Darwin word-aligns FP doubles but doubleword-aligns 64-bit ints. */
#define ADJUST_FIELD_ALIGN(FIELD, COMPUTED) \
- (TYPE_MODE (TREE_CODE (TREE_TYPE (FIELD)) == ARRAY_TYPE \
- ? get_inner_array_type (FIELD) \
- : TREE_TYPE (FIELD)) == DFmode \
- ? MIN ((COMPUTED), 32) : (COMPUTED))
+ rs6000_field_alignment ((FIELD), (COMPUTED))
/* Darwin increases natural record alignment to doubleword if the first
field is an FP double while the FP fields remain word aligned. */
--- gcc/config/rs6000/linux64.h.jj 2002-06-08 00:40:12.000000000 +0200
+++ gcc/config/rs6000/linux64.h 2002-08-07 10:25:13.000000000 +0200
@@ -66,10 +66,7 @@ Boston, MA 02111-1307, USA. */
/* AIX word-aligns FP doubles but doubleword-aligns 64-bit ints. */
#define ADJUST_FIELD_ALIGN(FIELD, COMPUTED) \
- (TYPE_MODE (TREE_CODE (TREE_TYPE (FIELD)) == ARRAY_TYPE \
- ? get_inner_array_type (FIELD) \
- : TREE_TYPE (FIELD)) == DFmode \
- ? MIN ((COMPUTED), 32) : (COMPUTED))
+ rs6000_field_alignment ((FIELD), (COMPUTED))
/* AIX increases natural record alignment to doubleword if the first
field is an FP double while the FP fields remain word aligned. */
--- gcc/config/rs6000/sysv4.h.jj 2002-04-16 13:07:13.000000000 +0200
+++ gcc/config/rs6000/sysv4.h 2002-08-07 10:30:08.000000000 +0200
@@ -390,7 +390,9 @@ do { \
/* An expression for the alignment of a structure field FIELD if the
alignment computed in the usual way is COMPUTED. */
#define ADJUST_FIELD_ALIGN(FIELD, COMPUTED) \
- ((TARGET_ALTIVEC && TREE_CODE (TREE_TYPE (FIELD)) == VECTOR_TYPE) \
+ ((TARGET_ALTIVEC \
+ && TREE_CODE (TYPE_P (FIELD) ? (FIELD) : TREE_TYPE (FIELD)) \
+ == VECTOR_TYPE) \
? 128 : COMPUTED)
/* Define this macro as an expression for the alignment of a type
--- gcc/testsuite/g++.dg/abi/bitfield3.C.jj 2002-08-05 13:47:02.000000000 +0200
+++ gcc/testsuite/g++.dg/abi/bitfield3.C 2002-08-07 00:21:01.000000000 +0200
@@ -0,0 +1,80 @@
+// Test for oversized bitfield alignment in structs on IA-32
+// { dg-do run { target i?86-*-* } }
+// { dg-options "-O2" }
+
+struct A
+{
+ char a;
+ int b : 224; // { dg-warning "exceeds its type" "" }
+ char c;
+} a, a4[4];
+
+struct B
+{
+ char d;
+ A e;
+ char f;
+} b;
+
+struct C
+{
+ char g;
+ long long h : 64;
+ char i;
+} c, c4[4];
+
+struct D
+{
+ char j;
+ C k;
+ char l;
+} d;
+
+struct E
+{
+ char m;
+ long long n : 160; // { dg-warning "exceeds its type" "" }
+ char o;
+} e, e4[4];
+
+struct F
+{
+ char p;
+ E q;
+ char r;
+} f;
+
+int main (void)
+{
+ if (&a.c - &a.a != 32)
+ return 1;
+ if (sizeof (a) != 36)
+ return 2;
+ if (sizeof (a4) != 4 * 36)
+ return 3;
+ if (sizeof (b) != 2 * 4 + 36)
+ return 4;
+ if (__alignof__ (b.e) != 4)
+ return 5;
+ if (&c.i - &c.g != 12)
+ return 6;
+ if (sizeof (c) != 16)
+ return 7;
+ if (sizeof (c4) != 4 * 16)
+ return 8;
+ if (sizeof (d) != 2 * 4 + 16)
+ return 9;
+ if (__alignof__ (d.k) != 4)
+ return 10;
+ if (&e.o - &e.m != 24)
+ return 11;
+ if (sizeof (e) != 28)
+ return 12;
+ if (sizeof (e4) != 4 * 28)
+ return 13;
+ if (sizeof (f) != 2 * 4 + 28)
+ return 14;
+ if (__alignof__ (f.q) != 4)
+ return 15;
+ return 0;
+}
--- gcc/testsuite/gcc.dg/i386-bitfield1.c.jj 2002-08-07 00:17:59.000000000 +0200
+++ gcc/testsuite/gcc.dg/i386-bitfield1.c 2002-08-07 00:15:48.000000000 +0200
@@ -0,0 +1,53 @@
+// Test for bitfield alignment in structs on IA-32
+// { dg-do run { target i?86-*-* } }
+// { dg-options "-O2" }
+
+extern void abort (void);
+extern void exit (int);
+
+struct A
+{
+ char a;
+ long long b : 61;
+ char c;
+} a, a4[4];
+
+struct B
+{
+ char d;
+ struct A e;
+ char f;
+} b;
+
+struct C
+{
+ char g;
+ union U
+ {
+ char u1;
+ long long u2;
+ long long u3 : 64;
+ } h;
+ char i;
+} c;
+
+int main (void)
+{
+ if (&a.c - &a.a != 12)
+ abort ();
+ if (sizeof (a) != 16)
+ abort ();
+ if (sizeof (a4) != 4 * 16)
+ abort ();
+ if (sizeof (b) != 2 * 4 + 16)
+ abort ();
+ if (__alignof__ (b.e) != 4)
+ abort ();
+ if (&c.i - &c.g != 12)
+ abort ();
+ if (sizeof (c) != 16)
+ abort ();
+ if (__alignof__ (c.h) != 4)
+ abort ();
+ exit (0);
+}
Jakub
- References:
- [PATCH] IA-32 bitfields (was Re: libgcc_s, Linux, and PT_GNU_EH_FRAME, and binutils)
- Re: [PATCH] IA-32 bitfields (was Re: libgcc_s, Linux, andPT_GNU_EH_FRAME, and binutils)
- Re: [PATCH] IA-32 bitfields (was Re: libgcc_s, Linux, and PT_GNU_EH_FRAME, and binutils)
- Re: [PATCH] IA-32 bitfields (was Re: libgcc_s, Linux, and PT_GNU_EH_FRAME, and binutils)