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;
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 &);
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,
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 &);
"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!");
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");
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
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);
!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);
}
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
CodeGenTypes.cpp
ItaniumCXXABI.cpp
MicrosoftCXXABI.cpp
+ MicrosoftVBTables.cpp
ModuleBuilder.cpp
TargetInfo.cpp
)
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"; }
/*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()))
#include "CGCXXABI.h"
#include "CodeGenModule.h"
+#include "CGVTables.h"
+#include "MicrosoftVBTables.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
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,
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);
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);
llvm::Value *MemPtr,
const MemberPointerType *MPT);
+private:
+ /// VBTables - All the vbtables which have been referenced.
+ llvm::DenseMap<const CXXRecordDecl *, VBTableVector> VBTablesMap;
};
}
}
}
-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");
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,
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
--- /dev/null
+//===--- 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
--- /dev/null
+//===--- 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
// 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@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@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
// CHECK-NEXT: br label %[[SKIP_VBASES]]
// 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@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@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
// CHECK-NEXT: br label %[[SKIP_VBASES]]
// 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@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@constructors@@7BC@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@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
// CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %{{.*}}, i32 0)
--- /dev/null
+// 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@Test1@@7B01@@" = linkonce_odr unnamed_addr constant [4 x i32] [i32 0, i32 8, i32 12, i32 20]
+// TEST1: @"\01??_8D@Test1@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 -4]
+// TEST1: @"\01??_8D@Test1@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 -12]
+// TEST1: @"\01??_8C@Test1@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+// TEST1: @"\01??_8B@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@Test2@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 20]
+// TEST2: @"\01??_8D@Test2@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// TEST2: @"\01??_8C@Test2@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+// TEST2: @"\01??_8B@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@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@Test4@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// TEST4: @"\01??_8B@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@Test5@@7BB@1@@"
+// TEST5: @"\01??_8D@Test5@@7BC@1@@"
+// TEST5: @"\01??_8C@Test5@@7B@"
+// TEST5: @"\01??_8B@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@Test6@@7BB@1@E@1@F@1@@" =
+// TEST6: @"\01??_8G@Test6@@7BC@1@E@1@F@1@@" =
+// TEST6: @"\01??_8G@Test6@@7BB@1@F@1@@" =
+// TEST6: @"\01??_8G@Test6@@7BC@1@F@1@@" =
+// TEST6: @"\01??_8G@Test6@@7BB@1@E@1@@" =
+// TEST6: @"\01??_8G@Test6@@7BC@1@E@1@@" =
+// TEST6: @"\01??_8F@Test6@@7BB@1@E@1@@" = {{.*}} [2 x i32] [i32 0, i32 52]
+// TEST6: @"\01??_8F@Test6@@7BC@1@E@1@@" = {{.*}} [2 x i32] [i32 0, i32 44]
+// TEST6: @"\01??_8F@Test6@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 24]
+// TEST6: @"\01??_8F@Test6@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 16]
+// TEST6: @"\01??_8C@Test6@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// TEST6: @"\01??_8B@Test6@@7B@" = {{.*}} [2 x i32] [i32 0, i32 8]
+// TEST6: @"\01??_8E@Test6@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 28]
+// TEST6: @"\01??_8E@Test6@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 20]
+// TEST6: @"\01??_8D@Test6@@7BB@1@@" = {{.*}} [2 x i32] [i32 0, i32 24]
+// TEST6: @"\01??_8D@Test6@@7BC@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@Test7@@7B@" = {{.*}} [3 x i32] [i32 0, i32 12, i32 16]
+// TEST7: @"\01??_8D@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@Test8@@7B01@@" = {{.*}} [3 x i32] [i32 0, i32 8, i32 12]
+// TEST8: @"\01??_8D@Test8@@7BC@1@@" = {{.*}} [2 x i32] [i32 0, i32 -4]
+// TEST8: @"\01??_8C@Test8@@7B@" = {{.*}} [2 x i32] [i32 0, i32 12]
+// TEST8: @"\01??_8B@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@Test9@@7B01@@" =
+// TEST9: @"\01??_8E@Test9@@7BD@1@@" =
+// TEST9: @"\01??_8E@Test9@@7BC@1@@" =
+// TEST9: @"\01??_8E@Test9@@7BB@1@@" =
+// TEST9: @"\01??_8D@Test9@@7B@" =
+// TEST9: @"\01??_8D@Test9@@7BC@1@@" =
+// TEST9: @"\01??_8D@Test9@@7BB@1@@" =
+// TEST9: @"\01??_8C@Test9@@7B01@@" =
+// TEST9: @"\01??_8C@Test9@@7BB@1@@" =
+// TEST9: @"\01??_8BB@Test9@@7B@" =
+// TEST9: @"\01??_8B@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@Test10@@7B@" =
+// TEST10: @"\01??_8C@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@Test11@@7BD@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 28]
+// TEST11: @"\01??_8F@Test11@@7BE@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 16]
+// TEST11: @"\01??_8E@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 12]
+// TEST11: @"\01??_8C@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+// TEST11: @"\01??_8D@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 12]
+// TEST11: @"\01??_8B@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@Test12@@7BC@1@D@1@@" =
+// TEST12: @"\01??_8E@Test12@@7BB@1@D@1@@" =
+// TEST12: @"\01??_8E@Test12@@7BD@1@@" =
+// TEST12: @"\01??_8E@Test12@@7BC@1@@" =
+// TEST12: @"\01??_8E@Test12@@7BB@1@@" =
+// TEST12: @"\01??_8C@Test12@@7B01@@" =
+// TEST12: @"\01??_8C@Test12@@7BB@1@@" =
+// TEST12: @"\01??_8D@Test12@@7BC@1@@" =
+// TEST12: @"\01??_8D@Test12@@7BB@1@@" =
+// TEST12: @"\01??_8D@Test12@@7B@" =
+// TEST12: @"\01??_8B@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@Test13@@7BD@1@@" =
+// TEST13: @"\01??_8E@Test13@@7BC@1@D@1@@" =
+// TEST13: @"\01??_8E@Test13@@7BB@1@D@1@@" =
+// TEST13: @"\01??_8E@Test13@@7BC@1@@" =
+// TEST13: @"\01??_8E@Test13@@7BB@1@@" =
+// TEST13: @"\01??_8D@Test13@@7B@" =
+// TEST13: @"\01??_8D@Test13@@7BC@1@@" =
+// TEST13: @"\01??_8D@Test13@@7BB@1@@" =
+// TEST13: @"\01??_8C@Test13@@7B01@@" =
+// TEST13: @"\01??_8C@Test13@@7BB@1@@" =
+// TEST13: @"\01??_8B@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@Test14@@7B@" =
+// TEST14: @"\01??_8E@Test14@@7BC@1@@" =
+// TEST14: @"\01??_8E@Test14@@7BB@1@@" =
+// TEST14: @"\01??_8D@Test14@@7B@" =
+// TEST14: @"\01??_8D@Test14@@7BC@1@@" =
+// TEST14: @"\01??_8D@Test14@@7BB@1@@" =
+// TEST14: @"\01??_8C@Test14@@7B01@@" =
+// TEST14: @"\01??_8C@Test14@@7BB@1@@" =
+// TEST14: @"\01??_8B@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@Test15@@7BD@1@@" =
+// TEST15: @"\01??_8E@Test15@@7BB@1@D@1@@" =
+// TEST15: @"\01??_8E@Test15@@7BC@1@@" =
+// TEST15: @"\01??_8E@Test15@@7BB@1@@" =
+// TEST15: @"\01??_8C@Test15@@7B@" =
+// TEST15: @"\01??_8D@Test15@@7B01@@" =
+// TEST15: @"\01??_8D@Test15@@7BB@1@@" =
+// TEST15: @"\01??_8B@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@Test16@@7BE@1@@" =
+// TEST16: @"\01??_8F@Test16@@7BD@1@E@1@@" =
+// TEST16: @"\01??_8F@Test16@@7BC@1@E@1@@" =
+// TEST16: @"\01??_8F@Test16@@7BB@1@E@1@@" =
+// TEST16: @"\01??_8F@Test16@@7BD@1@@" =
+// TEST16: @"\01??_8F@Test16@@7BC@1@@" =
+// TEST16: @"\01??_8F@Test16@@7BB@1@@" =
+// TEST16: @"\01??_8E@Test16@@7B01@@" =
+// TEST16: @"\01??_8E@Test16@@7BD@1@@" =
+// TEST16: @"\01??_8E@Test16@@7BC@1@@" =
+// TEST16: @"\01??_8E@Test16@@7BB@1@@" =
+// TEST16: @"\01??_8D@Test16@@7B@" =
+// TEST16: @"\01??_8D@Test16@@7BC@1@@" =
+// TEST16: @"\01??_8D@Test16@@7BB@1@@" =
+// TEST16: @"\01??_8C@Test16@@7B01@@" =
+// TEST16: @"\01??_8C@Test16@@7BB@1@@" =
+// TEST16: @"\01??_8B@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@Test17@@7B01@@" =
+// TEST17: @"\01??_8J@Test17@@7B@" =
+// TEST17: @"\01??_8I@Test17@@7B01@@" =
+// TEST17: @"\01??_8H@Test17@@7B@" =
+// TEST17: @"\01??_8G@Test17@@7B01@@" =
+// TEST17: @"\01??_8F@Test17@@7B@" =
+// TEST17: @"\01??_8E@Test17@@7B01@@" =
+// TEST17: @"\01??_8D@Test17@@7B@" =
+// TEST17: @"\01??_8C@Test17@@7B01@@" =
+// TEST17: @"\01??_8B@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@Test18@@7BC@1@D@1@@" =
+// TEST18: @"\01??_8E@Test18@@7BB@1@D@1@@" =
+// TEST18: @"\01??_8E@Test18@@7BC@1@@" =
+// TEST18: @"\01??_8E@Test18@@7BB@1@@" =
+// TEST18: @"\01??_8B@Test18@@7B@" =
+// TEST18: @"\01??_8C@Test18@@7B@" =
+// TEST18: @"\01??_8D@Test18@@7BC@1@@" =
+// TEST18: @"\01??_8D@Test18@@7BB@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@Test19@@7B01@@" =
+// TEST19: @"\01??_8E@Test19@@7BD@1@@" =
+// TEST19: @"\01??_8E@Test19@@7BC@1@@" =
+// TEST19: @"\01??_8E@Test19@@7BB@1@@" =
+// TEST19: @"\01??_8D@Test19@@7B@" =
+// TEST19: @"\01??_8D@Test19@@7BC@1@@" =
+// TEST19: @"\01??_8D@Test19@@7BB@1@@" =
+// TEST19: @"\01??_8C@Test19@@7B01@@" =
+// TEST19: @"\01??_8C@Test19@@7BB@1@@" =
+// TEST19: @"\01??_8B@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@Test20@@7BC@1@@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 20, i32 24]
+// TEST20: @"\01??_8E@Test20@@7BD@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 16]
+// TEST20: @"\01??_8D@Test20@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
+// TEST20: @"\01??_8C@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@Test21@@7B@" =
+// TEST21: @"\01??_8H@Test21@@7BC@1@F@1@@" =
+// TEST21: @"\01??_8H@Test21@@7BD@1@F@1@@" =
+// TEST21: @"\01??_8H@Test21@@7BC@1@G@1@@" =
+// TEST21: @"\01??_8H@Test21@@7BD@1@G@1@@" =
+// TEST21: @"\01??_8G@Test21@@7BC@1@@" =
+// TEST21: @"\01??_8G@Test21@@7BD@1@@" =
+// TEST21: @"\01??_8F@Test21@@7B@" =
+// TEST21: @"\01??_8F@Test21@@7BC@1@@" =
+// TEST21: @"\01??_8F@Test21@@7BD@1@@" =
+// TEST21: @"\01??_8E@Test21@@7BC@1@@" =
+// TEST21: @"\01??_8E@Test21@@7BD@1@@" =
+// TEST21: @"\01??_8D@Test21@@7B@" =
+// TEST21: @"\01??_8B@Test21@@7B@" =
+// TEST21: @"\01??_8C@Test21@@7B@" =
+}