r198900 - [ms-abi] Fixing CGRecordLayoutBuilder w.r.t. MS NonVirutalBase Layout

Warren Hunt whunt at google.com
Thu Jan 9 15:51:32 PST 2014


Author: whunt
Date: Thu Jan  9 17:51:31 2014
New Revision: 198900

URL: http://llvm.org/viewvc/llvm-project?rev=198900&view=rev
Log:
[ms-abi] Fixing CGRecordLayoutBuilder w.r.t. MS NonVirutalBase Layout


The MS abi lays out *all* non-virtual bases with leading vfptrs before 
laying out non-virutal bases without vfptrs.  This guarantees that the 
primary base is laid out first.  r198818 fixed RecordLayoutBuilder to 
produce compatiable layouts.  This patch fixes CGRecordLayoutBuilder to 
be able to consume those layouts and produce meaningful output without 
tripping any asserts about assumed incoming layout.

A test case is included that shows CGRecordLayoutBuilder in fact 
produces output in the compatiable order.


Added:
    cfe/trunk/test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp   (with props)
Modified:
    cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
    cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp

Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.cpp?rev=198900&r1=198899&r2=198900&view=diff
==============================================================================
--- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp Thu Jan  9 17:51:31 2014
@@ -2157,7 +2157,7 @@ MicrosoftRecordLayoutBuilder::getAdjuste
   // Respect required alignment, this is necessary because we may have adjusted
   // the alignment in the case of pragam pack.
   Info.Alignment = std::max(Info.Alignment, Layout.getRequiredAlignment());
-  Info.Size = Layout.getNonVirtualSize();
+  Info.Size = Layout.getDataSize();
   return Info;
 }
 
@@ -2538,17 +2538,17 @@ void MicrosoftRecordLayoutBuilder::injec
     // different from the general case layout but it may have to do with lazy
     // placement of zero sized bases.
     VBPtrOffset = Size;
-    if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) {
+    if (LastBaseLayout && LastBaseLayout->getDataSize().isZero()) {
       VBPtrOffset = Bases[LastBaseDecl];
-      if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero())
+      if (PenultBaseLayout && PenultBaseLayout->getDataSize().isZero())
         VBPtrOffset = Bases[PenultBaseDecl];
     }
     // Once we've located a spot for the vbptr, place it.
     VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment);
     Size = VBPtrOffset + PointerInfo.Size;
-    if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) {
+    if (LastBaseLayout && LastBaseLayout->getDataSize().isZero()) {
       // Add the padding between zero sized bases after the vbptr.
-      if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero())
+      if (PenultBaseLayout && PenultBaseLayout->getDataSize().isZero())
         Size += CharUnits::One();
       Size = Size.RoundUpToAlignment(LastBaseLayout->getRequiredAlignment());
       Bases[LastBaseDecl] = Size;
@@ -2601,7 +2601,7 @@ void MicrosoftRecordLayoutBuilder::layou
     CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
     VBases.insert(std::make_pair(BaseDecl,
         ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
-    Size = BaseOffset + BaseLayout.getNonVirtualSize();
+    Size = BaseOffset + BaseLayout.getDataSize();
     updateAlignment(Info.Alignment);
     PreviousBaseLayout = &BaseLayout;
   }

Modified: cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp?rev=198900&r1=198899&r2=198900&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp Thu Jan  9 17:51:31 2014
@@ -144,6 +144,11 @@ private:
   bool LayoutNonVirtualBases(const CXXRecordDecl *RD, 
                              const ASTRecordLayout &Layout);
 
+  /// MSLayoutNonVirtualBases - layout the virtual bases of a record decl,
+  /// like MSVC.
+  bool MSLayoutNonVirtualBases(const CXXRecordDecl *RD, 
+                               const ASTRecordLayout &Layout);
+
   /// ComputeNonVirtualBaseType - Compute the non-virtual base field types.
   bool ComputeNonVirtualBaseType(const CXXRecordDecl *RD);
   
@@ -708,6 +713,72 @@ CGRecordLayoutBuilder::LayoutNonVirtualB
 }
 
 bool
+CGRecordLayoutBuilder::MSLayoutNonVirtualBases(const CXXRecordDecl *RD,
+                                               const ASTRecordLayout &Layout) {
+  // Add a vfptr if the layout says to do so.
+  if (Layout.hasOwnVFPtr()) {
+    llvm::Type *FunctionType =
+      llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()),
+                              /*isVarArg=*/true);
+    llvm::Type *VTableTy = FunctionType->getPointerTo();
+
+    if (getTypeAlignment(VTableTy) > Alignment) {
+      // FIXME: Should we allow this to happen in Sema?
+      assert(!Packed && "Alignment is wrong even with packed struct!");
+      return false;
+    }
+
+    assert(NextFieldOffset.isZero() &&
+           "VTable pointer must come first!");
+    AppendField(CharUnits::Zero(), VTableTy->getPointerTo());
+  }
+
+  // Layout the non-virtual bases that have leading vfptrs.
+  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+       E = RD->bases_end(); I != E; ++I) {
+    if (I->isVirtual())
+      continue;
+    const CXXRecordDecl *BaseDecl = 
+      cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+    const ASTRecordLayout &BaseLayout
+      = Types.getContext().getASTRecordLayout(BaseDecl);
+
+    if (!BaseLayout.hasExtendableVFPtr())
+      continue;
+
+    if (!LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl)))
+      return false;
+  }
+
+  // Layout the non-virtual bases that don't have leading vfptrs.
+  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+       E = RD->bases_end(); I != E; ++I) {
+    if (I->isVirtual())
+      continue;
+    const CXXRecordDecl *BaseDecl = 
+      cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+    const ASTRecordLayout &BaseLayout
+      = Types.getContext().getASTRecordLayout(BaseDecl);
+
+    if (BaseLayout.hasExtendableVFPtr())
+      continue;
+
+    if (!LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl)))
+      return false;
+  }
+
+  // Add a vb-table pointer if the layout insists.
+  if (Layout.hasOwnVBPtr()) {
+    CharUnits VBPtrOffset = Layout.getVBPtrOffset();
+    llvm::Type *Vbptr = llvm::Type::getInt32PtrTy(Types.getLLVMContext());
+    AppendPadding(VBPtrOffset, getTypeAlignment(Vbptr));
+    AppendField(VBPtrOffset, Vbptr);
+  }
+
+  return true;
+}
+
+bool
 CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) {
   const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD);
 
@@ -755,7 +826,10 @@ bool CGRecordLayoutBuilder::LayoutFields
 
   const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
   if (RD)
-    if (!LayoutNonVirtualBases(RD, Layout))
+    if (Types.getTarget().getCXXABI().isMicrosoft()) {
+      if (!MSLayoutNonVirtualBases(RD, Layout))
+        return false;
+    } else if (!LayoutNonVirtualBases(RD, Layout))
       return false;
 
   unsigned FieldNo = 0;

Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp?rev=198900&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp Thu Jan  9 17:51:31 2014
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=i686-pc-win32 -o - %s  2>/dev/null | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=x86_64-pc-win32 -o - %s  2>/dev/null | FileCheck %s
+
+struct C0 { int a; };
+struct C1 { int a; virtual void C1M() {} };
+struct C2 { int a; virtual void C2M() {} };
+struct C3 : C0, C1, C2 {} a;
+
+// Check to see that both C1 and C2 get laid out before C0 does.
+// CHECK: %struct.C3 = type { %struct.C1, %struct.C2, %struct.C0 }

Propchange: cfe/trunk/test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp
------------------------------------------------------------------------------
    svn:executable = *





More information about the cfe-commits mailing list