diff options
| -rw-r--r-- | clang/include/clang/Basic/TargetInfo.h | 10 | ||||
| -rw-r--r-- | clang/lib/Basic/TargetInfo.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Basic/Targets.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 17 | ||||
| -rw-r--r-- | clang/test/CodeGen/arm-bitfield-alignment.c | 15 |
5 files changed, 49 insertions, 0 deletions
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 8406205c7fd..cb7570ad4a2 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -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". diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 330258b025b..cb6449f9741 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -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; diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 047cf0d5b5c..3d6f4f95944 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -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); } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c517d17666d..861a6ee164e 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -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/clang/test/CodeGen/arm-bitfield-alignment.c b/clang/test/CodeGen/arm-bitfield-alignment.c new file mode 100644 index 00000000000..66bbdae57bb --- /dev/null +++ b/clang/test/CodeGen/arm-bitfield-alignment.c @@ -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 |

