diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/RecordLayoutBuilder.cpp | 120 | ||||
-rw-r--r-- | clang/lib/AST/RecordLayoutBuilder.h | 8 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCXX.cpp | 47 |
3 files changed, 156 insertions, 19 deletions
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 901d5a5b26f..10295f18835 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/TargetInfo.h" +#include <llvm/ADT/SmallSet.h> #include <llvm/Support/MathExtras.h> using namespace clang; @@ -25,14 +26,17 @@ ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {} void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) { - if (RD->isPolymorphic() || RD->getNumVBases()) - { - // assert (RD->getNumBases() == 0 && "no polymorphic inheritance yet"); - int AS = 0; - UpdateAlignment(Ctx.Target.getPointerAlign(AS)); - Size += Ctx.Target.getPointerWidth(AS); - NextOffset = Size; - } + // FIXME: audit indirect virtual bases + if (!RD->isPolymorphic() && !RD->getNumVBases()) + return; + + SelectPrimaryBase(RD); + if (PrimaryBase == 0) { + int AS = 0; + UpdateAlignment(Ctx.Target.getPointerAlign(AS)); + Size += Ctx.Target.getPointerWidth(AS); + NextOffset = Size; + } } void @@ -47,6 +51,104 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { } } +// Helper routines related to the abi definition from: +// http://www.codesourcery.com/public/cxx-abi/abi.html +// +/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but +/// no other data. +bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) { + // FIXME: Audit the corners + if (!RD->isDynamicClass()) + return false; + const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); + if (BaseInfo.getNonVirtualSize() == Ctx.Target.getPointerWidth(0)) + return true; + return false; +} + +void ASTRecordLayoutBuilder::SelectPrimaryForBase(const CXXRecordDecl *RD, + llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (!i->isVirtual()) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + // Only bases with virtual bases participate in computing the + // indirect primary base classes. + // FIXME: audit indirect virtual bases + if (Base->getNumVBases() == 0) + return; + // FIXME: This information is recomputed a whole lot, cache it instead. + SelectPrimaryBase(Base); + IndirectPrimary.insert(PrimaryBase); + SelectPrimaryForBase(Base, IndirectPrimary); + } + } +} + +/// SelectPrimaryBase - Selects the primary base for the given class and +/// records that with setPrimaryBase. +void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { + // The primary base is the first non-virtual indirect or direct base class, + // if one exists. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (!i->isVirtual()) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (Base->isDynamicClass()) { + setPrimaryBase(Base); + return; + } + } + } + + // Otherwise, it is the first nearly empty virtual base that is not an + // indirect primary base class, if one exists. + + // If we have no virtual bases at this point, bail out as the searching below + // is expensive. + // FIXME: audit indirect virtual bases + if (RD->getNumVBases() == 0) { + setPrimaryBase(0); + return; + } + + // First, we compute all the primary bases for all of out direct and indirect + // non-virtual bases, and record all their primary base classes. + const CXXRecordDecl *FirstPrimary = 0; + llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimary; + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (!i->isVirtual()) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + SelectPrimaryForBase(Base, IndirectPrimary); + } + } + + // Then we can search for the first nearly empty virtual base itself. + // FIXME: audit indirect virtual bases + for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(), + e = RD->vbases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (IsNearlyEmpty(Base)) { + if (FirstPrimary==0) + FirstPrimary = Base; + if (!IndirectPrimary.count(Base)) { + setPrimaryBase(Base); + return; + } + } + } + + // Otherwise if is the first nearly empty base, if one exists, otherwise + // there is no primary base class. + setPrimaryBase(FirstPrimary); + return; +} + void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) { const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); assert(BaseInfo.getDataSize() > 0 && @@ -86,6 +188,7 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { LayoutVtable(RD); LayoutNonVirtualBases(RD); + // FIXME: audit indirect virtual bases assert (RD->getNumVBases() == 0 && "FIXME: We don't support virtual bases yet!"); // FIXME: We need to layout the virtual bases in the complete object layout. @@ -277,6 +380,7 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, Builder.FieldOffsets.size(), NonVirtualSize, Builder.NonVirtualAlignment, + Builder.PrimaryBase, Builder.Bases.data(), Builder.BaseOffsets.data(), Builder.Bases.size()); diff --git a/clang/lib/AST/RecordLayoutBuilder.h b/clang/lib/AST/RecordLayoutBuilder.h index e21536077a5..a6c9c5e873d 100644 --- a/clang/lib/AST/RecordLayoutBuilder.h +++ b/clang/lib/AST/RecordLayoutBuilder.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/Support/DataTypes.h" namespace clang { @@ -35,6 +36,8 @@ class ASTRecordLayoutBuilder { uint64_t NonVirtualSize; unsigned NonVirtualAlignment; + const CXXRecordDecl *PrimaryBase; + llvm::SmallVector<const CXXRecordDecl *, 4> Bases; llvm::SmallVector<uint64_t, 4> BaseOffsets; @@ -48,6 +51,11 @@ class ASTRecordLayoutBuilder { void LayoutFields(const RecordDecl *D); void LayoutField(const FieldDecl *D); + void SelectPrimaryBase(const CXXRecordDecl *RD); + void SelectPrimaryForBase(const CXXRecordDecl *RD, + llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary); + void setPrimaryBase(const CXXRecordDecl *PB) { PrimaryBase = PB; } + bool IsNearlyEmpty(const CXXRecordDecl *RD); void LayoutVtable(const CXXRecordDecl *RD); void LayoutNonVirtualBases(const CXXRecordDecl *RD); void LayoutNonVirtualBase(const CXXRecordDecl *RD); diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index 97937ea89a1..375c9ac40e4 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -540,9 +540,12 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { llvm::Type *Ptr8Ty; Ptr8Ty = llvm::PointerType::get(llvm::Type::Int8Ty, 0); m = llvm::Constant::getNullValue(Ptr8Ty); - int64_t offset = 0; - methods.push_back(m); offset += LLVMPointerWidth; - methods.push_back(GenerateRtti(RD)); offset += LLVMPointerWidth; + int64_t Offset = 0; + methods.push_back(m); Offset += LLVMPointerWidth; + methods.push_back(GenerateRtti(RD)); Offset += LLVMPointerWidth; + + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { @@ -550,6 +553,16 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { continue; const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (PrimaryBase != Base) { + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); + int64_t BaseOffset = -(Layout.getBaseClassOffset(Base) / 8); + m = llvm::ConstantInt::get(llvm::Type::Int64Ty, BaseOffset); + m = llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty); + methods.push_back(m); + // FIXME: GenerateRtti for Base in RD. + m = llvm::Constant::getNullValue(Ptr8Ty); + methods.push_back(m); + } for (meth_iter mi = Base->method_begin(), me = Base->method_end(); mi != me; ++mi) { if (mi->isVirtual()) { @@ -558,16 +571,28 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { methods.push_back(m); } } + if (PrimaryBase == Base) { + for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; + ++mi) { + if (mi->isVirtual()) { + m = CGM.GetAddrOfFunction(GlobalDecl(*mi)); + m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty); + methods.push_back(m); + } + } + } } - - for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; - ++mi) { - if (mi->isVirtual()) { - m = CGM.GetAddrOfFunction(GlobalDecl(*mi)); - m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty); - methods.push_back(m); + if (PrimaryBase == 0) { + for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; + ++mi) { + if (mi->isVirtual()) { + m = CGM.GetAddrOfFunction(GlobalDecl(*mi)); + m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty); + methods.push_back(m); + } } } + llvm::Constant *C; llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size()); C = llvm::ConstantArray::get(type, methods); @@ -577,7 +602,7 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { // FIXME: finish layout for virtual bases vtable = Builder.CreateGEP(vtable, llvm::ConstantInt::get(llvm::Type::Int64Ty, - offset/8)); + Offset/8)); return vtable; } |