Index: clang/lib/AST/RecordLayoutBuilder.cpp =================================================================== --- clang/lib/AST/RecordLayoutBuilder.cpp +++ clang/lib/AST/RecordLayoutBuilder.cpp @@ -1526,12 +1526,17 @@ UpdateAlignment(TypeAlign); } +static bool isAIXLayout(const ASTContext &Context) { + return Context.getTargetInfo().getTriple().getOS() == llvm::Triple::AIX; +} + void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr(); uint64_t FieldSize = D->getBitWidthValue(Context); TypeInfo FieldInfo = Context.getTypeInfo(D->getType()); uint64_t StorageUnitSize = FieldInfo.Width; unsigned FieldAlign = FieldInfo.Align; + bool AlignIsRequired = FieldInfo.AlignIsRequired; // UnfilledBitsInLastUnit is the difference between the end of the // last allocated bitfield (i.e. the first bit offset available for @@ -1609,9 +1614,49 @@ } } + // On AIX, [bool, char, short] bitfields have the same alignment + // as [unsigned]. + if (isAIXLayout(Context)) { + const BuiltinType *BTy = nullptr; + + // Get the underlying type from EnumDecl. + if (const EnumType *ET = dyn_cast( + D->getType().getDesugaredType(Context).getTypePtr())) { + const EnumDecl *ED = ET->getDecl(); + if (const BuiltinType *BT = + dyn_cast(ED->getPromotionType().getTypePtr())) + BTy = BT; + } else { + BTy = Context.getBaseElementType(D->getType())->getAs(); + } + + if (BTy) { + BuiltinType::Kind BTyKind = BTy->getKind(); + if (BTyKind != BuiltinType::ULong && BTyKind != BuiltinType::Long && + BTyKind != BuiltinType::ULongLong && + BTyKind != BuiltinType::LongLong) { + // Only set bitfields alignment to unsigned when it does + // not have attribute align specified or is less than + // unsigned alignment. + if (FieldAlign < Context.getTypeSize(Context.UnsignedIntTy)) + FieldAlign = Context.getTypeSize(Context.UnsignedIntTy); + StorageUnitSize = Context.getTypeSize(Context.UnsignedIntTy); + } else { + // Handle AIX oversized Long Long bitfield under 32 bit compile mode. + if (StorageUnitSize > 32 && + Context.getTargetInfo().getTriple().isArch32Bit()) { + StorageUnitSize = 32; + if (!AlignIsRequired) + FieldAlign = 32; + } + } + } + } + // If the field is wider than its declared type, it follows - // different rules in all cases. - if (FieldSize > StorageUnitSize) { + // different rules in all cases, except on AIX. + // On AIX, wide bitfield follows the same rules as normal bitfield. + if (FieldSize > StorageUnitSize && !isAIXLayout(Context)) { LayoutWideBitField(FieldSize, StorageUnitSize, FieldPacked, D); return; } Index: clang/test/Layout/aix-bitfield-alignment.cpp =================================================================== --- /dev/null +++ clang/test/Layout/aix-bitfield-alignment.cpp @@ -0,0 +1,217 @@ +// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \ +// RUN: -fsyntax-only -faix-pragma-pack -x c++ %s | \ +// RUN: FileCheck --check-prefixes=CHECK,CHECK32 %s + +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \ +// RUN: -fsyntax-only -faix-pragma-pack -x c++ %s | \ +// RUN: FileCheck --check-prefixes=CHECK,CHECK64 %s + +struct A { + bool b : 3; + unsigned char c : 2; + unsigned short s : 6; +}; + +int a = sizeof(A); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct A +// CHECK-NEXT: 0:0-2 | _Bool b +// CHECK-NEXT: 0:3-4 | unsigned char c +// CHECK-NEXT: 0:5-10 | unsigned short s +// CHECK-NEXT: | [sizeof=4, dsize=4, align=4, preferredalign=4, +// CHECK-NEXT: | nvsize=4, nvalign=4, preferrednvalign=4] + +struct B { + char c; + int : 0; +}; + +int b = sizeof(B); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct B +// CHECK-NEXT: 0 | char c +// CHECK-NEXT: 4:- | int +// CHECK-NEXT: | [sizeof=4, dsize=4, align=4, preferredalign=4, +// CHECK-NEXT: | nvsize=4, nvalign=4, preferrednvalign=4] + +struct C { + signed int a1 : 6; + signed char a2 : 4; + short int a3 : 2; + int a4 : 2; + signed long a5 : 5; + long long int a6 : 6; + unsigned long a7 : 8; +}; + +int c = sizeof(C); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct C +// CHECK-NEXT: 0:0-5 | int a1 +// CHECK-NEXT: 0:6-9 | signed char a2 +// CHECK-NEXT: 1:2-3 | short a3 +// CHECK-NEXT: 1:4-5 | int a4 +// CHECK-NEXT: 1:6-10 | long a5 +// CHECK-NEXT: 2:3-8 | long long a6 +// CHECK32: 4:0-7 | unsigned long a7 +// CHECK32: | [sizeof=8, dsize=8, align=4, preferredalign=4, +// CHECK32: | nvsize=8, nvalign=4, preferrednvalign=4] +// CHECK64: 3:1-8 | unsigned long a7 +// CHECK64: | [sizeof=8, dsize=8, align=8, preferredalign=8, +// CHECK64: | nvsize=8, nvalign=8, preferrednvalign=8] + +#pragma align(packed) +struct C1 { + signed int a1 : 6; + signed char a2 : 4; + short int a3 : 2; + int a4 : 2; + signed long a5 : 5; + long long int a6 : 6; + unsigned long a7 : 8; +}; +#pragma align(reset) + +int c1 = sizeof(C1); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct C1 +// CHECK-NEXT: 0:0-5 | int a1 +// CHECK-NEXT: 0:6-9 | signed char a2 +// CHECK-NEXT: 1:2-3 | short a3 +// CHECK-NEXT: 1:4-5 | int a4 +// CHECK-NEXT: 1:6-10 | long a5 +// CHECK-NEXT: 2:3-8 | long long a6 +// CHECK-NEXT: 3:1-8 | unsigned long a7 +// CHECK-NEXT: | [sizeof=5, dsize=5, align=1, preferredalign=1, +// CHECK-NEXT: | nvsize=5, nvalign=1, preferrednvalign=1] + +#pragma pack(4) +struct C2 { + signed int a1 : 6; + signed char a2 : 4; + short int a3 : 2; + int a4 : 2; + signed long a5 : 5; + long long int a6 : 6; + unsigned long a7 : 8; +}; +#pragma pack(pop) + +int c2 = sizeof(C2); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct C2 +// CHECK-NEXT: 0:0-5 | int a1 +// CHECK-NEXT: 0:6-9 | signed char a2 +// CHECK-NEXT: 1:2-3 | short a3 +// CHECK-NEXT: 1:4-5 | int a4 +// CHECK-NEXT: 1:6-10 | long a5 +// CHECK-NEXT: 2:3-8 | long long a6 +// CHECK-NEXT: 3:1-8 | unsigned long a7 +// CHECK-NEXT: | [sizeof=8, dsize=8, align=4, preferredalign=4, +// CHECK-NEXT: | nvsize=8, nvalign=4, preferrednvalign=4] + +typedef __attribute__((aligned(32))) short mySHORT; +struct D { + char c : 8; + mySHORT : 0; +}; + +int d = sizeof(D); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct D +// CHECK-NEXT: 0:0-7 | char c +// CHECK-NEXT: 32:- | mySHORT +// CHECK-NEXT: | [sizeof=32, dsize=32, align=32, preferredalign=32, +// CHECK-NEXT: | nvsize=32, nvalign=32, preferrednvalign=32] + +typedef __attribute__((aligned(32))) long myLONG; +struct D1 { + char c : 8; + myLONG : 0; +}; + +int d1 = sizeof(D1); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct D1 +// CHECK-NEXT: 0:0-7 | char c +// CHECK-NEXT: 32:- | myLONG +// CHECK-NEXT: | [sizeof=32, dsize=32, align=32, preferredalign=32, +// CHECK-NEXT: | nvsize=32, nvalign=32, preferrednvalign=32] + +typedef __attribute__((aligned(32))) long long myLONGLONG; +struct D2 { + char c : 8; + myLONGLONG : 0; +}; + +int d2 = sizeof(D2); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct D2 +// CHECK-NEXT: 0:0-7 | char c +// CHECK-NEXT: 32:- | myLONGLONG +// CHECK-NEXT: | [sizeof=32, dsize=32, align=32, preferredalign=32, +// CHECK-NEXT: | nvsize=32, nvalign=32, preferrednvalign=32] + +enum class Bool : bool { False = 0, + True = 1 }; + +struct E { + Bool b : 1; +}; + +int e = sizeof(E); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct E +// CHECK-NEXT: 0:0-0 | enum Bool b +// CHECK-NEXT: | [sizeof=4, dsize=4, align=4, preferredalign=4, +// CHECK-NEXT: | nvsize=4, nvalign=4, preferrednvalign=4] + +enum LL : unsigned long long { val = 1 }; + +struct F { + enum LL e : 32; +}; + +int f = sizeof(F); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct F +// CHECK-NEXT: 0:0-31 | enum LL e +// CHECK32-NEXT: | [sizeof=4, dsize=4, align=4, preferredalign=4, +// CHECK32-NEXT: | nvsize=4, nvalign=4, preferrednvalign=4] +// CHECK64-NEXT: | [sizeof=8, dsize=8, align=8, preferredalign=8, +// CHECK64-NEXT: | nvsize=8, nvalign=8, preferrednvalign=8] + +enum LL1 : unsigned long long { val1 = 1 } __attribute__((aligned(16))); +struct F1 { + enum LL1 e : 32; +}; + +int f1 = sizeof(F1); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct F1 +// CHECK-NEXT: 0:0-31 | enum LL1 e +// CHECK-NEXT: | [sizeof=16, dsize=16, align=16, preferredalign=16, +// CHECK-NEXT: | nvsize=16, nvalign=16, preferrednvalign=16] + +struct G { + long long l : 32 __attribute__((aligned(16))); +}; + +int g = sizeof(G); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct G +// CHECK-NEXT: 0:0-31 | long long l +// CHECK-NEXT: | [sizeof=16, dsize=16, align=16, preferredalign=16, +// CHECK-NEXT: | nvsize=16, nvalign=16, preferrednvalign=16]