r184309 - [ms-cxxabi] Emit and install appropriately mangled vbtables

Reid Kleckner reid at kleckner.net
Wed Jun 19 08:20:39 PDT 2013


Author: rnk
Date: Wed Jun 19 10:20:38 2013
New Revision: 184309

URL: http://llvm.org/viewvc/llvm-project?rev=184309&view=rev
Log:
[ms-cxxabi] Emit and install appropriately mangled vbtables

In Itanium, dynamic classes have one vtable with several different
address points for dynamic base classes that can't share vtables.

In the MS C++ ABI, each vbtable that can't be shared gets its own
symbol, similar to how ctor vtables work in Itanium.  However, instead
of mangling the subobject offset into the symbol, the unique portions of
the inheritance path are mangled into the symbol to make it unique.

This patch implements the MSVC 2012 scheme for forming unique vbtable
symbol names.  MSVC 2010 use the same mangling with a different subset
of the path.  Implementing that mangling and possibly others is TODO.

Each vbtable is an array of i32 offsets from the vbptr that points to it
to another virtual base subobject.  The first entry of a vbtable always
points to the base of the current subobject, implying that it is the
same no matter which parent class contains it.

Reviewers: rjmccall

Differential Revision: http://llvm-reviews.chandlerc.com/D636

Added:
    cfe/trunk/lib/CodeGen/MicrosoftVBTables.cpp
    cfe/trunk/lib/CodeGen/MicrosoftVBTables.h
    cfe/trunk/test/CodeGenCXX/microsoft-abi-vbtables.cpp
Modified:
    cfe/trunk/include/clang/AST/Mangle.h
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/CodeGen/CGCXXABI.cpp
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CGVTables.cpp
    cfe/trunk/lib/CodeGen/CMakeLists.txt
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp

Modified: cfe/trunk/include/clang/AST/Mangle.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Mangle.h (original)
+++ cfe/trunk/include/clang/AST/Mangle.h Wed Jun 19 10:20:38 2013
@@ -110,6 +110,12 @@ public:
                                raw_ostream &) = 0;
   virtual void mangleCXXVTT(const CXXRecordDecl *RD,
                             raw_ostream &) = 0;
+  /// \brief Mangle vbtable symbols.  Only a subset of the bases along the path
+  /// to the vbtable are included in the name.  It's up to the caller to pick
+  /// them correctly.
+  virtual void mangleCXXVBTable(const CXXRecordDecl *Derived,
+                                ArrayRef<const CXXRecordDecl *> BasePath,
+                                raw_ostream &Out) = 0;
   virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
                                    const CXXRecordDecl *Type,
                                    raw_ostream &) = 0;

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Wed Jun 19 10:20:38 2013
@@ -130,6 +130,9 @@ public:
                        raw_ostream &);
   void mangleCXXVTT(const CXXRecordDecl *RD,
                     raw_ostream &);
+  void mangleCXXVBTable(const CXXRecordDecl *Derived,
+                        ArrayRef<const CXXRecordDecl *> BasePath,
+                        raw_ostream &Out);
   void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
                            const CXXRecordDecl *Type,
                            raw_ostream &);
@@ -3597,6 +3600,13 @@ void ItaniumMangleContext::mangleCXXVTT(
   Mangler.mangleNameOrStandardSubstitution(RD);
 }
 
+void
+ItaniumMangleContext::mangleCXXVBTable(const CXXRecordDecl *Derived,
+                                       ArrayRef<const CXXRecordDecl *> BasePath,
+                                       raw_ostream &Out) {
+  llvm_unreachable("The Itanium C++ ABI does not have virtual base tables!");
+}
+
 void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
                                                int64_t Offset,
                                                const CXXRecordDecl *Type,

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Wed Jun 19 10:20:38 2013
@@ -155,6 +155,9 @@ public:
                                raw_ostream &);
   virtual void mangleCXXVTT(const CXXRecordDecl *RD,
                             raw_ostream &);
+  virtual void mangleCXXVBTable(const CXXRecordDecl *Derived,
+                                ArrayRef<const CXXRecordDecl *> BasePath,
+                                raw_ostream &Out);
   virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
                                    const CXXRecordDecl *Type,
                                    raw_ostream &);
@@ -1757,24 +1760,41 @@ void MicrosoftMangleContext::mangleCXXDt
     "cannot mangle thunk for this destructor yet");
   getDiags().Report(DD->getLocation(), DiagID);
 }
+
 void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
                                              raw_ostream &Out) {
-  // <mangled-name> ::= ? <operator-name> <class-name> <storage-class>
-  //                      <cvr-qualifiers> [<name>] @
-  // <operator-name> ::= _7 # vftable
-  //                 ::= _8 # vbtable
+  // <mangled-name> ::= ?_7 <class-name> <storage-class>
+  //                    <cvr-qualifiers> [<name>] @
   // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
-  // is always '6' for vftables and '7' for vbtables. (The difference is
-  // beyond me.)
-  // TODO: vbtables.
+  // is always '6' for vftables.
   MicrosoftCXXNameMangler Mangler(*this, Out);
   Mangler.getStream() << "\01??_7";
   Mangler.mangleName(RD);
-  Mangler.getStream() << "6B";
+  Mangler.getStream() << "6B";  // '6' for vftable, 'B' for const.
   // TODO: If the class has more than one vtable, mangle in the class it came
   // from.
   Mangler.getStream() << '@';
 }
+
+void MicrosoftMangleContext::mangleCXXVBTable(
+    const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath,
+    raw_ostream &Out) {
+  // <mangled-name> ::= ?_8 <class-name> <storage-class>
+  //                    <cvr-qualifiers> [<name>] @
+  // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
+  // is always '7' for vbtables.
+  MicrosoftCXXNameMangler Mangler(*this, Out);
+  Mangler.getStream() << "\01??_8";
+  Mangler.mangleName(Derived);
+  Mangler.getStream() << "7B";  // '7' for vbtable, 'B' for const.
+  for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(),
+                                                 E = BasePath.end();
+       I != E; ++I) {
+    Mangler.mangleName(*I);
+  }
+  Mangler.getStream() << '@';
+}
+
 void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
                                           raw_ostream &) {
   llvm_unreachable("The MS C++ ABI does not have virtual table tables!");

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Wed Jun 19 10:20:38 2013
@@ -273,8 +273,9 @@ CharUnits CGCXXABI::getMemberPointerPath
   return ThisAdjustment;
 }
 
-llvm::BasicBlock *CGCXXABI::EmitCtorCompleteObjectHandler(
-                                                         CodeGenFunction &CGF) {
+llvm::BasicBlock *
+CGCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
+                                        const CXXRecordDecl *RD) {
   if (CGM.getTarget().getCXXABI().hasConstructorVariants())
     llvm_unreachable("shouldn't be called in this ABI");
 

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Wed Jun 19 10:20:38 2013
@@ -231,7 +231,8 @@ public:
                                          CanQualType &ResTy,
                                SmallVectorImpl<CanQualType> &ArgTys) = 0;
 
