[llvm-commits] [dragonegg] r163470 - in /dragonegg/trunk: include/dragonegg/Trees.h src/Convert.cpp src/Trees.cpp test/validator/c/2012-09-08-BitfieldAlignment.c
Duncan Sands
baldrick at free.fr
Sat Sep 8 06:20:55 PDT 2012
Author: baldrick
Date: Sat Sep 8 08:20:54 2012
New Revision: 163470
URL: http://llvm.org/viewvc/llvm-project?rev=163470&view=rev
Log:
Correctly compute the alignment of struct fields, in particular bitfields:
DECL_ALIGN doesn't return the alignment of the octet containing the first
bit of the field, which is what we currently need. This should fix the
gcc-4.7 buildbot, which is crashing due to the use of movaps to store to
a memory location that the front-end wrongly claimed was 16 byte aligned.
Added:
dragonegg/trunk/test/validator/c/2012-09-08-BitfieldAlignment.c
Modified:
dragonegg/trunk/include/dragonegg/Trees.h
dragonegg/trunk/src/Convert.cpp
dragonegg/trunk/src/Trees.cpp
Modified: dragonegg/trunk/include/dragonegg/Trees.h
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/include/dragonegg/Trees.h?rev=163470&r1=163469&r2=163470&view=diff
==============================================================================
--- dragonegg/trunk/include/dragonegg/Trees.h (original)
+++ dragonegg/trunk/include/dragonegg/Trees.h Sat Sep 8 08:20:54 2012
@@ -122,6 +122,10 @@
/// getFieldOffsetInBits - Return the bit offset of a FIELD_DECL in a structure.
uint64_t getFieldOffsetInBits(const_tree field);
+/// getFieldAlignment - Return (in octets) the alignment within a structure of
+/// the octet containing the first bit of the given FIELD_DECL.
+unsigned getFieldAlignment(const_tree field);
+
/// isBitfield - Returns whether to treat the specified field as a bitfield.
bool isBitfield(const_tree field_decl);
Modified: dragonegg/trunk/src/Convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/src/Convert.cpp?rev=163470&r1=163469&r2=163470&view=diff
==============================================================================
--- dragonegg/trunk/src/Convert.cpp (original)
+++ dragonegg/trunk/src/Convert.cpp Sat Sep 8 08:20:54 2012
@@ -2012,8 +2012,8 @@
unsigned DestFieldAlign = DestLoc.getAlignment();
unsigned SrcFieldAlign = SrcLoc.getAlignment();
if (FieldIdx) {
- DestFieldAlign = MinAlign(DestFieldAlign, DECL_ALIGN(Field) / 8);
- SrcFieldAlign = MinAlign(SrcFieldAlign, DECL_ALIGN(Field) / 8);
+ DestFieldAlign = MinAlign(DestFieldAlign, getFieldAlignment(Field));
+ SrcFieldAlign = MinAlign(SrcFieldAlign, getFieldAlignment(Field));
}
// Copy the field.
@@ -2108,7 +2108,7 @@
// Compute the field's alignment.
unsigned FieldAlign = DestLoc.getAlignment();
if (FieldIdx)
- FieldAlign = MinAlign(FieldAlign, DECL_ALIGN(Field) / 8);
+ FieldAlign = MinAlign(FieldAlign, getFieldAlignment(Field));
// Zero the field.
MemRef FieldLoc(FieldPtr, FieldAlign, DestLoc.Volatile);
@@ -6069,6 +6069,7 @@
// BitStart - This is the actual offset of the field from the start of the
// struct, in bits. For bitfields this may be on a non-byte boundary.
+ uint64_t FieldBitOffset = getInt64(DECL_FIELD_BIT_OFFSET(FieldDecl), true);
unsigned BitStart;
Value *FieldPtr;
@@ -6079,8 +6080,7 @@
// Get a pointer to the byte in which the GCC field starts.
FieldPtr = Builder.CreateStructGEP(StructAddrLV.Ptr, MemberIndex);
// Within that byte, the bit at which the GCC field starts.
- BitStart = TREE_INT_CST_LOW(DECL_FIELD_BIT_OFFSET(TREE_OPERAND(exp, 1)));
- BitStart &= 7;
+ BitStart = FieldBitOffset & 7;
} else {
// Offset will hold the field offset in octets.
Value *Offset;
@@ -6105,7 +6105,7 @@
}
// Here BitStart gives the offset of the field in bits from Offset.
- BitStart = getInt64(DECL_FIELD_BIT_OFFSET(FieldDecl), true);
+ BitStart = FieldBitOffset;
// Incorporate as much of it as possible into the pointer computation.
unsigned ByteOffset = BitStart / 8;
@@ -6121,9 +6121,9 @@
FieldPtr = Builder.CreateBitCast(FieldPtr, FieldTy->getPointerTo());
}
- // The alignment is given by DECL_ALIGN. Be conservative and don't assume
- // that the field is properly aligned even if the type is not.
- LVAlign = MinAlign(LVAlign, DECL_ALIGN(FieldDecl) / 8);
+ // Compute the alignment of the octet containing the first bit of the field,
+ // without assuming that the containing struct itself is properly aligned.
+ LVAlign = MinAlign(LVAlign, getFieldAlignment(FieldDecl));
// If the FIELD_DECL has an annotate attribute on it, emit it.
if (lookup_attribute("annotate", DECL_ATTRIBUTES(FieldDecl)))
Modified: dragonegg/trunk/src/Trees.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/src/Trees.cpp?rev=163470&r1=163469&r2=163470&view=diff
==============================================================================
--- dragonegg/trunk/src/Trees.cpp (original)
+++ dragonegg/trunk/src/Trees.cpp Sat Sep 8 08:20:54 2012
@@ -223,6 +223,18 @@
return Result;
}
+/// getFieldAlignment - Return (in octets) the alignment within a structure of
+/// the octet containing the first bit of the given FIELD_DECL.
+unsigned getFieldAlignment(const_tree field) {
+ // DECL_OFFSET_ALIGN is the maximum power-of-two that is known to divide
+ // DECL_FIELD_OFFSET*BITS_PER_UNIT. The field itself is offset a further
+ // DECL_FIELD_BIT_OFFSET bits.
+ assert(DECL_OFFSET_ALIGN(field) > 0 && (DECL_OFFSET_ALIGN(field) & 7) == 0 &&
+ "Field has no or wrong alignment!");
+ uint64_t FieldBitOffset = getInt64(DECL_FIELD_BIT_OFFSET(field), true);
+ return MinAlign(DECL_OFFSET_ALIGN(field) / 8, FieldBitOffset / 8);
+}
+
/// isBitfield - Returns whether to treat the specified field as a bitfield.
bool isBitfield(const_tree field_decl) {
if (!DECL_BIT_FIELD(field_decl))
Added: dragonegg/trunk/test/validator/c/2012-09-08-BitfieldAlignment.c
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/test/validator/c/2012-09-08-BitfieldAlignment.c?rev=163470&view=auto
==============================================================================
--- dragonegg/trunk/test/validator/c/2012-09-08-BitfieldAlignment.c (added)
+++ dragonegg/trunk/test/validator/c/2012-09-08-BitfieldAlignment.c Sat Sep 8 08:20:54 2012
@@ -0,0 +1,41 @@
+// RUN: %dragonegg -S %s -o - | FileCheck %s
+// Check that bitfields are aligned properly.
+
+struct __attribute__ ((__packed__)) __attribute__ ((aligned (4))) Foo {
+ int aligned;
+ unsigned char aligned4_a : 3;
+ unsigned char aligned4_b : 3;
+ unsigned char aligned4_c : 3;
+ unsigned char aligned1_a : 3;
+ unsigned char aligned1_b : 3;
+ unsigned char aligned1_c : 3;
+ unsigned char aligned2 : 3;
+};
+
+extern void baz(struct Foo *);
+
+void bar() {
+ struct Foo foo;
+ foo.aligned4_a = 7;
+// CHECK: load i8* {{.*}}, align 4
+// CHECK: store i8 {{.*}}, align 4
+ foo.aligned4_b = 7;
+// CHECK: load i8* {{.*}}, align 4
+// CHECK: store i8 {{.*}}, align 4
+ foo.aligned4_c = 7;
+// CHECK: load i16* {{.*}}, align 4
+// CHECK: store i16 {{.*}}, align 4
+ foo.aligned1_a = 7;
+// CHECK: load i8* {{.*}}, align 1
+// CHECK: store i8 {{.*}}, align 1
+ foo.aligned1_b = 7;
+// CHECK: load i8* {{.*}}, align 1
+// CHECK: store i8 {{.*}}, align 1
+ foo.aligned1_c = 7;
+// CHECK: load i16* {{.*}}, align 1
+// CHECK: store i16 {{.*}}, align 1
+ foo.aligned2 = 7;
+// CHECK: load i8* {{.*}}, align 2
+// CHECK: store i8 {{.*}}, align 2
+ baz(&foo);
+}
More information about the llvm-commits
mailing list