Xiangling_L updated this revision to Diff 269396.
Xiangling_L marked 2 inline comments as done.
Xiangling_L added a comment.
Simplify the code;
Add one more testcase related to [[no_unique_addr]];
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D79719/new/
https://reviews.llvm.org/D79719
Files:
clang/include/clang/AST/RecordLayout.h
clang/include/clang/Basic/TargetInfo.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/RecordLayout.cpp
clang/lib/AST/RecordLayoutBuilder.cpp
clang/lib/Basic/Targets/OSTargets.h
clang/lib/Basic/Targets/PPC.h
clang/test/Layout/aix-double-struct-member.cpp
clang/test/Layout/aix-no-unique-address-with-double.cpp
clang/test/Layout/aix-virtual-function-and-base-with-double.cpp
Index: clang/test/Layout/aix-virtual-function-and-base-with-double.cpp
===================================================================
--- /dev/null
+++ clang/test/Layout/aix-virtual-function-and-base-with-double.cpp
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK32 %s
+
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | \
+// RUN: FileCheck --check-prefixes=CHECK,CHECK64 %s
+
+namespace test1 {
+struct A {
+ double d1;
+ virtual void boo() {}
+};
+
+struct B {
+ double d2;
+ A a;
+};
+
+struct C : public A {
+ double d3;
+};
+
+int i = sizeof(B);
+int j = sizeof(C);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test1::A
+// CHECK-NEXT: 0 | (A vtable pointer)
+// CHECK32-NEXT: 4 | double d1
+// CHECK32-NEXT: | [sizeof=12, dsize=12, align=4, preferredalign=4,
+// CHECK32-NEXT: | nvsize=12, nvalign=4, preferrednvalign=4]
+// CHECK64-NEXT: 8 | double d1
+// CHECK64-NEXT: | [sizeof=16, dsize=16, align=8, preferredalign=8,
+// CHECK64-NEXT: | nvsize=16, nvalign=8, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test1::B
+// CHECK-NEXT: 0 | double d2
+// CHECK-NEXT: 8 | struct test1::A a
+// CHECK-NEXT: 8 | (A vtable pointer)
+// CHECK32-NEXT: 12 | double d1
+// CHECK32-NEXT: | [sizeof=24, dsize=20, align=4, preferredalign=8,
+// CHECK32-NEXT: | nvsize=20, nvalign=4, preferrednvalign=8]
+// CHECK64-NEXT: 16 | double d1
+// CHECK64-NEXT: | [sizeof=24, dsize=24, align=8, preferredalign=8,
+// CHECK64-NEXT: | nvsize=24, nvalign=8, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test1::C
+// CHECK-NEXT: 0 | struct test1::A (primary base)
+// CHECK-NEXT: 0 | (A vtable pointer)
+// CHECK32-NEXT: 4 | double d1
+// CHECK32-NEXT: 12 | double d3
+// CHECK32-NEXT: | [sizeof=20, dsize=20, align=4, preferredalign=4,
+// CHECK32-NEXT: | nvsize=20, nvalign=4, preferrednvalign=4]
+// CHECK64-NEXT: 8 | double d1
+// CHECK64-NEXT: 16 | double d3
+// CHECK64-NEXT: | [sizeof=24, dsize=24, align=8, preferredalign=8,
+// CHECK64-NEXT: | nvsize=24, nvalign=8, preferrednvalign=8]
+
+}; // namespace test1
+
+namespace test2 {
+struct A {
+ long long l1;
+};
+
+struct B : public virtual A {
+ double d2;
+};
+
+#pragma pack(2)
+struct C : public virtual A {
+ double __attribute__((aligned(4))) d3;
+};
+
+int i = sizeof(B);
+int j = sizeof(C);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test2::A
+// CHECK-NEXT: 0 | long long l1
+// CHECK-NEXT: | [sizeof=8, dsize=8, align=8, preferredalign=8,
+// CHECK-NEXT: | nvsize=8, nvalign=8, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test2::B
+// CHECK-NEXT: 0 | (B vtable pointer)
+// CHECK32-NEXT: 4 | double d2
+// CHECK64-NEXT: 8 | double d2
+// CHECK-NEXT: 16 | struct test2::A (virtual base)
+// CHECK-NEXT: 16 | long long l1
+// CHECK-NEXT: | [sizeof=24, dsize=24, align=8, preferredalign=8,
+// CHECK32-NEXT: | nvsize=12, nvalign=4, preferrednvalign=4]
+// CHECK64-NEXT: | nvsize=16, nvalign=8, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test2::C
+// CHECK-NEXT: 0 | (C vtable pointer)
+// CHECK32-NEXT: 4 | double d3
+// CHECK32-NEXT: 12 | struct test2::A (virtual base)
+// CHECK32-NEXT: 12 | long long l1
+// CHECK32-NEXT: | [sizeof=20, dsize=20, align=2, preferredalign=2,
+// CHECK32-NEXT: | nvsize=12, nvalign=2, preferrednvalign=2]
+// CHECK64-NEXT: 8 | double d3
+// CHECK64-NEXT: 16 | struct test2::A (virtual base)
+// CHECK64-NEXT: 16 | long long l1
+// CHECK64-NEXT: | [sizeof=24, dsize=24, align=2, preferredalign=2,
+// CHECK64-NEXT: | nvsize=16, nvalign=2, preferrednvalign=2]
+
+}; // namespace test2
Index: clang/test/Layout/aix-no-unique-address-with-double.cpp
===================================================================
--- /dev/null
+++ clang/test/Layout/aix-no-unique-address-with-double.cpp
@@ -0,0 +1,144 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | \
+// RUN: FileCheck %s
+
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | \
+// RUN: FileCheck %s
+
+struct Empty {};
+
+struct A {
+ double d;
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct Empty (empty)
+// CHECK-NEXT: | [sizeof=1, dsize=1, align=1, preferredalign=1,
+// CHECK-NEXT: | nvsize=1, nvalign=1, preferrednvalign=1]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct A
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=8, nvalign=4, preferrednvalign=8]
+
+struct B {
+ ~B();
+
+ Empty emp;
+ A a;
+ char c;
+};
+
+struct B1 {
+ [[no_unique_address]] B b;
+ char ext[7];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct B
+// CHECK-NEXT: 0 | struct Empty emp (empty)
+// CHECK-NEXT: 4 | struct A a
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: 12 | char c
+// CHECK-NEXT: | [sizeof=16, dsize=13, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=13, nvalign=4, preferrednvalign=4]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct B1
+// CHECK-NEXT: 0 | struct B b
+// CHECK-NEXT: 0 | struct Empty emp (empty)
+// CHECK-NEXT: 4 | struct A a
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: 12 | char c
+// CHECK-NEXT: 13 | char [7] ext
+// CHECK-NEXT: | [sizeof=20, dsize=20, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=20, nvalign=4, preferrednvalign=4]
+
+struct C {
+ ~C();
+
+ [[no_unique_address]] Empty emp;
+ A a;
+ char c;
+};
+
+struct C1 {
+ [[no_unique_address]] C c;
+ char ext[7];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct C
+// CHECK-NEXT: 0 | struct Empty emp (empty)
+// CHECK-NEXT: 0 | struct A a
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: 8 | char c
+// CHECK-NEXT: | [sizeof=16, dsize=9, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=9, nvalign=4, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct C1
+// CHECK-NEXT: 0 | struct C c
+// CHECK-NEXT: 0 | struct Empty emp (empty)
+// CHECK-NEXT: 0 | struct A a
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: 8 | char c
+// CHECK-NEXT: 9 | char [7] ext
+// CHECK-NEXT: | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=16, nvalign=4, preferrednvalign=8]
+
+struct D {
+ ~D();
+
+ [[no_unique_address]] char notEmp;
+ A a;
+ char c;
+};
+
+struct D1 {
+ [[no_unique_address]] D d;
+ char ext[7];
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct D
+// CHECK-NEXT: 0 | char notEmp
+// CHECK-NEXT: 4 | struct A a
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: 12 | char c
+// CHECK-NEXT: | [sizeof=16, dsize=13, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=13, nvalign=4, preferrednvalign=4]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct D1
+// CHECK-NEXT: 0 | struct D d
+// CHECK-NEXT: 0 | char notEmp
+// CHECK-NEXT: 4 | struct A a
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: 12 | char c
+// CHECK-NEXT: 13 | char [7] ext
+// CHECK-NEXT: | [sizeof=20, dsize=20, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=20, nvalign=4, preferrednvalign=4]
+
+struct E {
+ [[no_unique_address]] Empty emp;
+ int : 0;
+ double d;
+};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct E
+// CHECK-NEXT: 0 | struct Empty emp (empty)
+// CHECK-NEXT: 0:- | int
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: | [sizeof=8, dsize=8, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=8, nvalign=4, preferrednvalign=4]
+
+int a = sizeof(Empty);
+int b = sizeof(A);
+int c = sizeof(B1);
+int d = sizeof(C1);
+int e = sizeof(D1);
+int f = sizeof(E);
Index: clang/test/Layout/aix-double-struct-member.cpp
===================================================================
--- /dev/null
+++ clang/test/Layout/aix-double-struct-member.cpp
@@ -0,0 +1,298 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | \
+// RUN: FileCheck %s
+
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | \
+// RUN: FileCheck %s
+
+namespace test1 {
+// Test double alignment when it is/is not the first struct member.
+struct D {
+ double d1;
+ int i1;
+};
+
+struct DoubleFirst {
+ struct D d2;
+ int i2;
+};
+
+struct IntFirst {
+ int i3;
+ struct D d3;
+};
+
+int a = sizeof(DoubleFirst);
+int b = sizeof(IntFirst);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test1::D
+// CHECK-NEXT: 0 | double d1
+// CHECK-NEXT: 8 | int i1
+// CHECK-NEXT: | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=16, nvalign=4, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test1::DoubleFirst
+// CHECK-NEXT: 0 | struct test1::D d2
+// CHECK-NEXT: 0 | double d1
+// CHECK-NEXT: 8 | int i1
+// CHECK-NEXT: 16 | int i2
+// CHECK-NEXT: | [sizeof=24, dsize=24, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=24, nvalign=4, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test1::IntFirst
+// CHECK-NEXT: 0 | int i3
+// CHECK-NEXT: 4 | struct test1::D d3
+// CHECK-NEXT: 4 | double d1
+// CHECK-NEXT: 12 | int i1
+// CHECK-NEXT: | [sizeof=20, dsize=20, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=20, nvalign=4, preferrednvalign=4]
+}; // namespace test1
+
+namespace test2 {
+// Test AIX layout for zero sized bitfield followed by double.
+struct Double {
+ int : 0;
+ double d;
+};
+
+int a = sizeof(Double);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test2::Double
+// CHECK-NEXT: 0:- | int
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: | [sizeof=8, dsize=8, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=8, nvalign=4, preferrednvalign=4]
+}; // namespace test2
+
+namespace test3 {
+// Test the alignment of a double member in union.
+union A {
+ int b;
+ double d;
+};
+
+struct UnionStruct {
+ union A a;
+ int i;
+};
+
+int a = sizeof(UnionStruct);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | union test3::A
+// CHECK-NEXT: 0 | int b
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=8, nvalign=4, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test3::UnionStruct
+// CHECK-NEXT: 0 | union test3::A a
+// CHECK-NEXT: 0 | int b
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: 8 | int i
+// CHECK-NEXT: | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=16, nvalign=4, preferrednvalign=8]
+
+}; // namespace test3
+
+namespace test4 {
+// Test the AIX Alignment rule when layout base class.
+struct A {
+ int a;
+};
+
+struct B {
+ double d;
+};
+
+class S : A, B {
+};
+
+int a = sizeof(S);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test4::A
+// CHECK-NEXT: 0 | int a
+// CHECK-NEXT: | [sizeof=4, dsize=4, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=4, nvalign=4, preferrednvalign=4]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test4::B
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=8, nvalign=4, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | class test4::S
+// CHECK-NEXT: 0 | struct test4::A (base)
+// CHECK-NEXT: 0 | int a
+// CHECK-NEXT: 4 | struct test4::B (base)
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: | [sizeof=12, dsize=12, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=12, nvalign=4, preferrednvalign=4]
+}; // namespace test4
+
+namespace test5 {
+// Test the AIX alignment rule with basic inheritance.
+struct Empty {
+};
+
+struct EmptyDer : Empty {
+ double d;
+};
+
+struct NonEmpty {
+ int i;
+};
+
+struct NonEmptyDer : NonEmpty {
+ double d;
+};
+
+int a = sizeof(EmptyDer);
+int b = sizeof(NonEmptyDer);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test5::Empty (empty)
+// CHECK-NEXT: | [sizeof=1, dsize=1, align=1, preferredalign=1,
+// CHECK-NEXT: | nvsize=1, nvalign=1, preferrednvalign=1]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test5::EmptyDer
+// CHECK-NEXT: 0 | struct test5::Empty (base) (empty)
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=8, nvalign=4, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test5::NonEmpty
+// CHECK-NEXT: 0 | int i
+// CHECK-NEXT: | [sizeof=4, dsize=4, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=4, nvalign=4, preferrednvalign=4]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test5::NonEmptyDer
+// CHECK-NEXT: 0 | struct test5::NonEmpty (base)
+// CHECK-NEXT: 0 | int i
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: | [sizeof=12, dsize=12, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=12, nvalign=4, preferrednvalign=4]
+}; // namespace test5
+
+namespace test6 {
+// Test how #pragma pack and align attribute interacts with AIX alignment.
+struct A {
+ char a;
+ double __attribute__((aligned(16))) d;
+ int i;
+};
+
+struct B {
+ double __attribute__((aligned(4))) d1;
+ char a;
+ double d2;
+};
+
+#pragma pack(2)
+struct C {
+ int i;
+ short j;
+ double k;
+};
+
+#pragma pack(2)
+struct D {
+ double d;
+ short j;
+ int i;
+};
+
+#pragma pack(8)
+struct E {
+ double __attribute__((aligned(4))) d;
+ short s;
+};
+
+#pragma pack(4)
+struct F : public D {
+ double d;
+};
+
+#pragma pack(2)
+struct G : public E {
+ int i;
+};
+
+int a = sizeof(A);
+int b = sizeof(B);
+int c = sizeof(C);
+int d = sizeof(D);
+int e = sizeof(E);
+int f = sizeof(F);
+int g = sizeof(G);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test6::A
+// CHECK-NEXT: 0 | char a
+// CHECK-NEXT: 16 | double d
+// CHECK-NEXT: 24 | int i
+// CHECK-NEXT: | [sizeof=32, dsize=32, align=16, preferredalign=16,
+// CHECK-NEXT: | nvsize=32, nvalign=16, preferrednvalign=16]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test6::B
+// CHECK-NEXT: 0 | double d1
+// CHECK-NEXT: 8 | char a
+// CHECK-NEXT: 12 | double d2
+// CHECK-NEXT: | [sizeof=24, dsize=24, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=24, nvalign=4, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test6::C
+// CHECK-NEXT: 0 | int i
+// CHECK-NEXT: 4 | short j
+// CHECK-NEXT: 6 | double k
+// CHECK-NEXT: | [sizeof=14, dsize=14, align=2, preferredalign=2,
+// CHECK-NEXT: | nvsize=14, nvalign=2, preferrednvalign=2]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test6::D
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: 8 | short j
+// CHECK-NEXT: 10 | int i
+// CHECK-NEXT: | [sizeof=14, dsize=14, align=2, preferredalign=2,
+// CHECK-NEXT: | nvsize=14, nvalign=2, preferrednvalign=2]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test6::E
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: 8 | short s
+// CHECK-NEXT: | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=16, nvalign=4, preferrednvalign=8]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test6::F
+// CHECK-NEXT: 0 | struct test6::D (base)
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: 8 | short j
+// CHECK-NEXT: 10 | int i
+// CHECK-NEXT: 16 | double d
+// CHECK-NEXT: | [sizeof=24, dsize=24, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=24, nvalign=4, preferrednvalign=4]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test6::G
+// CHECK-NEXT: 0 | struct test6::E (base)
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: 8 | short s
+// CHECK-NEXT: 16 | int i
+// CHECK-NEXT: | [sizeof=20, dsize=20, align=2, preferredalign=2,
+// CHECK-NEXT: | nvsize=20, nvalign=2, preferrednvalign=2]
+
+}; // namespace test6
Index: clang/lib/Basic/Targets/PPC.h
===================================================================
--- clang/lib/Basic/Targets/PPC.h
+++ clang/lib/Basic/Targets/PPC.h
@@ -368,11 +368,17 @@
}
if (Triple.isOSFreeBSD() || Triple.isOSNetBSD() || Triple.isOSOpenBSD() ||
- Triple.getOS() == llvm::Triple::AIX || Triple.isMusl()) {
+ Triple.isMusl()) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble();
}
+ if (Triple.isOSAIX()) {
+ LongDoubleWidth = 64;
+ LongDoubleAlign = DoubleAlign = 32;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ }
+
// PPC32 supports atomics up to 4 bytes.
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
}
@@ -404,12 +410,17 @@
if (Triple.getOS() == llvm::Triple::AIX)
SuitableAlign = 64;
- if (Triple.isOSFreeBSD() || Triple.getOS() == llvm::Triple::AIX ||
- Triple.isMusl()) {
+ if (Triple.isOSFreeBSD() || Triple.isMusl()) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble();
}
+ if (Triple.isOSAIX()) {
+ LongDoubleWidth = 64;
+ LongDoubleAlign = DoubleAlign = 32;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ }
+
// PPC64 supports atomics up to 8 bytes.
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
Index: clang/lib/Basic/Targets/OSTargets.h
===================================================================
--- clang/lib/Basic/Targets/OSTargets.h
+++ clang/lib/Basic/Targets/OSTargets.h
@@ -719,6 +719,8 @@
// AIX sets FLT_EVAL_METHOD to be 1.
unsigned getFloatEvalMethod() const override { return 1; }
bool hasInt128Type() const override { return false; }
+
+ bool supportsAIXPowerAlignment() const override { return true; }
};
void addWindowsDefines(const llvm::Triple &Triple, const LangOptions &Opts,
Index: clang/lib/AST/RecordLayoutBuilder.cpp
===================================================================
--- clang/lib/AST/RecordLayoutBuilder.cpp
+++ clang/lib/AST/RecordLayoutBuilder.cpp
@@ -6,7 +6,6 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/Attr.h"
@@ -15,6 +14,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/Format.h"
@@ -588,6 +588,9 @@
/// Alignment - The current alignment of the record layout.
CharUnits Alignment;
+ /// PreferredAlignment - The preferred alignment of the record layout.
+ CharUnits PreferredAlignment;
+
/// The alignment if attribute packed is not used.
CharUnits UnpackedAlignment;
@@ -631,6 +634,7 @@
CharUnits NonVirtualSize;
CharUnits NonVirtualAlignment;
+ CharUnits PreferredNVAlignment;
/// If we've laid out a field but not included its tail padding in Size yet,
/// this is the size up to the end of that field.
@@ -651,6 +655,15 @@
/// the flag of field offset changing due to packed attribute.
bool HasPackedField;
+ /// FirstNonOverlappingEmptyFieldStatus - An auxiliary field used for AIX.
+ /// When there are OverlappingEmptyFields existing in the aggregate, the
+ /// status shows if a following non-overlappingEmptyField can be found.
+ enum {
+ Default,
+ FirstNonOverlappingEmptyFieldFound,
+ FirstNonOverlappingEmptyFieldHandled
+ } FirstNonOverlappingEmptyFieldStatus;
+
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
/// Bases - base classes and their offsets in the record.
@@ -677,17 +690,19 @@
ItaniumRecordLayoutBuilder(const ASTContext &Context,
EmptySubobjectMap *EmptySubobjects)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
- Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()),
- UnadjustedAlignment(CharUnits::One()),
- UseExternalLayout(false), InferAlignment(false), Packed(false),
- IsUnion(false), IsMac68kAlign(false), IsMsStruct(false),
- UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0),
- MaxFieldAlignment(CharUnits::Zero()), DataSize(0),
- NonVirtualSize(CharUnits::Zero()),
+ Alignment(CharUnits::One()), PreferredAlignment(CharUnits::One()),
+ UnpackedAlignment(CharUnits::One()),
+ UnadjustedAlignment(CharUnits::One()), UseExternalLayout(false),
+ InferAlignment(false), Packed(false), IsUnion(false),
+ IsMac68kAlign(false), IsMsStruct(false), UnfilledBitsInLastUnit(0),
+ LastBitfieldTypeSize(0), MaxFieldAlignment(CharUnits::Zero()),
+ DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
+ PreferredNVAlignment(CharUnits::One()),
PaddedFieldSize(CharUnits::Zero()), PrimaryBase(nullptr),
- PrimaryBaseIsVirtual(false), HasOwnVFPtr(false),
- HasPackedField(false), FirstNearlyEmptyVBase(nullptr) {}
+ PrimaryBaseIsVirtual(false), HasOwnVFPtr(false), HasPackedField(false),
+ FirstNonOverlappingEmptyFieldStatus(Default),
+ FirstNearlyEmptyVBase(nullptr) {}
void Layout(const RecordDecl *D);
void Layout(const CXXRecordDecl *D);
@@ -762,9 +777,13 @@
/// alignment.
void FinishLayout(const NamedDecl *D);
- void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment);
+ void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment,
+ CharUnits PreferredAlignment);
+ void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment) {
+ UpdateAlignment(NewAlignment, UnpackedNewAlignment, NewAlignment);
+ }
void UpdateAlignment(CharUnits NewAlignment) {
- UpdateAlignment(NewAlignment, NewAlignment);
+ UpdateAlignment(NewAlignment, NewAlignment, NewAlignment);
}
/// Retrieve the externally-supplied field offset for the given
@@ -806,6 +825,10 @@
};
} // end anonymous namespace
+static bool isAIXLayout(const ASTContext &Context) {
+ return Context.getTargetInfo().getTriple().getOS() == llvm::Triple::AIX;
+}
+
void ItaniumRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
for (const auto &I : RD->bases()) {
assert(!I.getType()->isDependentType() &&
@@ -997,7 +1020,7 @@
setSize(getSize().alignTo(BaseAlign));
// Update the alignment.
- UpdateAlignment(BaseAlign, UnpackedBaseAlign);
+ UpdateAlignment(BaseAlign, UnpackedBaseAlign, BaseAlign);
}
void ItaniumRecordLayoutBuilder::LayoutNonVirtualBases(
@@ -1179,8 +1202,6 @@
CharUnits
ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base->Class);
-
-
CharUnits Offset;
// Query the external layout to see if it provides an offset.
@@ -1196,26 +1217,40 @@
// Clang <= 6 incorrectly applied the 'packed' attribute to base classes.
// Per GCC's documentation, it only applies to non-static data members.
CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlignment();
+ CharUnits UnpackedPreferredAlign = Layout.getPreferredNVAlignment();
CharUnits BaseAlign =
(Packed && ((Context.getLangOpts().getClangABICompat() <=
LangOptions::ClangABI::Ver6) ||
Context.getTargetInfo().getTriple().isPS4()))
? CharUnits::One()
: UnpackedBaseAlign;
+ CharUnits PreferredAlign =
+ (Packed && ((Context.getLangOpts().getClangABICompat() <=
+ LangOptions::ClangABI::Ver6) ||
+ Context.getTargetInfo().getTriple().isPS4()))
+ ? CharUnits::One()
+ : UnpackedPreferredAlign;
// If we have an empty base class, try to place it at offset 0.
if (Base->Class->isEmpty() &&
(!HasExternalLayout || Offset == CharUnits::Zero()) &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
setSize(std::max(getSize(), Layout.getSize()));
- UpdateAlignment(BaseAlign, UnpackedBaseAlign);
+ UpdateAlignment(BaseAlign, UnpackedBaseAlign, PreferredAlign);
return CharUnits::Zero();
}
+ // Do not use AIX special alignment if current base is not the first member or
+ // the struct is not a union.
+ if (isAIXLayout(Context) && !(getDataSize().isZero() || IsUnion)) {
+ PreferredAlign = BaseAlign;
+ }
+
// The maximum field alignment overrides base align.
if (!MaxFieldAlignment.isZero()) {
BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
+ PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment);
UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
}
@@ -1248,7 +1283,7 @@
setSize(std::max(getSize(), Offset + Layout.getSize()));
// Remember max struct/class alignment.
- UpdateAlignment(BaseAlign, UnpackedBaseAlign);
+ UpdateAlignment(BaseAlign, UnpackedBaseAlign, PreferredAlign);
return Offset;
}
@@ -1321,6 +1356,7 @@
NonVirtualSize = Context.toCharUnitsFromBits(
llvm::alignTo(getSizeInBits(), Context.getTargetInfo().getCharAlign()));
NonVirtualAlignment = Alignment;
+ PreferredNVAlignment = PreferredAlignment;
// Lay out the virtual bases and add the primary virtual base offsets.
LayoutVirtualBases(RD, RD);
@@ -1733,25 +1769,34 @@
void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
bool InsertExtraPadding) {
+ auto *FieldClass = D->getType()->getAsCXXRecordDecl();
+ bool PotentiallyOverlapping = D->hasAttr<NoUniqueAddressAttr>() && FieldClass;
+ bool IsOverlappingEmptyField =
+ PotentiallyOverlapping && FieldClass->isEmpty();
+
+ if (isAIXLayout(Context) && FirstNonOverlappingEmptyFieldStatus == Default &&
+ !IsOverlappingEmptyField)
+ FirstNonOverlappingEmptyFieldStatus = FirstNonOverlappingEmptyFieldFound;
+
if (D->isBitField()) {
+ if (FirstNonOverlappingEmptyFieldStatus ==
+ FirstNonOverlappingEmptyFieldFound)
+ FirstNonOverlappingEmptyFieldStatus =
+ FirstNonOverlappingEmptyFieldHandled;
LayoutBitField(D);
return;
}
uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
-
// Reset the unfilled bits.
UnfilledBitsInLastUnit = 0;
LastBitfieldTypeSize = 0;
- auto *FieldClass = D->getType()->getAsCXXRecordDecl();
- bool PotentiallyOverlapping = D->hasAttr<NoUniqueAddressAttr>() && FieldClass;
- bool IsOverlappingEmptyField = PotentiallyOverlapping && FieldClass->isEmpty();
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
- CharUnits FieldOffset = (IsUnion || IsOverlappingEmptyField)
- ? CharUnits::Zero()
- : getDataSize();
+ CharUnits FieldOffset =
+ (IsUnion || IsOverlappingEmptyField) ? CharUnits::Zero() : getDataSize();
+
CharUnits FieldSize;
CharUnits FieldAlign;
// The amount of this class's dsize occupied by the field.
@@ -1829,21 +1874,52 @@
}
}
+ // AIX ABI has this special rule that in aggregates, the first member of
+ // floating point data type(or aggregate type contains floating point data
+ // type) is aligned according to its natural alignment value, subsequent
+ // of such data type members of the aggregate are aligned on 4-byte
+ // boundaries.
+ CharUnits PreferredAlign = FieldAlign;
+ if (isAIXLayout(Context) && FieldOffset == CharUnits::Zero() &&
+ ((D->getFieldIndex() == 0 && !IsOverlappingEmptyField) || IsUnion ||
+ (D->getFieldIndex() != 0 && FirstNonOverlappingEmptyFieldStatus ==
+ FirstNonOverlappingEmptyFieldFound))) {
+ FirstNonOverlappingEmptyFieldStatus = FirstNonOverlappingEmptyFieldHandled;
+
+ if (const BuiltinType *BTy =
+ Context.getBaseElementType(D->getType())->getAs<BuiltinType>()) {
+ if (BTy->isFloatingPoint()) {
+ PreferredAlign = FieldSize;
+ }
+ } else if (const RecordType *RT = D->getType()
+ ->getBaseElementTypeUnsafe()
+ ->getAs<RecordType>()) {
+ if (const RecordDecl *RD = RT->getDecl()) {
+ const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD);
+ PreferredAlign = FieldRecord.getPreferredAlignment();
+ }
+ }
+ }
+
// The align if the field is not packed. This is to check if the attribute
// was unnecessary (-Wpacked).
CharUnits UnpackedFieldAlign = FieldAlign;
CharUnits UnpackedFieldOffset = FieldOffset;
- if (FieldPacked)
+ if (FieldPacked) {
FieldAlign = CharUnits::One();
+ PreferredAlign = CharUnits::One();
+ }
CharUnits MaxAlignmentInChars =
Context.toCharUnitsFromBits(D->getMaxAlignment());
FieldAlign = std::max(FieldAlign, MaxAlignmentInChars);
+ PreferredAlign = std::max(PreferredAlign, MaxAlignmentInChars);
UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars);
// The maximum field alignment overrides the aligned attribute.
if (!MaxFieldAlignment.isZero()) {
FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+ PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment);
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
}
@@ -1910,7 +1986,7 @@
// Remember max struct/class alignment.
UnadjustedAlignment = std::max(UnadjustedAlignment, FieldAlign);
- UpdateAlignment(FieldAlign, UnpackedFieldAlign);
+ UpdateAlignment(FieldAlign, UnpackedFieldAlign, PreferredAlign);
}
void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
@@ -1936,8 +2012,10 @@
uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit;
uint64_t UnpackedSizeInBits =
llvm::alignTo(getSizeInBits(), Context.toBits(UnpackedAlignment));
- uint64_t RoundedSize =
- llvm::alignTo(getSizeInBits(), Context.toBits(Alignment));
+
+ uint64_t RoundedSize = llvm::alignTo(
+ getSizeInBits(),
+ Context.toBits(!isAIXLayout(Context) ? Alignment : PreferredAlignment));
if (UseExternalLayout) {
// If we're inferring alignment, and the external size is smaller than
@@ -1981,7 +2059,8 @@
}
void ItaniumRecordLayoutBuilder::UpdateAlignment(
- CharUnits NewAlignment, CharUnits UnpackedNewAlignment) {
+ CharUnits NewAlignment, CharUnits UnpackedNewAlignment,
+ CharUnits PreferredNewAlignment) {
// The alignment is not modified when using 'mac68k' alignment or when
// we have an externally-supplied layout that also provides overall alignment.
if (IsMac68kAlign || (UseExternalLayout && !InferAlignment))
@@ -1998,6 +2077,12 @@
"Alignment not a power of 2");
UnpackedAlignment = UnpackedNewAlignment;
}
+
+ if (PreferredNewAlignment > PreferredAlignment) {
+ assert(llvm::isPowerOf2_64(PreferredNewAlignment.getQuantity()) &&
+ "Alignment not a power of 2");
+ PreferredAlignment = PreferredNewAlignment;
+ }
}
uint64_t
@@ -3048,10 +3133,10 @@
Builder.cxxLayout(RD);
NewEntry = new (*this) ASTRecordLayout(
*this, Builder.Size, Builder.Alignment, Builder.Alignment,
- Builder.RequiredAlignment,
- Builder.HasOwnVFPtr, Builder.HasOwnVFPtr || Builder.PrimaryBase,
- Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets,
- Builder.NonVirtualSize, Builder.Alignment, CharUnits::Zero(),
+ Builder.Alignment, Builder.RequiredAlignment, Builder.HasOwnVFPtr,
+ Builder.HasOwnVFPtr || Builder.PrimaryBase, Builder.VBPtrOffset,
+ Builder.DataSize, Builder.FieldOffsets, Builder.NonVirtualSize,
+ Builder.Alignment, Builder.Alignment, CharUnits::Zero(),
Builder.PrimaryBase, false, Builder.SharedVBPtrBase,
Builder.EndsWithZeroSizedObject, Builder.LeadsWithZeroSizedBase,
Builder.Bases, Builder.VBases);
@@ -3059,8 +3144,8 @@
Builder.layout(D);
NewEntry = new (*this) ASTRecordLayout(
*this, Builder.Size, Builder.Alignment, Builder.Alignment,
- Builder.RequiredAlignment,
- Builder.Size, Builder.FieldOffsets);
+ Builder.Alignment, Builder.RequiredAlignment, Builder.Size,
+ Builder.FieldOffsets);
}
} else {
if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
@@ -3080,11 +3165,13 @@
CharUnits NonVirtualSize =
skipTailPadding ? DataSize : Builder.NonVirtualSize;
NewEntry = new (*this) ASTRecordLayout(
- *this, Builder.getSize(), Builder.Alignment, Builder.UnadjustedAlignment,
+ *this, Builder.getSize(), Builder.Alignment,
+ Builder.PreferredAlignment, Builder.UnadjustedAlignment,
/*RequiredAlignment : used by MS-ABI)*/
Builder.Alignment, Builder.HasOwnVFPtr, RD->isDynamicClass(),
CharUnits::fromQuantity(-1), DataSize, Builder.FieldOffsets,
NonVirtualSize, Builder.NonVirtualAlignment,
+ Builder.PreferredNVAlignment,
EmptySubobjects.SizeOfLargestEmptySubobject, Builder.PrimaryBase,
Builder.PrimaryBaseIsVirtual, nullptr, false, false, Builder.Bases,
Builder.VBases);
@@ -3093,7 +3180,8 @@
Builder.Layout(D);
NewEntry = new (*this) ASTRecordLayout(
- *this, Builder.getSize(), Builder.Alignment, Builder.UnadjustedAlignment,
+ *this, Builder.getSize(), Builder.Alignment,
+ Builder.PreferredAlignment, Builder.UnadjustedAlignment,
/*RequiredAlignment : used by MS-ABI)*/
Builder.Alignment, Builder.getSize(), Builder.FieldOffsets);
}
@@ -3245,14 +3333,11 @@
ItaniumRecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/nullptr);
Builder.Layout(D);
- const ASTRecordLayout *NewEntry =
- new (*this) ASTRecordLayout(*this, Builder.getSize(),
- Builder.Alignment,
- Builder.UnadjustedAlignment,
- /*RequiredAlignment : used by MS-ABI)*/
- Builder.Alignment,
- Builder.getDataSize(),
- Builder.FieldOffsets);
+ const ASTRecordLayout *NewEntry = new (*this) ASTRecordLayout(
+ *this, Builder.getSize(), Builder.Alignment, Builder.PreferredAlignment,
+ Builder.UnadjustedAlignment,
+ /*RequiredAlignment : used by MS-ABI)*/
+ Builder.Alignment, Builder.getDataSize(), Builder.FieldOffsets);
ObjCLayouts[Key] = NewEntry;
@@ -3415,22 +3500,26 @@
if (CXXRD && !isMsLayout(C))
OS << ", dsize=" << Layout.getDataSize().getQuantity();
OS << ", align=" << Layout.getAlignment().getQuantity();
+ if (isAIXLayout(C))
+ OS << ", preferredalign=" << Layout.getPreferredAlignment().getQuantity();
if (CXXRD) {
OS << ",\n";
PrintIndentNoOffset(OS, IndentLevel - 1);
OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
OS << ", nvalign=" << Layout.getNonVirtualAlignment().getQuantity();
+ if (isAIXLayout(C))
+ OS << ", preferrednvalign="
+ << Layout.getPreferredNVAlignment().getQuantity();
}
OS << "]\n";
}
-void ASTContext::DumpRecordLayout(const RecordDecl *RD,
- raw_ostream &OS,
+void ASTContext::DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS,
bool Simple) const {
if (!Simple) {
::DumpRecordLayout(OS, RD, *this, CharUnits(), 0, nullptr,
- /*PrintSizeInfo*/true,
+ /*PrintSizeInfo*/ true,
/*IncludeVirtualBases=*/true);
return;
}
@@ -3450,9 +3539,13 @@
if (!isMsLayout(*this))
OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
OS << " Alignment:" << toBits(Info.getAlignment()) << "\n";
+ if (isAIXLayout(*this))
+ OS << " PreferredAlignment:" << toBits(Info.getPreferredAlignment())
+ << "\n";
OS << " FieldOffsets: [";
for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) {
- if (i) OS << ", ";
+ if (i)
+ OS << ", ";
OS << Info.getFieldOffset(i);
}
OS << "]>\n";
Index: clang/lib/AST/RecordLayout.cpp
===================================================================
--- clang/lib/AST/RecordLayout.cpp
+++ clang/lib/AST/RecordLayout.cpp
@@ -29,45 +29,42 @@
ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
CharUnits alignment,
+ CharUnits preferredAlignment,
CharUnits unadjustedAlignment,
CharUnits requiredAlignment,
CharUnits datasize,
ArrayRef<uint64_t> fieldoffsets)
: Size(size), DataSize(datasize), Alignment(alignment),
+ PreferredAlignment(preferredAlignment),
UnadjustedAlignment(unadjustedAlignment),
RequiredAlignment(requiredAlignment) {
FieldOffsets.append(Ctx, fieldoffsets.begin(), fieldoffsets.end());
}
// Constructor for C++ records.
-ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
- CharUnits size, CharUnits alignment,
- CharUnits unadjustedAlignment,
- CharUnits requiredAlignment,
- bool hasOwnVFPtr, bool hasExtendableVFPtr,
- CharUnits vbptroffset,
- CharUnits datasize,
- ArrayRef<uint64_t> fieldoffsets,
- CharUnits nonvirtualsize,
- CharUnits nonvirtualalignment,
- CharUnits SizeOfLargestEmptySubobject,
- const CXXRecordDecl *PrimaryBase,
- bool IsPrimaryBaseVirtual,
- const CXXRecordDecl *BaseSharingVBPtr,
- bool EndsWithZeroSizedObject,
- bool LeadsWithZeroSizedBase,
- const BaseOffsetsMapTy& BaseOffsets,
- const VBaseOffsetsMapTy& VBaseOffsets)
- : Size(size), DataSize(datasize), Alignment(alignment),
- UnadjustedAlignment(unadjustedAlignment),
- RequiredAlignment(requiredAlignment), CXXInfo(new (Ctx) CXXRecordLayoutInfo)
-{
+ASTRecordLayout::ASTRecordLayout(
+ const ASTContext &Ctx, CharUnits size, CharUnits alignment,
+ CharUnits preferredAlignment, CharUnits unadjustedAlignment,
+ CharUnits requiredAlignment, bool hasOwnVFPtr, bool hasExtendableVFPtr,
+ CharUnits vbptroffset, CharUnits datasize, ArrayRef<uint64_t> fieldoffsets,
+ CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
+ CharUnits preferrednvalignment, CharUnits SizeOfLargestEmptySubobject,
+ const CXXRecordDecl *PrimaryBase, bool IsPrimaryBaseVirtual,
+ const CXXRecordDecl *BaseSharingVBPtr, bool EndsWithZeroSizedObject,
+ bool LeadsWithZeroSizedBase, const BaseOffsetsMapTy &BaseOffsets,
+ const VBaseOffsetsMapTy &VBaseOffsets)
+ : Size(size), DataSize(datasize), Alignment(alignment),
+ PreferredAlignment(preferredAlignment),
+ UnadjustedAlignment(unadjustedAlignment),
+ RequiredAlignment(requiredAlignment),
+ CXXInfo(new (Ctx) CXXRecordLayoutInfo) {
FieldOffsets.append(Ctx, fieldoffsets.begin(), fieldoffsets.end());
CXXInfo->PrimaryBase.setPointer(PrimaryBase);
CXXInfo->PrimaryBase.setInt(IsPrimaryBaseVirtual);
CXXInfo->NonVirtualSize = nonvirtualsize;
CXXInfo->NonVirtualAlignment = nonvirtualalignment;
+ CXXInfo->PreferredNVAlignment = preferrednvalignment;
CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject;
CXXInfo->BaseOffsets = BaseOffsets;
CXXInfo->VBaseOffsets = VBaseOffsets;
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -2393,6 +2393,12 @@
if (T->isMemberPointerType())
return getPreferredTypeAlign(getPointerDiffType().getTypePtr());
+ if (const auto *RT = T->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ return std::max(
+ ABIAlign, (unsigned)toBits(getASTRecordLayout(RD).PreferredAlignment));
+ }
+
if (!Target->allowsLargerPreferedTypeAlignment())
return ABIAlign;
@@ -2403,7 +2409,9 @@
T = ET->getDecl()->getIntegerType().getTypePtr();
if (T->isSpecificBuiltinType(BuiltinType::Double) ||
T->isSpecificBuiltinType(BuiltinType::LongLong) ||
- T->isSpecificBuiltinType(BuiltinType::ULongLong))
+ T->isSpecificBuiltinType(BuiltinType::ULongLong) ||
+ (T->isSpecificBuiltinType(BuiltinType::LongDouble) &&
+ Target->supportsAIXPowerAlignment()))
// Don't increase the alignment if an alignment attribute was specified on a
// typedef declaration.
if (!TI.AlignIsRequired)
Index: clang/include/clang/Basic/TargetInfo.h
===================================================================
--- clang/include/clang/Basic/TargetInfo.h
+++ clang/include/clang/Basic/TargetInfo.h
@@ -1371,6 +1371,9 @@
/// Whether target allows to overalign ABI-specified preferred alignment
virtual bool allowsLargerPreferedTypeAlignment() const { return true; }
+ /// Whether target supports the special power alignment rules of AIX.
+ virtual bool supportsAIXPowerAlignment() const { return false; }
+
/// Set supported OpenCL extensions and optional core features.
virtual void setSupportedOpenCLOpts() {}
Index: clang/include/clang/AST/RecordLayout.h
===================================================================
--- clang/include/clang/AST/RecordLayout.h
+++ clang/include/clang/AST/RecordLayout.h
@@ -70,6 +70,11 @@
// Alignment - Alignment of record in characters.
CharUnits Alignment;
+ // PreferredAlignment - Preferred alignment of record in characters. This
+ // can be different than Alignment in cases where it is beneficial for
+ // performance.
+ CharUnits PreferredAlignment;
+
// UnadjustedAlignment - Maximum of the alignments of the record members in
// characters.
CharUnits UnadjustedAlignment;
@@ -91,6 +96,11 @@
/// which is the alignment of the object without virtual bases.
CharUnits NonVirtualAlignment;
+ /// PreferredNVAlignment - The preferred non-virtual alignment (in chars) of
+ /// an object, which is the preferred alignment of the object without
+ /// virtual bases.
+ CharUnits PreferredNVAlignment;
+
/// SizeOfLargestEmptySubobject - The size of the largest empty subobject
/// (either a base or a member). Will be zero if the class doesn't contain
/// any empty subobjects.
@@ -139,30 +149,26 @@
CXXRecordLayoutInfo *CXXInfo = nullptr;
ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
- CharUnits unadjustedAlignment,
+ CharUnits preferredAlignment, CharUnits unadjustedAlignment,
CharUnits requiredAlignment, CharUnits datasize,
ArrayRef<uint64_t> fieldoffsets);
using BaseOffsetsMapTy = CXXRecordLayoutInfo::BaseOffsetsMapTy;
// Constructor for C++ records.
- ASTRecordLayout(const ASTContext &Ctx,
- CharUnits size, CharUnits alignment,
- CharUnits unadjustedAlignment,
- CharUnits requiredAlignment,
- bool hasOwnVFPtr, bool hasExtendableVFPtr,
- CharUnits vbptroffset,
- CharUnits datasize,
- ArrayRef<uint64_t> fieldoffsets,
+ ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
+ CharUnits preferredAlignment, CharUnits unadjustedAlignment,
+ CharUnits requiredAlignment, bool hasOwnVFPtr,
+ bool hasExtendableVFPtr, CharUnits vbptroffset,
+ CharUnits datasize, ArrayRef<uint64_t> fieldoffsets,
CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
+ CharUnits preferrednvalignment,
CharUnits SizeOfLargestEmptySubobject,
- const CXXRecordDecl *PrimaryBase,
- bool IsPrimaryBaseVirtual,
+ const CXXRecordDecl *PrimaryBase, bool IsPrimaryBaseVirtual,
const CXXRecordDecl *BaseSharingVBPtr,
- bool EndsWithZeroSizedObject,
- bool LeadsWithZeroSizedBase,
- const BaseOffsetsMapTy& BaseOffsets,
- const VBaseOffsetsMapTy& VBaseOffsets);
+ bool EndsWithZeroSizedObject, bool LeadsWithZeroSizedBase,
+ const BaseOffsetsMapTy &BaseOffsets,
+ const VBaseOffsetsMapTy &VBaseOffsets);
~ASTRecordLayout() = default;
@@ -175,6 +181,10 @@
/// getAlignment - Get the record alignment in characters.
CharUnits getAlignment() const { return Alignment; }
+ /// getPreferredFieldAlignment - Get the record preferred alignment in
+ /// characters.
+ CharUnits getPreferredAlignment() const { return PreferredAlignment; }
+
/// getUnadjustedAlignment - Get the record alignment in characters, before
/// alignment adjustement.
CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; }
@@ -193,9 +203,7 @@
/// getDataSize() - Get the record data size, which is the record size
/// without tail padding, in characters.
- CharUnits getDataSize() const {
- return DataSize;
- }
+ CharUnits getDataSize() const { return DataSize; }
/// getNonVirtualSize - Get the non-virtual size (in chars) of an object,
/// which is the size of the object without virtual bases.
@@ -205,14 +213,23 @@
return CXXInfo->NonVirtualSize;
}
- /// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object,
- /// which is the alignment of the object without virtual bases.
+ /// getNonVirtualAlignment - Get the non-virtual alignment (in chars) of an
+ /// object, which is the alignment of the object without virtual bases.
CharUnits getNonVirtualAlignment() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->NonVirtualAlignment;
}
+ /// getPreferredNVAlignment - Get the preferred non-virtual alignment (in
+ /// chars) of an object, which is the preferred alignment of the object
+ /// without virtual bases.
+ CharUnits getPreferredNVAlignment() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+
+ return CXXInfo->PreferredNVAlignment;
+ }
+
/// getPrimaryBase - Get the primary base for this record.
const CXXRecordDecl *getPrimaryBase() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
@@ -287,9 +304,7 @@
return !CXXInfo->VBPtrOffset.isNegative();
}
- CharUnits getRequiredAlignment() const {
- return RequiredAlignment;
- }
+ CharUnits getRequiredAlignment() const { return RequiredAlignment; }
bool endsWithZeroSizedObject() const {
return CXXInfo && CXXInfo->EndsWithZeroSizedObject;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits