]> granicus.if.org Git - clang/commitdiff
[ARM/AArch64] Enforce alignment for bitfielded structs
authorBradley Smith <bradley.smith@arm.com>
Tue, 28 Apr 2015 11:24:54 +0000 (11:24 +0000)
committerBradley Smith <bradley.smith@arm.com>
Tue, 28 Apr 2015 11:24:54 +0000 (11:24 +0000)
When creating a global variable with a type of a struct with bitfields, we must
forcibly set the alignment of the global from the RecordDecl. We must do this so
that the proper bitfield alignment makes its way down to LLVM, since clang will
mangle the bitfields into one large type.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@235976 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/TargetInfo.h
lib/Basic/TargetInfo.cpp
lib/Basic/Targets.cpp
lib/CodeGen/CodeGenModule.cpp
test/CodeGen/arm-bitfield-alignment.c [new file with mode: 0644]

index 8406205c7fd9ddc4422c3aee0b8c0f35476414ee..cb7570ad4a216b626cc743a3533c5c555903fec2 100644 (file)
@@ -204,6 +204,11 @@ protected:
   /// not for language specific address spaces
   bool UseAddrSpaceMapMangling;
 
+  /// \brief Specify if globals of a struct type containing bitfields should
+  /// have their alignment explicitly specified so as to ensure that LLVM uses
+  /// the correct alignment
+  bool EnforceBitfieldContainerAlignment;
+
 public:
   IntType getSizeType() const { return SizeType; }
   IntType getIntMaxType() const { return IntMaxType; }
@@ -454,6 +459,11 @@ public:
     return HasAlignMac68kSupport;
   }
 
+  /// \brief Check whether the alignment of bitfield struct should be enforced
+  bool enforceBitfieldContainerAlignment() const {
+    return EnforceBitfieldContainerAlignment;
+  }
+
   /// \brief Return the user string for the specified integer type enum.
   ///
   /// For example, SignedShort -> "short".
index 330258b025b5f5c9d11cda6ad45c523378dc4f79..cb6449f9741fb471fbd6dfa5b821fd8c786238da 100644 (file)
@@ -75,6 +75,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
   RegParmMax = 0;
   SSERegParmMax = 0;
   HasAlignMac68kSupport = false;
+  EnforceBitfieldContainerAlignment = false;
 
   // Default to no types using fpret.
   RealTypeUsesObjCFPRet = 0;
index 047cf0d5b5c04686940bfd8c4bb53a2ebb01d200..3d6f4f9594419ae7eb3f270827422de34082b91b 100644 (file)
@@ -3983,6 +3983,9 @@ class ARMTargetInfo : public TargetInfo {
 
     ZeroLengthBitfieldBoundary = 0;
 
+    // Enforce the alignment of bitfield structs
+    EnforceBitfieldContainerAlignment = true;
+
     // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
     // so set preferred for small types to 32.
     if (T.isOSBinFormatMachO()) {
@@ -4825,6 +4828,9 @@ public:
     UseBitFieldTypeAlignment = true;
     UseZeroLengthBitfieldAlignment = true;
 
+    // Enforce the alignment of bitfield structs
+    EnforceBitfieldContainerAlignment = true;
+
     // AArch64 targets default to using the ARM C++ ABI.
     TheCXXABI.set(TargetCXXABI::GenericAArch64);
   }
index c517d17666d3b472c96096d6facc1060c1e0e33e..861a6ee164e8781e9e5a134b339d3a4ac8b4bbe0 100644 (file)
@@ -1799,6 +1799,23 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
         D->getType().isConstant(Context) &&
         isExternallyVisible(D->getLinkageAndVisibility().getLinkage()))
       GV->setSection(".cp.rodata");
+
+    // The ARM/AArch64 ABI expects structs with bitfields to respect the proper
+    // container alignment, hence we have to enfore this in the IR so as to
+    // work around clang combining bitfields into one large type.
+    if (getContext().getTargetInfo().enforceBitfieldContainerAlignment()) {
+      if (const auto *RT = D->getType()->getAs<RecordType>()) {
+        const RecordDecl *RD = RT->getDecl();
+
+        for (auto I = RD->field_begin(), End = RD->field_end(); I != End; ++I) {
+          if ((*I)->isBitField()) {
+            const ASTRecordLayout &Info = getContext().getASTRecordLayout(RD);
+            GV->setAlignment(Info.getAlignment().getQuantity());
+            break;
+          }
+        }
+      }
+    }
   }
 
   if (AddrSpace != Ty->getAddressSpace())
diff --git a/test/CodeGen/arm-bitfield-alignment.c b/test/CodeGen/arm-bitfield-alignment.c
new file mode 100644 (file)
index 0000000..66bbdae
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple arm-none-eabi -ffreestanding -emit-llvm -o - -O3 %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64 -ffreestanding -emit-llvm -o - -O3 %s | FileCheck %s
+
+extern struct T {
+  int b0 : 8;
+  int b1 : 24;
+  int b2 : 1;
+} g;
+
+int func() {
+  return g.b1;
+}
+
+// CHECK: @g = external global %struct.T, align 4
+// CHECK: %{{.*}} = load i64, i64* bitcast (%struct.T* @g to i64*), align 4