diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -1528,12 +1528,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 @@ -1611,9 +1616,33 @@ } } + if (isAIXLayout(Context)) { + if (StorageUnitSize < Context.getTypeSize(Context.UnsignedIntTy)) { + // On AIX, [bool, char, short] bitfields have the same alignment + // as [unsigned]. + StorageUnitSize = Context.getTypeSize(Context.UnsignedIntTy); + } else if (StorageUnitSize > Context.getTypeSize(Context.UnsignedIntTy) && + Context.getTargetInfo().getTriple().isArch32Bit() && + FieldSize <= 32) { + // Under 32-bit compile mode, the bitcontainer is 32 bits if a single + // long long bitfield has length no greater than 32 bits. + StorageUnitSize = 32; + + if (!AlignIsRequired) + FieldAlign = 32; + } + + if (FieldAlign < StorageUnitSize) { + // The bitfield alignment should always be greater than or equal to + // bitcontainer size. + FieldAlign = StorageUnitSize; + } + } + // 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; } diff --git a/clang/test/Layout/aix-bitfield-alignment.c b/clang/test/Layout/aix-bitfield-alignment.c new file mode 100644 --- /dev/null +++ b/clang/test/Layout/aix-bitfield-alignment.c @@ -0,0 +1,234 @@ +// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \ +// RUN: -fsyntax-only -fxl-pragma-pack -x c %s | \ +// RUN: FileCheck --check-prefixes=CHECK,CHECK32 %s +// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \ +// RUN: -fsyntax-only -fxl-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 -fxl-pragma-pack -x c %s | \ +// RUN: FileCheck --check-prefixes=CHECK,CHECK64 %s +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \ +// RUN: -fsyntax-only -fxl-pragma-pack -x c++ %s | \ +// RUN: FileCheck --check-prefixes=CHECK,CHECK64 %s + +struct A { + unsigned char c : 2; +} A; + +int a = sizeof(A); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct A +// CHECK-NEXT: 0:0-1 | unsigned char c +// CHECK-NEXT: sizeof=4, {{(dsize=4, )?}}align=4, preferredalign=4 + +struct B { + char c; + int : 0; +} B; + +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 + +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; +} C; + +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 +// CHECK64: 3:1-8 | unsigned long a7 +// CHECK64: sizeof=8, {{(dsize=8, )?}}align=8, preferredalign=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; +} C1; +#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 + +#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; +} C2; +#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 + +typedef __attribute__((aligned(32))) short mySHORT; +struct D { + char c : 8; + mySHORT : 0; +} D; + +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 + +typedef __attribute__((aligned(32))) long myLONG; +struct D11 { + char c : 8; + myLONG : 0; +} D11; + +int d11 = sizeof(D11); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct D11 +// CHECK-NEXT: 0:0-7 | char c +// CHECK-NEXT: 32:- | myLONG +// CHECK-NEXT: sizeof=32, {{(dsize=32, )?}}align=32, preferredalign=32 + +typedef __attribute__((aligned(2))) long myLONG2; +struct D12 { + char c : 8; + myLONG2 : 0; +} D12; + +int d12 = sizeof(D12); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct D12 +// CHECK-NEXT: 0:0-7 | char c +// CHECK32: 4:- | myLONG2 +// CHECK32: sizeof=4, {{(dsize=4, )?}}align=4, preferredalign=4 +// CHECK64: 8:- | myLONG2 +// CHECK64: sizeof=8, {{(dsize=8, )?}}align=8, preferredalign=8 + +typedef __attribute__((aligned(32))) long long myLONGLONG; +struct D21 { + char c : 8; + myLONGLONG : 0; +} D21; + +int d21 = sizeof(D21); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct D21 +// CHECK-NEXT: 0:0-7 | char c +// CHECK-NEXT: 32:- | myLONGLONG +// CHECK-NEXT: sizeof=32, {{(dsize=32, )?}}align=32, preferredalign=32 + +typedef __attribute__((aligned(2))) long long myLONGLONG2; +struct D22 { + char c : 8; + myLONGLONG2 : 0; +} D22; + +int d22 = sizeof(D22); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct D22 +// CHECK-NEXT: 0:0-7 | char c +// CHECK32: 4:- | myLONGLONG2 +// CHECK32: sizeof=4, {{(dsize=4, )?}}align=4, preferredalign=4 +// CHECK64: 8:- | myLONGLONG2 +// CHECK64: sizeof=8, {{(dsize=8, )?}}align=8, preferredalign=8 + +enum LL : unsigned long long { val = 1 }; + +struct E { + enum LL e : 32; +} E; + +int e = sizeof(E); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct E +// CHECK-NEXT: 0:0-31 | enum LL e +// CHECK32-NEXT: sizeof=4, {{(dsize=4, )?}}align=4, preferredalign=4 +// CHECK64-NEXT: sizeof=8, {{(dsize=8, )?}}align=8, preferredalign=8 + +enum LL1 : unsigned long long { val1 = 1 } __attribute__((aligned(16))); +struct E1 { + enum LL1 e : 32; +} E1; + +int e1 = sizeof(E1); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct E1 +// CHECK-NEXT: 0:0-31 | enum LL1 e +// CHECK-NEXT: sizeof=16, {{(dsize=16, )?}}align=16, preferredalign=16 + +struct F { + long long l : 32 __attribute__((aligned(16))); +} F; + +int f = sizeof(F); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct F +// CHECK-NEXT: 0:0-31 | long long l +// CHECK-NEXT: sizeof=16, {{(dsize=16, )?}}align=16, preferredalign=16 + +struct G { + long long ll : 45; +} G; + +int s = sizeof(G); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct G +// CHECK-NEXT: 0:0-44 | long long ll +// CHECK-NEXT: sizeof=8, {{(dsize=8, )?}}align=8, preferredalign=8 diff --git a/clang/test/Layout/aix-bitfield-alignment.cpp b/clang/test/Layout/aix-bitfield-alignment.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Layout/aix-bitfield-alignment.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \ +// RUN: -fsyntax-only -fxl-pragma-pack -x c++ %s | \ +// RUN: FileCheck --check-prefixes=CHECK %s + +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \ +// RUN: -fsyntax-only -fxl-pragma-pack -x c++ %s | \ +// RUN: FileCheck --check-prefixes=CHECK %s + +struct A { + bool b : 3; +}; + +int a = sizeof(A); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct A +// CHECK-NEXT: 0:0-2 | _Bool b +// CHECK-NEXT: | [sizeof=4, dsize=4, align=4, preferredalign=4, +// CHECK-NEXT: | nvsize=4, nvalign=4, preferrednvalign=4] + +enum class Bool : bool { False = 0, + True = 1 }; + +struct B { + Bool b : 1; +}; + +int b = sizeof(B); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct B +// 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 };