From 9c600bbda00d96de188d08ac866e37f366534760 Mon Sep 17 00:00:00 2001 From: Warren Hunt Date: Wed, 9 Apr 2014 21:57:24 +0000 Subject: [PATCH] [MS-ABI] Update to alias-avoidance padding This patch changes how we determine if padding is needed between two bases in msvc compatibility mode. Test cases included. In addition, a very minor change to the printing of structures to ease lit testing. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205933 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/RecordLayoutBuilder.cpp | 31 +-- .../Layout/ms-x86-alias-avoidance-padding.cpp | 260 ++++++++++++++++++ 2 files changed, 275 insertions(+), 16 deletions(-) diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index ce55d2e49a..8427eb5604 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -2099,12 +2099,13 @@ static bool isMsLayout(const RecordDecl* D) { // * The ABI attempts to avoid aliasing of zero sized bases by adding padding // between bases or vbases with specific properties. The criteria for // additional padding between two bases is that the first base is zero sized -// or has a zero sized subobject and the second base is zero sized or leads -// with a zero sized base (sharing of vfptrs can reorder the layout of the -// so the leading base is not always the first one declared). The padding -// added for bases is 1 byte. The padding added for vbases depends on the -// alignment of the object but is at least 4 bytes (in both 32 and 64 bit -// modes). +// or ends with a zero sized subobject and the second base is zero sized or +// leads with a zero sized base (sharing of vfptrs can reorder the layout of +// the so the leading base is not always the first one declared). This rule +// is slightly buggy (conservative) because it doesn't take into account +// fields that are not records. The padding added for bases is 1 byte. The +// padding added for vbases depends on the alignment of the object but is at +// least 4 bytes (in both 32 and 64 bit modes). // * There is no concept of non-virtual alignment or any distinction between // data size and non-virtual size. // * __declspec(align) on bitfields has the effect of changing the bitfield's @@ -2213,9 +2214,10 @@ public: bool HasVBPtr : 1; /// \brief Lets us know if we're in 64-bit mode bool Is64BitMode : 1; - /// \brief True if this class contains a zero sized member or base or a base - /// with a zero sized member or base. Only used for MS-ABI. - bool HasZeroSizedSubObject : 1; + /// \brief True if the last sub-object within the type is zero sized or the + /// object itself is zero sized. This *does not* count members that are not + /// records. Only used for MS-ABI. + bool EndsWithZeroSizedObject : 1; /// \brief True if this class is zero sized or first base is zero sized or /// has this property. Only used for MS-ABI. bool LeadsWithZeroSizedBase : 1; @@ -2231,8 +2233,7 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( if (!MaxFieldAlignment.isZero()) Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); // Track zero-sized subobjects here where it's already available. - if (Layout.hasZeroSizedSubObject()) - HasZeroSizedSubObject = true; + EndsWithZeroSizedObject = Layout.hasZeroSizedSubObject(); // Respect required alignment, this is necessary because we may have adjusted // the alignment in the case of pragam pack. Note that the required alignment // doesn't actually apply to the struct alignment at this point. @@ -2339,7 +2340,7 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { void MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) { - HasZeroSizedSubObject = false; + EndsWithZeroSizedObject = false; LeadsWithZeroSizedBase = false; HasOwnVFPtr = false; HasVBPtr = false; @@ -2617,7 +2618,6 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { if (HasVtordisp) Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize; // Insert the virtual base. - HasZeroSizedSubObject = false; ElementInfo Info = getAdjustedElementInfo(BaseLayout); CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment); VBases.insert(std::make_pair(BaseDecl, @@ -2637,7 +2637,7 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { } // Zero-sized structures have size equal to their alignment. if (Size.isZero()) { - HasZeroSizedSubObject = true; + EndsWithZeroSizedObject = true; LeadsWithZeroSizedBase = true; Size = Alignment; } @@ -2750,7 +2750,7 @@ ASTContext::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const { Builder.FieldOffsets.size(), Builder.NonVirtualSize, Builder.Alignment, CharUnits::Zero(), Builder.PrimaryBase, false, Builder.SharedVBPtrBase, - Builder.HasZeroSizedSubObject, Builder.LeadsWithZeroSizedBase, + Builder.EndsWithZeroSizedObject, Builder.LeadsWithZeroSizedBase, Builder.Bases, Builder.VBases); } else { Builder.layout(D); @@ -3078,7 +3078,6 @@ static void DumpCXXRecordLayout(raw_ostream &OS, PrintIndentNoOffset(OS, IndentLevel - 1); OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity(); OS << ", nvalign=" << Layout.getNonVirtualAlignment().getQuantity() << "]\n"; - OS << '\n'; } void ASTContext::DumpRecordLayout(const RecordDecl *RD, diff --git a/test/Layout/ms-x86-alias-avoidance-padding.cpp b/test/Layout/ms-x86-alias-avoidance-padding.cpp index aac652135a..94ed031734 100644 --- a/test/Layout/ms-x86-alias-avoidance-padding.cpp +++ b/test/Layout/ms-x86-alias-avoidance-padding.cpp @@ -298,6 +298,257 @@ struct JC4 : JC1, JC2 { // CHECK-X64-NEXT: | [sizeof=24, align=8 // CHECK-X64-NEXT: | nvsize=24, nvalign=8] +struct RA {}; +struct RB { char c; }; +struct RV {}; +struct RW { char c; }; +struct RY { RY() { printf("%Id\n", (char*)this - buffer); } }; +struct RX0 : RB, RA {}; +struct RX1 : RA, RB {}; +struct RX2 : RA { char a; }; +struct RX3 : RA { RB a; }; +struct RX4 { RA a; char b; }; +struct RX5 { RA a; RB b; }; +struct RX6 : virtual RV { RB a; }; +struct RX7 : virtual RW { RA a; }; +struct RX8 : RA, virtual RW {}; + +struct RZ0 : RX0, RY {}; +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct RZ0 +// CHECK-NEXT: 0 | struct RX0 (base) +// CHECK-NEXT: 0 | struct RB (base) +// CHECK-NEXT: 0 | char c +// CHECK-NEXT: 1 | struct RA (base) (empty) +// CHECK-NEXT: 2 | struct RY (base) (empty) +// CHECK-NEXT: | [sizeof=2, align=1 +// CHECK-NEXT: | nvsize=2, nvalign=1] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct RZ0 +// CHECK-X64-NEXT: 0 | struct RX0 (base) +// CHECK-X64-NEXT: 0 | struct RB (base) +// CHECK-X64-NEXT: 0 | char c +// CHECK-X64-NEXT: 1 | struct RA (base) (empty) +// CHECK-X64-NEXT: 2 | struct RY (base) (empty) +// CHECK-X64-NEXT: | [sizeof=2, align=1 +// CHECK-X64-NEXT: | nvsize=2, nvalign=1] + +struct RZ1 : RX1, RY {}; +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct RZ1 +// CHECK-NEXT: 0 | struct RX1 (base) +// CHECK-NEXT: 0 | struct RA (base) (empty) +// CHECK-NEXT: 0 | struct RB (base) +// CHECK-NEXT: 0 | char c +// CHECK-NEXT: 1 | struct RY (base) (empty) +// CHECK-NEXT: | [sizeof=1, align=1 +// CHECK-NEXT: | nvsize=1, nvalign=1] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct RZ1 +// CHECK-X64-NEXT: 0 | struct RX1 (base) +// CHECK-X64-NEXT: 0 | struct RA (base) (empty) +// CHECK-X64-NEXT: 0 | struct RB (base) +// CHECK-X64-NEXT: 0 | char c +// CHECK-X64-NEXT: 1 | struct RY (base) (empty) +// CHECK-X64-NEXT: | [sizeof=1, align=1 +// CHECK-X64-NEXT: | nvsize=1, nvalign=1] + +struct RZ2 : RX2, RY {}; +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct RZ2 +// CHECK-NEXT: 0 | struct RX2 (base) +// CHECK-NEXT: 0 | struct RA (base) (empty) +// CHECK-NEXT: 0 | char a +// CHECK-NEXT: 2 | struct RY (base) (empty) +// CHECK-NEXT: | [sizeof=2, align=1 +// CHECK-NEXT: | nvsize=2, nvalign=1] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct RZ2 +// CHECK-X64-NEXT: 0 | struct RX2 (base) +// CHECK-X64-NEXT: 0 | struct RA (base) (empty) +// CHECK-X64-NEXT: 0 | char a +// CHECK-X64-NEXT: 2 | struct RY (base) (empty) +// CHECK-X64-NEXT: | [sizeof=2, align=1 +// CHECK-X64-NEXT: | nvsize=2, nvalign=1] + +struct RZ3 : RX3, RY {}; +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct RZ3 +// CHECK-NEXT: 0 | struct RX3 (base) +// CHECK-NEXT: 0 | struct RA (base) (empty) +// CHECK-NEXT: 0 | struct RB a +// CHECK-NEXT: 0 | char c +// CHECK-NEXT: | [sizeof=1, align=1 +// CHECK-NEXT: | nvsize=1, nvalign=1] +// CHECK-NEXT: 1 | struct RY (base) (empty) +// CHECK-NEXT: | [sizeof=1, align=1 +// CHECK-NEXT: | nvsize=1, nvalign=1] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct RZ3 +// CHECK-X64-NEXT: 0 | struct RX3 (base) +// CHECK-X64-NEXT: 0 | struct RA (base) (empty) +// CHECK-X64-NEXT: 0 | struct RB a +// CHECK-X64-NEXT: 0 | char c +// CHECK-X64-NEXT: | [sizeof=1, align=1 +// CHECK-X64-NEXT: | nvsize=1, nvalign=1] +// CHECK-X64-NEXT: 1 | struct RY (base) (empty) +// CHECK-X64-NEXT: | [sizeof=1, align=1 +// CHECK-X64-NEXT: | nvsize=1, nvalign=1] + +struct RZ4 : RX4, RY {}; +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct RZ4 +// CHECK-NEXT: 0 | struct RX4 (base) +// CHECK-NEXT: 0 | struct RA a (empty) +// CHECK-NEXT: | [sizeof=1, align=1 +// CHECK-NEXT: | nvsize=0, nvalign=1] +// CHECK-NEXT: 1 | char b +// CHECK-NEXT: 3 | struct RY (base) (empty) +// CHECK-NEXT: | [sizeof=3, align=1 +// CHECK-NEXT: | nvsize=3, nvalign=1] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct RZ4 +// CHECK-X64-NEXT: 0 | struct RX4 (base) +// CHECK-X64-NEXT: 0 | struct RA a (empty) +// CHECK-X64-NEXT: | [sizeof=1, align=1 +// CHECK-X64-NEXT: | nvsize=0, nvalign=1] +// CHECK-X64-NEXT: 1 | char b +// CHECK-X64-NEXT: 3 | struct RY (base) (empty) +// CHECK-X64-NEXT: | [sizeof=3, align=1 +// CHECK-X64-NEXT: | nvsize=3, nvalign=1] + +struct RZ5 : RX5, RY {}; +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct RZ5 +// CHECK-NEXT: 0 | struct RX5 (base) +// CHECK-NEXT: 0 | struct RA a (empty) +// CHECK-NEXT: | [sizeof=1, align=1 +// CHECK-NEXT: | nvsize=0, nvalign=1] +// CHECK-NEXT: 1 | struct RB b +// CHECK-NEXT: 1 | char c +// CHECK-NEXT: | [sizeof=1, align=1 +// CHECK-NEXT: | nvsize=1, nvalign=1] +// CHECK-NEXT: 2 | struct RY (base) (empty) +// CHECK-NEXT: | [sizeof=2, align=1 +// CHECK-NEXT: | nvsize=2, nvalign=1] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct RZ5 +// CHECK-X64-NEXT: 0 | struct RX5 (base) +// CHECK-X64-NEXT: 0 | struct RA a (empty) +// CHECK-X64-NEXT: | [sizeof=1, align=1 +// CHECK-X64-NEXT: | nvsize=0, nvalign=1] +// CHECK-X64-NEXT: 1 | struct RB b +// CHECK-X64-NEXT: 1 | char c +// CHECK-X64-NEXT: | [sizeof=1, align=1 +// CHECK-X64-NEXT: | nvsize=1, nvalign=1] +// CHECK-X64-NEXT: 2 | struct RY (base) (empty) +// CHECK-X64-NEXT: | [sizeof=2, align=1 +// CHECK-X64-NEXT: | nvsize=2, nvalign=1] + +struct RZ6 : RX6, RY {}; +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct RZ6 +// CHECK-NEXT: 0 | struct RX6 (base) +// CHECK-NEXT: 0 | (RX6 vbtable pointer) +// CHECK-NEXT: 4 | struct RB a +// CHECK-NEXT: 4 | char c +// CHECK-NEXT: | [sizeof=1, align=1 +// CHECK-NEXT: | nvsize=1, nvalign=1] +// CHECK-NEXT: 9 | struct RY (base) (empty) +// CHECK-NEXT: 12 | struct RV (virtual base) (empty) +// CHECK-NEXT: | [sizeof=12, align=4 +// CHECK-NEXT: | nvsize=12, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct RZ6 +// CHECK-X64-NEXT: 0 | struct RX6 (base) +// CHECK-X64-NEXT: 0 | (RX6 vbtable pointer) +// CHECK-X64-NEXT: 8 | struct RB a +// CHECK-X64-NEXT: 8 | char c +// CHECK-X64-NEXT: | [sizeof=1, align=1 +// CHECK-X64-NEXT: | nvsize=1, nvalign=1] +// CHECK-X64-NEXT: 17 | struct RY (base) (empty) +// CHECK-X64-NEXT: 24 | struct RV (virtual base) (empty) +// CHECK-X64-NEXT: | [sizeof=24, align=8 +// CHECK-X64-NEXT: | nvsize=24, nvalign=8] + +struct RZ7 : RX7, RY {}; +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct RZ7 +// CHECK-NEXT: 0 | struct RX7 (base) +// CHECK-NEXT: 0 | (RX7 vbtable pointer) +// CHECK-NEXT: 4 | struct RA a (empty) +// CHECK-NEXT: | [sizeof=1, align=1 +// CHECK-NEXT: | nvsize=0, nvalign=1] +// CHECK-NEXT: 8 | struct RY (base) (empty) +// CHECK-NEXT: 8 | struct RW (virtual base) +// CHECK-NEXT: 8 | char c +// CHECK-NEXT: | [sizeof=9, align=4 +// CHECK-NEXT: | nvsize=8, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct RZ7 +// CHECK-X64-NEXT: 0 | struct RX7 (base) +// CHECK-X64-NEXT: 0 | (RX7 vbtable pointer) +// CHECK-X64-NEXT: 8 | struct RA a (empty) +// CHECK-X64-NEXT: | [sizeof=1, align=1 +// CHECK-X64-NEXT: | nvsize=0, nvalign=1] +// CHECK-X64-NEXT: 16 | struct RY (base) (empty) +// CHECK-X64-NEXT: 16 | struct RW (virtual base) +// CHECK-X64-NEXT: 16 | char c +// CHECK-X64-NEXT: | [sizeof=24, align=8 +// CHECK-X64-NEXT: | nvsize=16, nvalign=8] + +struct RZ8 : RX8, RY {}; +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct RZ8 +// CHECK-NEXT: 0 | struct RX8 (base) +// CHECK-NEXT: 4 | struct RA (base) (empty) +// CHECK-NEXT: 0 | (RX8 vbtable pointer) +// CHECK-NEXT: 4 | struct RY (base) (empty) +// CHECK-NEXT: 4 | struct RW (virtual base) +// CHECK-NEXT: 4 | char c +// CHECK-NEXT: | [sizeof=5, align=4 +// CHECK-NEXT: | nvsize=4, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct RZ8 +// CHECK-X64-NEXT: 0 | struct RX8 (base) +// CHECK-X64-NEXT: 8 | struct RA (base) (empty) +// CHECK-X64-NEXT: 0 | (RX8 vbtable pointer) +// CHECK-X64-NEXT: 8 | struct RY (base) (empty) +// CHECK-X64-NEXT: 8 | struct RW (virtual base) +// CHECK-X64-NEXT: 8 | char c +// CHECK-X64-NEXT: | [sizeof=16, align=8 +// CHECK-X64-NEXT: | nvsize=8, nvalign=8] + + + int a[ sizeof(AT3) + sizeof(BT3) + @@ -305,4 +556,13 @@ sizeof(T3) + sizeof(E) + sizeof(F) + sizeof(JC4) + +sizeof(RZ0) + +sizeof(RZ1) + +sizeof(RZ2) + +sizeof(RZ3) + +sizeof(RZ4) + +sizeof(RZ5) + +sizeof(RZ6) + +sizeof(RZ7) + +sizeof(RZ8) + 0]; -- 2.40.0