-  virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
+  virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
+                                                          const CXXRecordDecl *RD);
 
   /// Build the signature of the given destructor variant by adding
   /// any required parameters.  For convenience, ArgTys has been initialized
@@ -275,6 +276,13 @@ public:
                                            ReturnValueSlot ReturnValue,
                                            llvm::Value *This) = 0;
 
+  /// Emit any tables needed to implement virtual inheritance.  For Itanium,
+  /// this emits virtual table tables.  For the MSVC++ ABI, this emits virtual
+  /// base tables.
+  virtual void
+      EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
+                                   const CXXRecordDecl *RD) = 0;
+
   virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
                                    RValue RV, QualType ResultType);
 

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Jun 19 10:20:38 2013
@@ -1109,7 +1109,8 @@ void CodeGenFunction::EmitCtorPrologue(c
       !CGM.getTarget().getCXXABI().hasConstructorVariants()) {
     // The ABIs that don't have constructor variants need to put a branch
     // before the virtual base initialization code.
-    BaseCtorContinueBB = CGM.getCXXABI().EmitCtorCompleteObjectHandler(*this);
+    BaseCtorContinueBB =
+      CGM.getCXXABI().EmitCtorCompleteObjectHandler(*this, ClassDecl);
     assert(BaseCtorContinueBB);
   }
 

Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.cpp Wed Jun 19 10:20:38 2013
@@ -813,14 +813,8 @@ CodeGenVTables::GenerateClassData(const
   llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
   EmitVTableDefinition(VTable, Linkage, RD);
 
-  if (RD->getNumVBases()) {
-    if (!CGM.getTarget().getCXXABI().isMicrosoft()) {
-      llvm::GlobalVariable *VTT = GetAddrOfVTT(RD);
-      EmitVTTDefinition(VTT, Linkage, RD);
-    } else {
-      // FIXME: Emit vbtables here.
-    }
-  }
+  if (RD->getNumVBases())
+    CGM.getCXXABI().EmitVirtualInheritanceTables(Linkage, RD);
 
   // If this is the magic class __cxxabiv1::__fundamental_type_info,
   // we will emit the typeinfo for the fundamental types. This is the

Modified: cfe/trunk/lib/CodeGen/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CMakeLists.txt?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CMakeLists.txt (original)
+++ cfe/trunk/lib/CodeGen/CMakeLists.txt Wed Jun 19 10:20:38 2013
@@ -48,6 +48,7 @@ add_clang_library(clangCodeGen
   CodeGenTypes.cpp
   ItaniumCXXABI.cpp
   MicrosoftCXXABI.cpp
+  MicrosoftVBTables.cpp
   ModuleBuilder.cpp
   TargetInfo.cpp
   )

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Wed Jun 19 10:20:38 2013
@@ -135,6 +135,9 @@ public:
                                    ReturnValueSlot ReturnValue,
                                    llvm::Value *This);
 
+  void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
+                                    const CXXRecordDecl *RD);
+
   StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
   StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
 
@@ -841,6 +844,13 @@ RValue ItaniumCXXABI::EmitVirtualDestruc
                                /*ImplicitParam=*/0, QualType(), 0, 0);
 }
 
+void ItaniumCXXABI::EmitVirtualInheritanceTables(
+    llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) {
+  CodeGenVTables &VTables = CGM.getVTables();
+  llvm::GlobalVariable *VTT = VTables.GetAddrOfVTT(RD);
+  VTables.EmitVTTDefinition(VTT, Linkage, RD);
+}
+
 void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
                                     RValue RV, QualType ResultType) {
   if (!isa<CXXDestructorDecl>(CGF.CurGD.getDecl()))

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Wed Jun 19 10:20:38 2013
@@ -16,6 +16,8 @@
 
 #include "CGCXXABI.h"
 #include "CodeGenModule.h"
+#include "CGVTables.h"
+#include "MicrosoftVBTables.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 
@@ -60,7 +62,8 @@ public:
                                  CanQualType &ResTy,
                                  SmallVectorImpl<CanQualType> &ArgTys);
 
-  llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
+  llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
+                                                  const CXXRecordDecl *RD);
 
   void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
                                 CXXDtorType Type,
@@ -89,6 +92,9 @@ public:
                                    ReturnValueSlot ReturnValue,
                                    llvm::Value *This);
 
+  void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
+                                    const CXXRecordDecl *RD);
+
   void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
                        llvm::GlobalVariable *DeclPtr,
                        bool PerformInit);
@@ -184,6 +190,12 @@ private:
   bool MemberPointerConstantIsNull(const MemberPointerType *MPT,
                                    llvm::Constant *MP);
 
+  /// \brief - Initialize all vbptrs of 'this' with RD as the complete type.
+  void EmitVBPtrStores(CodeGenFunction &CGF, const CXXRecordDecl *RD);
+
+  /// \brief Caching wrapper around VBTableBuilder::enumerateVBTables().
+  const VBTableVector &EnumerateVBTables(const CXXRecordDecl *RD);
+
 public:
   virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
 
@@ -224,6 +236,9 @@ public:
                                   llvm::Value *MemPtr,
                                   const MemberPointerType *MPT);
 
+private:
+  /// VBTables - All the vbtables which have been referenced.
+  llvm::DenseMap<const CXXRecordDecl *, VBTableVector> VBTablesMap;
 };
 
 }
@@ -318,13 +333,14 @@ void MicrosoftCXXABI::BuildConstructorSi
   }
 }
 
-llvm::BasicBlock *MicrosoftCXXABI::EmitCtorCompleteObjectHandler(
-                                                         CodeGenFunction &CGF) {
+llvm::BasicBlock *
+MicrosoftCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
+                                               const CXXRecordDecl *RD) {
   llvm::Value *IsMostDerivedClass = getStructorImplicitParamValue(CGF);
   assert(IsMostDerivedClass &&
          "ctor for a class with virtual bases must have an implicit parameter");
-  llvm::Value *IsCompleteObject
-    = CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object");
+  llvm::Value *IsCompleteObject =
+    CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object");
 
   llvm::BasicBlock *CallVbaseCtorsBB = CGF.createBasicBlock("ctor.init_vbases");
   llvm::BasicBlock *SkipVbaseCtorsBB = CGF.createBasicBlock("ctor.skip_vbases");
@@ -332,13 +348,35 @@ llvm::BasicBlock *MicrosoftCXXABI::EmitC
                            CallVbaseCtorsBB, SkipVbaseCtorsBB);
 
   CGF.EmitBlock(CallVbaseCtorsBB);
-  // FIXME: emit vbtables somewhere around here.
+
+  // Fill in the vbtable pointers here.
+  EmitVBPtrStores(CGF, RD);
 
   // CGF will put the base ctor calls in this basic block for us later.
 
   return SkipVbaseCtorsBB;
 }
 
