From: Mike Stump Date: Fri, 14 Aug 2009 01:44:03 +0000 (+0000) Subject: Deconflate virtual base offsets from non-virtual base offsets. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=215389180617e4edb8aa95a5526509948ed1416f;p=clang Deconflate virtual base offsets from non-virtual base offsets. Deconflate a virtual base primary from a non-virtual base. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78971 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index 68287a3b70..77e8553d74 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -60,10 +60,12 @@ class ASTRecordLayout { bool PrimaryBaseWasVirtual; /// BaseOffsets - Contains a map from base classes to their offset. - /// FIXME: Does it make sense to store offsets for virtual base classes - /// here? /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) llvm::DenseMap BaseOffsets; + + /// VBaseOffsets - Contains a map from vbase classes to their offset. + /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) + llvm::DenseMap VBaseOffsets; }; /// CXXInfo - If the record layout is for a C++ record, this will have @@ -90,7 +92,8 @@ class ASTRecordLayout { uint64_t nonvirtualsize, unsigned nonvirtualalign, const CXXRecordDecl *PB, bool PBVirtual, const CXXRecordDecl **bases, const uint64_t *baseoffsets, - unsigned basecount) + unsigned basecount, const CXXRecordDecl **vbases, + const uint64_t *vbaseoffsets,unsigned vbasecount) : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) { if (FieldCount > 0) { @@ -105,6 +108,8 @@ class ASTRecordLayout { CXXInfo->NonVirtualAlign = nonvirtualalign; for (unsigned i = 0; i != basecount; ++i) CXXInfo->BaseOffsets[bases[i]] = baseoffsets[i]; + for (unsigned i = 0; i != vbasecount; ++i) + CXXInfo->VBaseOffsets[vbases[i]] = vbaseoffsets[i]; } ~ASTRecordLayout() { @@ -174,6 +179,14 @@ public: return CXXInfo->BaseOffsets[Base]; } + + /// getVBaseClassOffset - Get the offset, in bits, for the given base class. + uint64_t getVBaseClassOffset(const CXXRecordDecl *VBase) const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!"); + + return CXXInfo->VBaseOffsets[VBase]; + } }; } // end namespace clang diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 9c56121ee1..a53c16fba1 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -51,8 +51,8 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); // Skip the PrimaryBase here, as it is laid down first. - if (Base != PrimaryBase) - LayoutBaseNonVirtually(Base); + if (Base != PrimaryBase || PrimaryBaseWasVirtual) + LayoutBaseNonVirtually(Base, false); } } } @@ -77,9 +77,10 @@ void ASTRecordLayoutBuilder::SelectPrimaryForBase(const CXXRecordDecl *RD, const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - if (PrimaryBaseWasVirtual) { + + if (PrimaryBaseWasVirtual) IndirectPrimary.insert(PrimaryBase); - } + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = @@ -163,7 +164,7 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD, } void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { - LayoutBaseNonVirtually(RD); + LayoutBaseNonVirtually(RD, true); } void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, @@ -182,7 +183,8 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, } } -void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD) { +void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD, + bool IsVirtualBase) { const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); assert(BaseInfo.getDataSize() > 0 && "FIXME: Handle empty classes."); @@ -193,9 +195,14 @@ void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD) { // Round up the current record size to the base's alignment boundary. Size = (Size + (BaseAlign-1)) & ~(BaseAlign-1); - // Add base class offsets. - Bases.push_back(RD); - BaseOffsets.push_back(Size); + // Add base class offsets. + if (IsVirtualBase) { + VBases.push_back(RD); + VBaseOffsets.push_back(Size); + } else { + Bases.push_back(RD); + BaseOffsets.push_back(Size); + } // Reserve space for this base. Size += BaseSize; @@ -229,7 +236,7 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { if (PrimaryBase) { if (PrimaryBaseWasVirtual) IndirectPrimary.insert(PrimaryBase); - LayoutBaseNonVirtually(PrimaryBase); + LayoutBaseNonVirtually(PrimaryBase, PrimaryBaseWasVirtual); } LayoutNonVirtualBases(RD); } @@ -406,6 +413,8 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, assert(Builder.Bases.size() == Builder.BaseOffsets.size() && "Base offsets vector must be same size as bases vector!"); + assert(Builder.VBases.size() == Builder.VBaseOffsets.size() && + "Base offsets vector must be same size as bases vector!"); // FIXME: This should be done in FinalizeLayout. uint64_t DataSize = @@ -422,7 +431,10 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, Builder.PrimaryBaseWasVirtual, Builder.Bases.data(), Builder.BaseOffsets.data(), - Builder.Bases.size()); + Builder.Bases.size(), + Builder.VBases.data(), + Builder.VBaseOffsets.data(), + Builder.VBases.size()); } const ASTRecordLayout * diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index 24a185c8ab..4447fff781 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -42,6 +42,9 @@ class ASTRecordLayoutBuilder { llvm::SmallVector Bases; llvm::SmallVector BaseOffsets; + + llvm::SmallVector VBases; + llvm::SmallVector VBaseOffsets; ASTRecordLayoutBuilder(ASTContext &Ctx); @@ -68,7 +71,7 @@ class ASTRecordLayoutBuilder { void LayoutVtable(const CXXRecordDecl *RD, llvm::SmallSet &IndirectPrimary); void LayoutNonVirtualBases(const CXXRecordDecl *RD); - void LayoutBaseNonVirtually(const CXXRecordDecl *RD); + void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase); void LayoutVirtualBase(const CXXRecordDecl *RD); void LayoutVirtualBases(const CXXRecordDecl *RD, llvm::SmallSet &IndirectPrimary); diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 4460a254b7..04da0ee175 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -703,6 +703,7 @@ void CodeGenFunction::GenerateVtableForBase(const CXXRecordDecl *RD, if (isPrimary) { // The virtual base offsets come first... + // FIXME: audit for (CXXRecordDecl::reverse_base_class_const_iterator i = Class->bases_rbegin(), e = Class->bases_rend(); i != e; ++i) { @@ -710,7 +711,7 @@ void CodeGenFunction::GenerateVtableForBase(const CXXRecordDecl *RD, continue; const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); - int64_t BaseOffset = Layout.getBaseClassOffset(Base) / 8; + int64_t BaseOffset = Layout.getVBaseClassOffset(Base) / 8; llvm::Constant *m; m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), BaseOffset); m = llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty); @@ -741,7 +742,11 @@ void CodeGenFunction::GenerateVtableForBase(const CXXRecordDecl *RD, if (TopPrimary) { if (RD) { - int64_t BaseOffset = -(Layout.getBaseClassOffset(RD) / 8); + int64_t BaseOffset; + if (ForVirtualBase) + BaseOffset = -(Layout.getVBaseClassOffset(RD) / 8); + else + BaseOffset = -(Layout.getBaseClassOffset(RD) / 8); m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), BaseOffset); m = llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty); } @@ -784,13 +789,15 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { // The primary base comes first. GenerateVtableForBase(PrimaryBase, RD, rtti, methods, true, PrimaryBaseWasVirtual, IndirectPrimary); + + // Then come the non-virtual bases. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { if (i->isVirtual()) continue; const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); - if (Base != PrimaryBase) + if (Base != PrimaryBase || PrimaryBaseWasVirtual) GenerateVtableForBase(Base, RD, rtti, methods, false, false, IndirectPrimary); }