majnemer added you to the CC list for the revision "Support MS Non-Virtual Base 
Placement Rules in CGRecordLayoutBuilder".

Hi rnk, majnemer, rsmith,

Adds a case to CGRecordLayoutBuilder to understand how the ms-abi lays out 
non-virtual bases.  This behavior is already supported by RecordLayoutBuilder, 
but invoking the behavior would cause an assertion to trip in 
CGRecordLayoutBuilder when it didn't recognize the layout.

http://llvm-reviews.chandlerc.com/D2524

Files:
  lib/CodeGen/CGRecordLayoutBuilder.cpp
  test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp

Index: lib/CodeGen/CGRecordLayoutBuilder.cpp
===================================================================
--- lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -144,6 +144,11 @@
   bool LayoutNonVirtualBases(const CXXRecordDecl *RD, 
                              const ASTRecordLayout &Layout);
 
+  /// LayoutNonVirtualBases - 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 @@
 }
 
 bool
+CGRecordLayoutBuilder::MSLayoutNonVirtualBases(const CXXRecordDecl *RD,
+                                               const ASTRecordLayout &Layout) {
+  // 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;
+  }
+
+  // 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 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 @@
 
   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;
Index: test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp
@@ -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 }
Index: lib/CodeGen/CGRecordLayoutBuilder.cpp
===================================================================
--- lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -144,6 +144,11 @@
   bool LayoutNonVirtualBases(const CXXRecordDecl *RD, 
                              const ASTRecordLayout &Layout);
 
+  /// LayoutNonVirtualBases - 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 @@
 }
 
 bool
+CGRecordLayoutBuilder::MSLayoutNonVirtualBases(const CXXRecordDecl *RD,
+                                               const ASTRecordLayout &Layout) {
+  // 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;
+  }
+
+  // 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 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 @@
 
   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;
Index: test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/microsoft-abi-non-virtual-base-ordering.cpp
@@ -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 }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to