+void MicrosoftCXXABI::EmitVBPtrStores(CodeGenFunction &CGF,
+                                      const CXXRecordDecl *RD) {
+  llvm::Value *ThisInt8Ptr =
+    CGF.Builder.CreateBitCast(getThisValue(CGF), CGM.Int8PtrTy, "this.int8");
+
+  const VBTableVector &VBTables = EnumerateVBTables(RD);
+  for (VBTableVector::const_iterator I = VBTables.begin(), E = VBTables.end();
+       I != E; ++I) {
+    const ASTRecordLayout &SubobjectLayout =
+      CGM.getContext().getASTRecordLayout(I->VBPtrSubobject.getBase());
+    uint64_t Offs = (I->VBPtrSubobject.getBaseOffset() +
+                     SubobjectLayout.getVBPtrOffset()).getQuantity();
+    llvm::Value *VBPtr =
+        CGF.Builder.CreateConstInBoundsGEP1_64(ThisInt8Ptr, Offs);
+    VBPtr = CGF.Builder.CreateBitCast(VBPtr, I->GV->getType()->getPointerTo(0),
+                                      "vbptr." + I->ReusingBase->getName());
+    CGF.Builder.CreateStore(I->GV, VBPtr);
+  }
+}
+
 void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
                                                CXXDtorType Type,
                                                CanQualType &ResTy,
@@ -470,6 +508,31 @@ RValue MicrosoftCXXABI::EmitVirtualDestr
                                ImplicitParam, Context.BoolTy, 0, 0);
 }
 
