r205933 - [MS-ABI] Update to alias-avoidance padding

Warren Hunt whunt at google.com
Wed Apr 9 14:57:24 PDT 2014


Author: whunt
Date: Wed Apr  9 16:57:24 2014
New Revision: 205933

URL: http://llvm.org/viewvc/llvm-project?rev=205933&view=rev
Log:
[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.

Modified:
    cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
    cfe/trunk/test/Layout/ms-x86-alias-avoidance-padding.cpp

Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.cpp?rev=205933&r1=205932&r2=205933&view=diff
==============================================================================
--- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp Wed Apr  9 16:57:24 2014
@@ -2099,12 +2099,13 @@ static bool isMsLayout(const RecordDecl*
 // * 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::getAdjuste
   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::initi
 
 void
 MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
-  HasZeroSizedSubObject = false;
+  EndsWithZeroSizedObject = false;
   LeadsWithZeroSizedBase = false;
   HasOwnVFPtr = false;
   HasVBPtr = false;
@@ -2617,7 +2618,6 @@ void MicrosoftRecordLayoutBuilder::layou
     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::final
   }
   // 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::BuildMicrosoftASTRecordLayou
         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_ostr
   PrintIndentNoOffset(OS, IndentLevel - 1);
   OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
   OS << ", nvalign=" << Layout.getNonVirtualAlignment().getQuantity() << "]\n";
-  OS << '\n';
 }
 
 void ASTContext::DumpRecordLayout(const RecordDecl *RD,

Modified: cfe/trunk/test/Layout/ms-x86-alias-avoidance-padding.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Layout/ms-x86-alias-avoidance-padding.cpp?rev=205933&r1=205932&r2=205933&view=diff
==============================================================================
--- cfe/trunk/test/Layout/ms-x86-alias-avoidance-padding.cpp (original)
+++ cfe/trunk/test/Layout/ms-x86-alias-avoidance-padding.cpp Wed Apr  9 16:57:24 2014
@@ -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];





More information about the cfe-commits mailing list