+const VBTableVector &
+MicrosoftCXXABI::EnumerateVBTables(const CXXRecordDecl *RD) {
+  // At this layer, we can key the cache off of a single class, which is much
+  // easier than caching at the GlobalVariable layer.
+  llvm::DenseMap<const CXXRecordDecl*, VBTableVector>::iterator I;
+  bool added;
+  llvm::tie(I, added) = VBTablesMap.insert(std::make_pair(RD, VBTableVector()));
+  VBTableVector &VBTables = I->second;
+  if (!added)
+    return VBTables;
+
+  VBTableBuilder(CGM, RD).enumerateVBTables(VBTables);
+
+  return VBTables;
+}
+
+void MicrosoftCXXABI::EmitVirtualInheritanceTables(
+    llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) {
+  const VBTableVector &VBTables = EnumerateVBTables(RD);
+  for (VBTableVector::const_iterator I = VBTables.begin(), E = VBTables.end();
+       I != E; ++I) {
+    I->EmitVBTableDefinition(CGM, RD, Linkage);
+  }
+}
+
 bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
                                    QualType elementType) {
   // Microsoft seems to completely ignore the possibility of a

Added: cfe/trunk/lib/CodeGen/MicrosoftVBTables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftVBTables.cpp?rev=184309&view=auto
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftVBTables.cpp (added)
+++ cfe/trunk/lib/CodeGen/MicrosoftVBTables.cpp Wed Jun 19 10:20:38 2013
@@ -0,0 +1,236 @@
+//===--- MicrosoftVBTables.cpp - Virtual Base Table Emission --------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class generates data about MSVC virtual base tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MicrosoftVBTables.h"
+#include "CodeGenModule.h"
+#include "CGCXXABI.h"
+
+namespace clang {
+namespace CodeGen {
+
+/// Holds intermediate data about a path to a vbptr inside a base subobject.
+struct VBTablePath {
+  VBTablePath(const VBTableInfo &VBInfo)
+    : VBInfo(VBInfo), NextBase(VBInfo.VBPtrSubobject.getBase()) { }
+
+  /// All the data needed to build a vbtable, minus the GlobalVariable whose
+  /// name we haven't computed yet.
+  VBTableInfo VBInfo;
+
+  /// Next base to use for disambiguation.  Can be null if we've already
+  /// disambiguated this path once.
+  const CXXRecordDecl *NextBase;
+
+  /// Path is not really a full path like a CXXBasePath.  It holds the subset of
+  /// records that need to be mangled into the vbtable symbol name in order to get
+  /// a unique name.
+  llvm::SmallVector<const CXXRecordDecl *, 1> Path;
+};
+
+VBTableBuilder::VBTableBuilder(CodeGenModule &CGM,
+                               const CXXRecordDecl *MostDerived)
+    : CGM(CGM), MostDerived(MostDerived),
+      DerivedLayout(CGM.getContext().getASTRecordLayout(MostDerived)) {}
+
+void VBTableBuilder::enumerateVBTables(VBTableVector &VBTables) {
+  VBTablePathVector Paths;
+  findUnambiguousPaths(MostDerived, BaseSubobject(MostDerived,
+                                                  CharUnits::Zero()), Paths);
+  for (VBTablePathVector::iterator I = Paths.begin(), E = Paths.end();
+       I != E; ++I) {
+    VBTablePath *P = *I;
+    P->VBInfo.GV = getAddrOfVBTable(P->VBInfo.ReusingBase, P->Path);
+    VBTables.push_back(P->VBInfo);
+  }
+}
+
+bool VBTableBuilder::hasVBPtr(const CXXRecordDecl *RD) {
+  const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+  return Layout.getVBPtrOffset().getQuantity() != -1;
+}
+
+void VBTableBuilder::findUnambiguousPaths(const CXXRecordDecl *ReusingBase,
+                                          BaseSubobject CurSubobject,
+                                          VBTablePathVector &Paths) {
+  size_t PathsStart = Paths.size();
+  bool ReuseVBPtrFromBase = true;
+  const CXXRecordDecl *CurBase = CurSubobject.getBase();
+
+  // If this base has a vbptr, then we've found a path.  These are not full
+  // paths, so we don't use CXXBasePath.
+  if (hasVBPtr(CurBase)) {
+    ReuseVBPtrFromBase = false;
+    VBTablePath *Info = new VBTablePath(
+      VBTableInfo(ReusingBase, CurSubobject, /*GV=*/0));
+    Paths.push_back(Info);
+  }
+
+  // Recurse onto any bases which themselves have virtual bases.
+  const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(CurBase);
+  for (CXXRecordDecl::base_class_const_iterator I = CurBase->bases_begin(),
+       E = CurBase->bases_end(); I != E; ++I) {
+    const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
+    if (!Base->getNumVBases())
+      continue;  // Bases without virtual bases have no vbptrs.
+    CharUnits NextOffset;
+    const CXXRecordDecl *NextReusingBase = Base;
+    if (I->isVirtual()) {
+      if (!VBasesSeen.insert(Base))
+        continue;  // Don't visit virtual bases twice.
+      NextOffset = DerivedLayout.getVBaseClassOffset(Base);
+    } else {
+      NextOffset = (CurSubobject.getBaseOffset() +
+                    Layout.getBaseClassOffset(Base));
+
+      // If CurBase didn't have a vbptr, then ReusingBase will reuse the vbptr
+      // from the first non-virtual base with vbases for its vbptr.
+      if (ReuseVBPtrFromBase) {
+        NextReusingBase = ReusingBase;
+        ReuseVBPtrFromBase = false;
+      }
+    }
+
+    size_t NumPaths = Paths.size();
+    findUnambiguousPaths(NextReusingBase, BaseSubobject(Base, NextOffset),
+                         Paths);
+
+    // Tag paths through this base with the base itself.  We might use it to
+    // disambiguate.
+    for (size_t I = NumPaths, E = Paths.size(); I != E; ++I)
+      Paths[I]->NextBase = Base;
+  }
+
+  bool AmbiguousPaths = rebucketPaths(Paths, PathsStart);
+  if (AmbiguousPaths)
+    rebucketPaths(Paths, PathsStart, /*SecondPass=*/true);
+
+#ifndef NDEBUG
+  // Check that the paths are in fact unique.
+  for (size_t I = PathsStart + 1, E = Paths.size(); I != E; ++I) {
+    assert(Paths[I]->Path != Paths[I - 1]->Path && "vbtable paths are not unique");
+  }
+#endif
+}
+
+static bool pathCompare(VBTablePath *LHS, VBTablePath *RHS) {
+  return LHS->Path < RHS->Path;
+}
+
+void VBTableBuilder::extendPath(VBTablePath *P, bool SecondPass) {
+  assert(P->NextBase || SecondPass);
+  if (P->NextBase) {
+    P->Path.push_back(P->NextBase);
+    P->NextBase = 0;  // Prevent the path from being extended twice.
+  }
+}
+
+bool VBTableBuilder::rebucketPaths(VBTablePathVector &Paths, size_t PathsStart,
+                                   bool SecondPass) {
+  // What we're essentially doing here is bucketing together ambiguous paths.
+  // Any bucket with more than one path in it gets extended by NextBase, which
+  // is usually the direct base of the inherited the vbptr.  This code uses a
+  // sorted vector to implement a multiset to form the buckets.  Note that the
+  // ordering is based on pointers, but it doesn't change our output order.  The
+  // current algorithm is designed to match MSVC 2012's names.
+  // TODO: Implement MSVC 2010 or earlier names to avoid extra vbtable cruft.
+  VBTablePathVector PathsSorted(&Paths[PathsStart], &Paths.back() + 1);
+  std::sort(PathsSorted.begin(), PathsSorted.end(), pathCompare);
+  bool AmbiguousPaths = false;
+  for (size_t I = 0, E = PathsSorted.size(); I != E;) {
+    // Scan forward to find the end of the bucket.
+    size_t BucketStart = I;
+    do {
+      ++I;
+    } while (I != E && PathsSorted[BucketStart]->Path == PathsSorted[I]->Path);
+
+    // If this bucket has multiple paths, extend them all.
+    if (I - BucketStart > 1) {
+      AmbiguousPaths = true;
+      for (size_t II = BucketStart; II != I; ++II)
+        extendPath(PathsSorted[II], SecondPass);
+    }
+  }
+  return AmbiguousPaths;
+}
+
+llvm::GlobalVariable *
+VBTableBuilder::getAddrOfVBTable(const CXXRecordDecl *ReusingBase,
+                                 ArrayRef<const CXXRecordDecl *> BasePath) {
+  // Caching at this layer is redundant with the caching in EnumerateVBTables().
+
+  SmallString<256> OutName;
+  llvm::raw_svector_ostream Out(OutName);
+  MangleContext &Mangler = CGM.getCXXABI().getMangleContext();
+  Mangler.mangleCXXVBTable(MostDerived, BasePath, Out);
+  Out.flush();
+  StringRef Name = OutName.str();
+
+  llvm::ArrayType *VBTableType =
+    llvm::ArrayType::get(CGM.IntTy, 1 + ReusingBase->getNumVBases());
+
+  assert(!CGM.getModule().getNamedGlobal(Name) &&
+         "vbtable with this name already exists: mangling bug?");
+  llvm::GlobalVariable *VBTable =
+    CGM.CreateOrReplaceCXXRuntimeVariable(Name, VBTableType,
+                                          llvm::GlobalValue::ExternalLinkage);
+  VBTable->setUnnamedAddr(true);
+  return VBTable;
+}
+
+void VBTableInfo::EmitVBTableDefinition(
+    CodeGenModule &CGM, const CXXRecordDecl *RD,
+    llvm::GlobalVariable::LinkageTypes Linkage) const {
+  assert(RD->getNumVBases() && ReusingBase->getNumVBases() &&
+         "should only emit vbtables for classes with vbtables");
+
+  const ASTRecordLayout &BaseLayout =
+    CGM.getContext().getASTRecordLayout(VBPtrSubobject.getBase());
+  const ASTRecordLayout &DerivedLayout =
+    CGM.getContext().getASTRecordLayout(RD);
+
+  SmallVector<llvm::Constant *, 4> Offsets;
+
+  // The offset from ReusingBase's vbptr to itself always leads.
+  CharUnits VBPtrOffset = BaseLayout.getVBPtrOffset();
+  Offsets.push_back(
+      llvm::ConstantInt::get(CGM.IntTy, -VBPtrOffset.getQuantity()));
+
+  // These are laid out in the same order as in Itanium, which is the same as
+  // the order of the vbase iterator.
+  for (CXXRecordDecl::base_class_const_iterator I = ReusingBase->vbases_begin(),
+       E = ReusingBase->vbases_end(); I != E; ++I) {
+    const CXXRecordDecl *VBase = I->getType()->getAsCXXRecordDecl();
+    CharUnits Offset = DerivedLayout.getVBaseClassOffset(VBase);
+    assert(!Offset.isNegative());
+    // Make it relative to the subobject vbptr.
+    Offset -= VBPtrSubobject.getBaseOffset() + VBPtrOffset;
+    Offsets.push_back(llvm::ConstantInt::get(CGM.IntTy, Offset.getQuantity()));
+  }
+
+  assert(Offsets.size() ==
+         cast<llvm::ArrayType>(cast<llvm::PointerType>(GV->getType())
+                               ->getElementType())->getNumElements());
+  llvm::ArrayType *VBTableType =
+    llvm::ArrayType::get(CGM.IntTy, Offsets.size());
+  llvm::Constant *Init = llvm::ConstantArray::get(VBTableType, Offsets);
+  GV->setInitializer(Init);
+
+  // Set the correct linkage.
+  GV->setLinkage(Linkage);
+
+  // Set the right visibility.
+  CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForVTable);
+}
+
+} // namespace CodeGen
+} // namespace clang

Added: cfe/trunk/lib/CodeGen/MicrosoftVBTables.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftVBTables.h?rev=184309&view=auto
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftVBTables.h (added)
+++ cfe/trunk/lib/CodeGen/MicrosoftVBTables.h Wed Jun 19 10:20:38 2013
@@ -0,0 +1,129 @@
+//===--- MicrosoftVBTables.h - Virtual Base Table Emission ----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class generates data about MSVC virtual base tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/BaseSubobject.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/GlobalVariable.h"
+#include <vector>
+
+namespace clang {
+
+class ASTRecordLayout;
+
+namespace CodeGen {
+
+class CodeGenModule;
+
+struct VBTableInfo {
+  VBTableInfo(const CXXRecordDecl *ReusingBase, BaseSubobject VBPtrSubobject,
+              llvm::GlobalVariable *GV)
+    : ReusingBase(ReusingBase), VBPtrSubobject(VBPtrSubobject), GV(GV) { }
+
+  /// The vbtable will hold all of the virtual bases of ReusingBase.  This may
+  /// or may not be the same class as VBPtrSubobject.Base.  A derived class will
+  /// reuse the vbptr of the first non-virtual base subobject that has one.
+  const CXXRecordDecl *ReusingBase;
+
+  /// The vbptr is stored inside this subobject.
+  BaseSubobject VBPtrSubobject;
+
+  /// The GlobalVariable for this vbtable.
+  llvm::GlobalVariable *GV;
+
+  /// \brief Emits a definition for GV by setting it's initializer.
+  void EmitVBTableDefinition(CodeGenModule &CGM, const CXXRecordDecl *RD,
+                             llvm::GlobalVariable::LinkageTypes Linkage) const;
+};
+
+// These are embedded in a DenseMap and the elements are large, so we don't want
+// SmallVector.
+typedef std::vector<VBTableInfo> VBTableVector;
+
+struct VBTablePath;
+
+typedef llvm::SmallVector<VBTablePath *, 6> VBTablePathVector;
+
+/// Produces MSVC-compatible vbtable data.  The symbols produced by this builder
+/// match those produced by MSVC 2012, which is different from MSVC 2010.
+///
+/// Unlike Itanium, which uses only one vtable per class, MSVC uses a different
+/// symbol for every "address point" installed in base subobjects.  As a result,
+/// we have to compute unique symbols for every table.  Since there can be
+/// multiple non-virtual base subobjects of the same class, combining the most
+/// derived class with the base containing the vtable is insufficient.  The most
+/// trivial algorithm would be to mangle in the entire path from base to most
+/// derived, but that would be too easy and would create unnecessarily large
+/// symbols.  ;)
+///
+/// MSVC 2012 appears to minimize the vbtable names using the following
+/// algorithm.  First, walk the class hierarchy in the usual order, depth first,
+/// left to right, to find all of the subobjects which contain a vbptr field.
+/// Visiting each class node yields a list of inheritance paths to vbptrs.  Each
+/// record with a vbptr creates an initially empty path.
+///
+/// To combine paths from child nodes, the paths are compared to check for
+/// ambiguity.  Paths are "ambiguous" if multiple paths have the same set of
+/// components in the same order.  Each group of ambiguous paths is extended by
+/// appending the class of the base from which it came.  If the current class
+/// node produced an ambiguous path, its path is extended with the current class.
+/// After extending paths, MSVC again checks for ambiguity, and extends any
+/// ambiguous path which wasn't already extended.  Because each node yields an
+/// unambiguous set of paths, MSVC doesn't need to extend any path more than once
+/// to produce an unambiguous set of paths.
+///
+/// The VBTableBuilder class attempts to implement this algorithm by repeatedly
+/// bucketing paths together by sorting them.
+///
+/// TODO: Presumably vftables use the same algorithm.
+///
+/// TODO: Implement the MSVC 2010 name mangling scheme to avoid emitting
+/// duplicate vbtables with different symbols.
+class VBTableBuilder {
+public:
+  VBTableBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerived);
+
+  void enumerateVBTables(VBTableVector &VBTables);
+
+private:
+  bool hasVBPtr(const CXXRecordDecl *RD);
+
+  llvm::GlobalVariable *getAddrOfVBTable(const CXXRecordDecl *ReusingBase,
+                                      ArrayRef<const CXXRecordDecl *> BasePath);
+
+  /// Enumerates paths to bases with vbptrs.  The paths elements are compressed
+  /// to contain only the classes necessary to form an unambiguous path.
+  void findUnambiguousPaths(const CXXRecordDecl *ReusingBase,
+                            BaseSubobject CurSubobject,
+                            VBTablePathVector &Paths);
+
+  void extendPath(VBTablePath *Info, bool SecondPass);
+
+  bool rebucketPaths(VBTablePathVector &Paths, size_t PathsStart,
+                     bool SecondPass = false);
+
+  CodeGenModule &CGM;
+
+  const CXXRecordDecl *MostDerived;
+
+  /// Caches the layout of the most derived class.
+  const ASTRecordLayout &DerivedLayout;
+
+  /// Set of vbases to avoid re-visiting the same vbases.
+  llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen;
+};
+
+} // namespace CodeGen
+
+} // namespace clang

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp?rev=184309&r1=184308&r2=184309&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp Wed Jun 19 10:20:38 2013
@@ -154,6 +154,10 @@ C::C() {
   // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
   //
   // CHECK: [[INIT_VBASES]]
+  // CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::C"* %{{.*}} to i8*
+  // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
+  // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to [2 x i32]**
+  // CHECK-NEXT: store [2 x i32]* @"\01??_8C at constructors@@7B@", [2 x i32]** %[[vbptr]]
   // CHECK-NEXT: bitcast %"struct.constructors::C"* %{{.*}} to %"struct.constructors::A"*
   // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A at constructors@@QAE at XZ"(%"struct.constructors::A"* %{{.*}})
   // CHECK-NEXT: br label %[[SKIP_VBASES]]
@@ -182,6 +186,10 @@ D::D() {
   // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
   //
   // CHECK: [[INIT_VBASES]]
+  // CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::D"* %{{.*}} to i8*
+  // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
+  // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to [2 x i32]**
+  // CHECK-NEXT: store [2 x i32]* @"\01??_8D at constructors@@7B@", [2 x i32]** %[[vbptr]]
   // CHECK-NEXT: bitcast %"struct.constructors::D"* %{{.*}} to %"struct.constructors::A"*
   // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A at constructors@@QAE at XZ"(%"struct.constructors::A"* %{{.*}})
   // CHECK-NEXT: br label %[[SKIP_VBASES]]
@@ -203,6 +211,13 @@ E::E() {
   // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
   //
   // CHECK: [[INIT_VBASES]]
+  // CHECK-NEXT: %[[this_i8:.*]] = bitcast %"struct.constructors::E"* %{{.*}} to i8*
+  // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
+  // CHECK-NEXT: %[[vbptr_E:.*]] = bitcast i8* %[[offs]] to [3 x i32]**
+  // CHECK-NEXT: store [3 x i32]* @"\01??_8E at constructors@@7B01@@", [3 x i32]** %[[vbptr_E]]
+  // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 4
+  // CHECK-NEXT: %[[vbptr_C:.*]] = bitcast i8* %[[offs]] to [2 x i32]**
+  // CHECK-NEXT: store [2 x i32]* @"\01??_8E at constructors@@7BC at 1@@", [2 x i32]** %[[vbptr_C]]
   // CHECK-NEXT: bitcast %"struct.constructors::E"* %{{.*}} to %"struct.constructors::A"*
   // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A at constructors@@QAE at XZ"(%"struct.constructors::A"* %{{.*}})
   // CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C at constructors@@QAE at XZ"(%"struct.constructors::C"* %{{.*}}, i32 0)

Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-vbtables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-vbtables.cpp?rev=184309&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-vbtables.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-vbtables.cpp Wed Jun 19 10:20:38 2013
@@ -0,0 +1,436 @@
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o %t
+//
+// FIXME: These repeated FileCheck invocations are ugly, but I can't get the
+// output in source file order.  Can CHECK-DAG help here?
+// RUN: FileCheck --check-prefix=TEST1  %s < %t
+// RUN: FileCheck --check-prefix=TEST2  %s < %t
+// RUN: FileCheck --check-prefix=TEST3  %s < %t
+// RUN: FileCheck --check-prefix=TEST4  %s < %t
+// RUN: FileCheck --check-prefix=TEST5  %s < %t
+// RUN: FileCheck --check-prefix=TEST6  %s < %t
+// RUN: FileCheck --check-prefix=TEST7  %s < %t
+// RUN: FileCheck --check-prefix=TEST8  %s < %t
+// RUN: FileCheck --check-prefix=TEST9  %s < %t
+// RUN: FileCheck --check-prefix=TEST10 %s < %t
+// RUN: FileCheck --check-prefix=TEST11 %s < %t
+// RUN: FileCheck --check-prefix=TEST12 %s < %t
+// RUN: FileCheck --check-prefix=TEST13 %s < %t
+// RUN: FileCheck --check-prefix=TEST14 %s < %t
+// RUN: FileCheck --check-prefix=TEST15 %s < %t
+// RUN: FileCheck --check-prefix=TEST16 %s < %t
+// RUN: FileCheck --check-prefix=TEST17 %s < %t
+// RUN: FileCheck --check-prefix=TEST18 %s < %t
+// RUN: FileCheck --check-prefix=TEST19 %s < %t
+// RUN: FileCheck --check-prefix=TEST20 %s < %t
+// RUN: FileCheck --check-prefix=TEST21 %s < %t
+
+// See microsoft-abi-structors.cpp for constructor codegen tests.
+
+namespace Test1 {
+// Classic diamond, fully virtual.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual A { int c; };
+struct D : virtual B, virtual C { int d; };
+D d; // Force vbtable emission.
+
+// Layout should be:
+// D: vbptr D
+//    int d
+// A: int a
+// B: vbptr B
+//    int b
+// C: vbptr C
+//    int c
+
+// TEST1: @"\01??_8D at Test1@@7B01@@" = linkonce_odr unnamed_addr constant [4 x i32] [i32 0, i32 8, i32 12, i32 20]
+// TEST1: @"\01??_8D at Test1@@7BB at 1@@" = {{.*}} [2 x i32] [i32 0, i32 -4]
+// TEST1: @"\01??_8D at Test1@@7BC at 1@@" = {{.*}} [2 x i32] [i32 0, i32 -12]
+// TEST1: @"\01??_8C at Test1@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+// TEST1: @"\01??_8B at Test1@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test2 {
+// Classic diamond, only A is virtual.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual A { int c; };
+struct D : B, C { int d; };
+D d; // Force vbtable emission.
+
+// Layout should be:
+// B: vbptr B
+//    int b
+// C: vbptr C
+//    int c
+// D: int d
+// A: int a
+
+// TEST2: @"\01??_8D at Test2@@7BB at 1@@" = {{.*}} [2 x i32] [i32 0, i32 20]
+// TEST2: @"\01??_8D at Test2@@7BC at 1@@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// TEST2: @"\01??_8C at Test2@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+// TEST2: @"\01??_8B at Test2@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test3 {
+struct A { int a; };
+struct B { int b; };
+struct C : virtual A, virtual B { int c; };
+C c;
+
+// TEST3: @"\01??_8C at Test3@@7B@" = {{.*}} [3 x i32] [i32 0, i32 8, i32 12]
+}
+
+namespace Test4 {
+// Test reusing a vbptr from a non-virtual base.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B, virtual A { int c; };
+C c; // Force vbtable emission.
+
+// TEST4: @"\01??_8C at Test4@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// TEST4: @"\01??_8B at Test4@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test5 {
+// Test multiple base subobjects of the same type when that type has a virtual
+// base.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B { int c; };
+struct D : B, C { int d; };
+D d; // Force vbtable emission.
+
+// TEST5: @"\01??_8D at Test5@@7BB at 1@@"
+// TEST5: @"\01??_8D at Test5@@7BC at 1@@"
+// TEST5: @"\01??_8C at Test5@@7B@"
+// TEST5: @"\01??_8B at Test5@@7B@"
+}
+
+namespace Test6 {
+// Test that we skip unneeded base path component names.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B { int c; };
+struct D : B, C { int d; };
+struct E : D { int e; };
+struct F : E, B, C { int f; };
+struct G : F, virtual E { int g; };
+G g;
+
+// TEST6: @"\01??_8G at Test6@@7BB at 1@E at 1@F at 1@@" =
+// TEST6: @"\01??_8G at Test6@@7BC at 1@E at 1@F at 1@@" =
+// TEST6: @"\01??_8G at Test6@@7BB at 1@F at 1@@" =
+// TEST6: @"\01??_8G at Test6@@7BC at 1@F at 1@@" =
+// TEST6: @"\01??_8G at Test6@@7BB at 1@E at 1@@" =
+// TEST6: @"\01??_8G at Test6@@7BC at 1@E at 1@@" =
+// TEST6: @"\01??_8F at Test6@@7BB at 1@E at 1@@" = {{.*}} [2 x i32] [i32 0, i32 52]
+// TEST6: @"\01??_8F at Test6@@7BC at 1@E at 1@@" = {{.*}} [2 x i32] [i32 0, i32 44]
+// TEST6: @"\01??_8F at Test6@@7BB at 1@@" = {{.*}} [2 x i32] [i32 0, i32 24]
+// TEST6: @"\01??_8F at Test6@@7BC at 1@@" = {{.*}} [2 x i32] [i32 0, i32 16]
+// TEST6: @"\01??_8C at Test6@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// TEST6: @"\01??_8B at Test6@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+// TEST6: @"\01??_8E at Test6@@7BB at 1@@" = {{.*}} [2 x i32] [i32 0, i32 28]
+// TEST6: @"\01??_8E at Test6@@7BC at 1@@" = {{.*}} [2 x i32] [i32 0, i32 20]
+// TEST6: @"\01??_8D at Test6@@7BB at 1@@" = {{.*}} [2 x i32] [i32 0, i32 24]
+// TEST6: @"\01??_8D at Test6@@7BC at 1@@" = {{.*}} [2 x i32] [i32 0, i32 16]
+}
+
+namespace Test7 {
+// Test a non-virtual base which reuses the vbptr of another base.
+struct A { int a; };
+struct B { int b; };
+struct C { int c; };
+struct D : virtual A { int d; };
+struct E : B, D, virtual A, virtual C { int e; };
+E o;
+
+// TEST7: @"\01??_8E at Test7@@7B@" = {{.*}} [3 x i32] [i32 0, i32 12, i32 16]
+// TEST7: @"\01??_8D at Test7@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test8 {
+// Test a virtual base which reuses the vbptr of another base.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B { int c; };
+struct D : virtual C { int d; };
+D o;
+
+// TEST8: @"\01??_8D at Test8@@7B01@@" = {{.*}} [3 x i32] [i32 0, i32 8, i32 12]
+// TEST8: @"\01??_8D at Test8@@7BC at 1@@" = {{.*}} [2 x i32] [i32 0, i32 -4]
+// TEST8: @"\01??_8C at Test8@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// TEST8: @"\01??_8B at Test8@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test9 {
+// D has to add to B's vbtable because D has more morally virtual bases than B.
+// D then takes B's vbptr and the vbtable is named for D, not B.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; };
+struct BB : B { int bb; };  // Indirection =/
+struct D : BB, C { int d; };
+struct E : virtual D { };
+E e;
+
+// TEST9: @"\01??_8E at Test9@@7B01@@" =
+// TEST9: @"\01??_8E at Test9@@7BD at 1@@" =
+// TEST9: @"\01??_8E at Test9@@7BC at 1@@" =
+// TEST9: @"\01??_8E at Test9@@7BB at 1@@" =
+// TEST9: @"\01??_8D at Test9@@7B@" =
+// TEST9: @"\01??_8D at Test9@@7BC at 1@@" =
+// TEST9: @"\01??_8D at Test9@@7BB at 1@@" =
+// TEST9: @"\01??_8C at Test9@@7B01@@" =
+// TEST9: @"\01??_8C at Test9@@7BB at 1@@" =
+// TEST9: @"\01??_8BB at Test9@@7B@" =
+// TEST9: @"\01??_8B at Test9@@7B@" =
+}
+
+namespace Test10 {
+struct A { int a; };
+struct B { int b; };
+struct C : virtual A { int c; };
+struct D : B, C { int d; };
+D d;
+
+// TEST10: @"\01??_8D at Test10@@7B@" =
+// TEST10: @"\01??_8C at Test10@@7B@" =
+
+}
+
+namespace Test11 {
+// Typical diamond with an extra single inheritance indirection for B and C.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual A { int c; };
+struct D : B { int d; };
+struct E : C { int e; };
+struct F : D, E { int f; };
+F f;
+
+// TEST11: @"\01??_8F at Test11@@7BD at 1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 28]
+// TEST11: @"\01??_8F at Test11@@7BE at 1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 16]
+// TEST11: @"\01??_8E at Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 12]
+// TEST11: @"\01??_8C at Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+// TEST11: @"\01??_8D at Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 12]
+// TEST11: @"\01??_8B at Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+
+}
+
+namespace Test12 {
+// Another vbptr inside a virtual base.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; };
+struct D : C, B { int d; };
+struct E : D, C, B { int e; };
+E e;
+
+// TEST12: @"\01??_8E at Test12@@7BC at 1@D at 1@@" =
+// TEST12: @"\01??_8E at Test12@@7BB at 1@D at 1@@" =
+// TEST12: @"\01??_8E at Test12@@7BD at 1@@" =
+// TEST12: @"\01??_8E at Test12@@7BC at 1@@" =
+// TEST12: @"\01??_8E at Test12@@7BB at 1@@" =
+// TEST12: @"\01??_8C at Test12@@7B01@@" =
+// TEST12: @"\01??_8C at Test12@@7BB at 1@@" =
+// TEST12: @"\01??_8D at Test12@@7BC at 1@@" =
+// TEST12: @"\01??_8D at Test12@@7BB at 1@@" =
+// TEST12: @"\01??_8D at Test12@@7B@" =
+// TEST12: @"\01??_8B at Test12@@7B@" =
+}
+
+namespace Test13 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; };
+struct D : virtual C { int d; };
+struct E : D, C, B { int e; };
+E e;
+
+// TEST13: @"\01??_8E at Test13@@7BD at 1@@" =
+// TEST13: @"\01??_8E at Test13@@7BC at 1@D at 1@@" =
+// TEST13: @"\01??_8E at Test13@@7BB at 1@D at 1@@" =
+// TEST13: @"\01??_8E at Test13@@7BC at 1@@" =
+// TEST13: @"\01??_8E at Test13@@7BB at 1@@" =
+// TEST13: @"\01??_8D at Test13@@7B@" =
+// TEST13: @"\01??_8D at Test13@@7BC at 1@@" =
+// TEST13: @"\01??_8D at Test13@@7BB at 1@@" =
+// TEST13: @"\01??_8C at Test13@@7B01@@" =
+// TEST13: @"\01??_8C at Test13@@7BB at 1@@" =
+// TEST13: @"\01??_8B at Test13@@7B@" =
+}
+
+namespace Test14 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; };
+struct D : virtual C { int d; };
+struct E : D, virtual C, virtual B { int e; };
+E e;
+
+// TEST14: @"\01??_8E at Test14@@7B@" =
+// TEST14: @"\01??_8E at Test14@@7BC at 1@@" =
+// TEST14: @"\01??_8E at Test14@@7BB at 1@@" =
+// TEST14: @"\01??_8D at Test14@@7B@" =
+// TEST14: @"\01??_8D at Test14@@7BC at 1@@" =
+// TEST14: @"\01??_8D at Test14@@7BB at 1@@" =
+// TEST14: @"\01??_8C at Test14@@7B01@@" =
+// TEST14: @"\01??_8C at Test14@@7BB at 1@@" =
+// TEST14: @"\01??_8B at Test14@@7B@" =
+}
+
+namespace Test15 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual A { int c; };
+struct D : virtual B { int d; };
+struct E : D, C, B { int e; };
+E e;
+
+// TEST15: @"\01??_8E at Test15@@7BD at 1@@" =
+// TEST15: @"\01??_8E at Test15@@7BB at 1@D at 1@@" =
+// TEST15: @"\01??_8E at Test15@@7BC at 1@@" =
+// TEST15: @"\01??_8E at Test15@@7BB at 1@@" =
+// TEST15: @"\01??_8C at Test15@@7B@" =
+// TEST15: @"\01??_8D at Test15@@7B01@@" =
+// TEST15: @"\01??_8D at Test15@@7BB at 1@@" =
+// TEST15: @"\01??_8B at Test15@@7B@" =
+}
+
+namespace Test16 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; }; // ambig
+struct D : virtual C { int d; };
+struct E : virtual D { int e; }; // ambig
+struct F : E, D, C, B { int f; };  // ambig
+F f;
+
+// TEST16: @"\01??_8F at Test16@@7BE at 1@@" =
+// TEST16: @"\01??_8F at Test16@@7BD at 1@E at 1@@" =
+// TEST16: @"\01??_8F at Test16@@7BC at 1@E at 1@@" =
+// TEST16: @"\01??_8F at Test16@@7BB at 1@E at 1@@" =
+// TEST16: @"\01??_8F at Test16@@7BD at 1@@" =
+// TEST16: @"\01??_8F at Test16@@7BC at 1@@" =
+// TEST16: @"\01??_8F at Test16@@7BB at 1@@" =
+// TEST16: @"\01??_8E at Test16@@7B01@@" =
+// TEST16: @"\01??_8E at Test16@@7BD at 1@@" =
+// TEST16: @"\01??_8E at Test16@@7BC at 1@@" =
+// TEST16: @"\01??_8E at Test16@@7BB at 1@@" =
+// TEST16: @"\01??_8D at Test16@@7B@" =
+// TEST16: @"\01??_8D at Test16@@7BC at 1@@" =
+// TEST16: @"\01??_8D at Test16@@7BB at 1@@" =
+// TEST16: @"\01??_8C at Test16@@7B01@@" =
+// TEST16: @"\01??_8C at Test16@@7BB at 1@@" =
+// TEST16: @"\01??_8B at Test16@@7B@" =
+}
+
+namespace Test17 {
+// This test case has an interesting alternating pattern of using "vbtable of B"
+// and "vbtable of C for C".  This may be the key to the underlying algorithm.
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; }; // ambig
+struct D : virtual C { int d; };
+struct E : virtual D { int e; }; // ambig
+struct F : virtual E { int f; };
+struct G : virtual F { int g; }; // ambig
+struct H : virtual G { int h; };
+struct I : virtual H { int i; }; // ambig
+struct J : virtual I { int j; };
+struct K : virtual J { int k; }; // ambig
+K k;
+
+// TEST17: @"\01??_8K at Test17@@7B01@@" =
+// TEST17: @"\01??_8J at Test17@@7B@" =
+// TEST17: @"\01??_8I at Test17@@7B01@@" =
+// TEST17: @"\01??_8H at Test17@@7B@" =
+// TEST17: @"\01??_8G at Test17@@7B01@@" =
+// TEST17: @"\01??_8F at Test17@@7B@" =
+// TEST17: @"\01??_8E at Test17@@7B01@@" =
+// TEST17: @"\01??_8D at Test17@@7B@" =
+// TEST17: @"\01??_8C at Test17@@7B01@@" =
+// TEST17: @"\01??_8B at Test17@@7B@" =
+}
+
+namespace Test18 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B { int c; };
+struct D : C, B { int d; };
+struct E : D, C, B { int e; };
+E e;
+
+// TEST18: @"\01??_8E at Test18@@7BC at 1@D at 1@@" =
+// TEST18: @"\01??_8E at Test18@@7BB at 1@D at 1@@" =
+// TEST18: @"\01??_8E at Test18@@7BC at 1@@" =
+// TEST18: @"\01??_8E at Test18@@7BB at 1@@" =
+// TEST18: @"\01??_8B at Test18@@7B@" =
+// TEST18: @"\01??_8C at Test18@@7B@" =
+// TEST18: @"\01??_8D at Test18@@7BC at 1@@" =
+// TEST18: @"\01??_8D at Test18@@7BB at 1@@" =
+}
+
+namespace Test19 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : virtual B { int c; };
+struct D : virtual C, virtual B { int d; };
+struct E : virtual D, virtual C, virtual B { int e; };
+E e;
+
+// TEST19: @"\01??_8E at Test19@@7B01@@" =
+// TEST19: @"\01??_8E at Test19@@7BD at 1@@" =
+// TEST19: @"\01??_8E at Test19@@7BC at 1@@" =
+// TEST19: @"\01??_8E at Test19@@7BB at 1@@" =
+// TEST19: @"\01??_8D at Test19@@7B@" =
+// TEST19: @"\01??_8D at Test19@@7BC at 1@@" =
+// TEST19: @"\01??_8D at Test19@@7BB at 1@@" =
+// TEST19: @"\01??_8C at Test19@@7B01@@" =
+// TEST19: @"\01??_8C at Test19@@7BB at 1@@" =
+// TEST19: @"\01??_8B at Test19@@7B@" =
+}
+
+namespace Test20 {
+// E has no direct vbases, but it adds to C's vbtable anyway.
+struct A { int a; };
+struct B { int b; };
+struct C : virtual A { int c; };
+struct D : virtual B { int d; };
+struct E : C, D { int e; };
+E f;
+
+// TEST20: @"\01??_8E at Test20@@7BC at 1@@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 20, i32 24]
+// TEST20: @"\01??_8E at Test20@@7BD at 1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 16]
+// TEST20: @"\01??_8D at Test20@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+// TEST20: @"\01??_8C at Test20@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+}
+
+namespace Test21 {
+struct A { int a; };
+struct B : virtual A { int b; };
+struct C : B { int c; };
+struct D : B { int d; };
+struct E : C, D { int e; };
+struct F : virtual E { int f; };
+struct G : E { int g; };
+struct H : F, G { int h; };
+H h;
+
+// TEST21: @"\01??_8H at Test21@@7B@" =
+// TEST21: @"\01??_8H at Test21@@7BC at 1@F at 1@@" =
+// TEST21: @"\01??_8H at Test21@@7BD at 1@F at 1@@" =
+// TEST21: @"\01??_8H at Test21@@7BC at 1@G at 1@@" =
+// TEST21: @"\01??_8H at Test21@@7BD at 1@G at 1@@" =
+// TEST21: @"\01??_8G at Test21@@7BC at 1@@" =
+// TEST21: @"\01??_8G at Test21@@7BD at 1@@" =
+// TEST21: @"\01??_8F at Test21@@7B@" =
+// TEST21: @"\01??_8F at Test21@@7BC at 1@@" =
+// TEST21: @"\01??_8F at Test21@@7BD at 1@@" =
+// TEST21: @"\01??_8E at Test21@@7BC at 1@@" =
+// TEST21: @"\01??_8E at Test21@@7BD at 1@@" =
+// TEST21: @"\01??_8D at Test21@@7B@" =
+// TEST21: @"\01??_8B at Test21@@7B@" =
+// TEST21: @"\01??_8C at Test21@@7B@" =
+}





More information about the cfe-commits mailing list