forked from OSchip/llvm-project
Don't build the entire vtable when all we want is the index of a virtual method.
llvm-svn: 90017
This commit is contained in:
parent
4ee17e1482
commit
f942ee0297
|
@ -1055,7 +1055,7 @@ CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
|
||||||
return VBaseOffset;
|
return VBaseOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, int64_t VtableIndex,
|
static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex,
|
||||||
llvm::Value *This, const llvm::Type *Ty) {
|
llvm::Value *This, const llvm::Type *Ty) {
|
||||||
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
|
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
|
||||||
|
|
||||||
|
@ -1071,7 +1071,7 @@ llvm::Value *
|
||||||
CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
|
CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
|
||||||
const llvm::Type *Ty) {
|
const llvm::Type *Ty) {
|
||||||
MD = MD->getCanonicalDecl();
|
MD = MD->getCanonicalDecl();
|
||||||
int64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD);
|
uint64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD);
|
||||||
|
|
||||||
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
|
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
|
||||||
}
|
}
|
||||||
|
@ -1080,7 +1080,7 @@ llvm::Value *
|
||||||
CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
|
CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
|
||||||
llvm::Value *&This, const llvm::Type *Ty) {
|
llvm::Value *&This, const llvm::Type *Ty) {
|
||||||
DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
|
DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
|
||||||
int64_t VtableIndex =
|
uint64_t VtableIndex =
|
||||||
CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type));
|
CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type));
|
||||||
|
|
||||||
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
|
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
|
||||||
|
|
|
@ -413,9 +413,10 @@ public:
|
||||||
|
|
||||||
// Get the function pointer (or index if this is a virtual function).
|
// Get the function pointer (or index if this is a virtual function).
|
||||||
if (MD->isVirtual()) {
|
if (MD->isVirtual()) {
|
||||||
int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
|
uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
|
||||||
|
|
||||||
Values[0] = llvm::ConstantInt::get(PtrDiffTy, Index + 1);
|
// The pointer is 1 + the virtual table offset in bytes.
|
||||||
|
Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1);
|
||||||
} else {
|
} else {
|
||||||
llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD);
|
llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD);
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "CodeGenModule.h"
|
#include "CodeGenModule.h"
|
||||||
#include "CodeGenFunction.h"
|
#include "CodeGenFunction.h"
|
||||||
|
|
||||||
|
#include "clang/AST/CXXInheritance.h"
|
||||||
#include "clang/AST/RecordLayout.h"
|
#include "clang/AST/RecordLayout.h"
|
||||||
#include "llvm/ADT/DenseSet.h"
|
#include "llvm/ADT/DenseSet.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -781,23 +782,242 @@ VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D,
|
||||||
return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
|
return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
|
/// TypeConversionRequiresAdjustment - Returns whether conversion from a
|
||||||
|
/// derived type to a base type requires adjustment.
|
||||||
|
static bool
|
||||||
|
TypeConversionRequiresAdjustment(ASTContext &Ctx,
|
||||||
|
const CXXRecordDecl *DerivedDecl,
|
||||||
|
const CXXRecordDecl *BaseDecl) {
|
||||||
|
CXXBasePaths Paths(/*FindAmbiguities=*/false,
|
||||||
|
/*RecordPaths=*/true, /*DetectVirtual=*/true);
|
||||||
|
if (!const_cast<CXXRecordDecl *>(DerivedDecl)->
|
||||||
|
isDerivedFrom(const_cast<CXXRecordDecl *>(BaseDecl), Paths)) {
|
||||||
|
assert(false && "Class must be derived from the passed in base class!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CXXBasePath &Path = Paths.front();
|
||||||
|
|
||||||
|
size_t Start = 0, End = Path.size();
|
||||||
|
|
||||||
|
// Check if we have a virtual base.
|
||||||
|
if (const RecordType *RT = Paths.getDetectedVirtual()) {
|
||||||
|
const CXXRecordDecl *VirtualBase = cast<CXXRecordDecl>(RT->getDecl());
|
||||||
|
assert(VirtualBase->isCanonicalDecl() && "Must have canonical decl!");
|
||||||
|
|
||||||
|
// Check the virtual base class offset.
|
||||||
|
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(DerivedDecl);
|
||||||
|
|
||||||
|
if (Layout.getVBaseClassOffset(VirtualBase) != 0) {
|
||||||
|
// This requires an adjustment.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now ignore all the path elements up to the virtual base.
|
||||||
|
// FIXME: It would be nice if CXXBasePaths could return an index to the
|
||||||
|
// CXXElementSpecifier that corresponded to the virtual base.
|
||||||
|
for (; Start != End; ++Start) {
|
||||||
|
const CXXBasePathElement& Element = Path[Start];
|
||||||
|
|
||||||
|
if (Element.Class == VirtualBase)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; Start != End; ++Start) {
|
||||||
|
const CXXBasePathElement &Element = Path[Start];
|
||||||
|
|
||||||
|
// Check the base class offset.
|
||||||
|
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class);
|
||||||
|
|
||||||
|
const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
|
||||||
|
const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
|
||||||
|
|
||||||
|
if (Layout.getBaseClassOffset(Base) != 0) {
|
||||||
|
// This requires an adjustment.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
TypeConversionRequiresAdjustment(ASTContext &Ctx,
|
||||||
|
QualType DerivedType, QualType BaseType) {
|
||||||
|
// Canonicalize the types.
|
||||||
|
QualType CanDerivedType = Ctx.getCanonicalType(DerivedType);
|
||||||
|
QualType CanBaseType = Ctx.getCanonicalType(BaseType);
|
||||||
|
|
||||||
|
assert(CanDerivedType->getTypeClass() == CanBaseType->getTypeClass() &&
|
||||||
|
"Types must have same type class!");
|
||||||
|
|
||||||
|
if (CanDerivedType == CanBaseType) {
|
||||||
|
// No adjustment needed.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) {
|
||||||
|
CanDerivedType = RT->getPointeeType();
|
||||||
|
CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType();
|
||||||
|
} else if (const PointerType *PT = dyn_cast<PointerType>(CanDerivedType)) {
|
||||||
|
CanDerivedType = PT->getPointeeType();
|
||||||
|
CanBaseType = cast<PointerType>(CanBaseType)->getPointeeType();
|
||||||
|
} else {
|
||||||
|
assert(false && "Unexpected return type!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CanDerivedType == CanBaseType) {
|
||||||
|
// No adjustment needed.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CXXRecordDecl *DerivedDecl =
|
||||||
|
cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
|
||||||
|
|
||||||
|
const CXXRecordDecl *BaseDecl =
|
||||||
|
cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
|
||||||
|
|
||||||
|
return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
|
||||||
|
|
||||||
|
// Itanium C++ ABI 2.5.2:
|
||||||
|
// The order of the virtual function pointers in a virtual table is the
|
||||||
|
// order of declaration of the corresponding member functions in the class.
|
||||||
|
//
|
||||||
|
// There is an entry for any virtual function declared in a class,
|
||||||
|
// whether it is a new function or overrides a base class function,
|
||||||
|
// unless it overrides a function from the primary base, and conversion
|
||||||
|
// between their return types does not require an adjustment.
|
||||||
|
|
||||||
|
int64_t CurrentIndex = 0;
|
||||||
|
|
||||||
|
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
|
||||||
|
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
|
||||||
|
|
||||||
|
if (PrimaryBase) {
|
||||||
|
assert(PrimaryBase->isCanonicalDecl() &&
|
||||||
|
"Should have the canonical decl of the primary base!");
|
||||||
|
|
||||||
|
// Since the record decl shares its vtable pointer with the primary base
|
||||||
|
// we need to start counting at the end of the primary base's vtable.
|
||||||
|
CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
const CXXDestructorDecl *ImplicitVirtualDtor = 0;
|
||||||
|
|
||||||
|
for (CXXRecordDecl::method_iterator i = RD->method_begin(),
|
||||||
|
e = RD->method_end(); i != e; ++i) {
|
||||||
|
const CXXMethodDecl *MD = *i;
|
||||||
|
|
||||||
|
// We only want virtual methods.
|
||||||
|
if (!MD->isVirtual())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool ShouldAddEntryForMethod = true;
|
||||||
|
|
||||||
|
// Check if this method overrides a method in the primary base.
|
||||||
|
for (CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
|
||||||
|
e = MD->end_overridden_methods(); i != e; ++i) {
|
||||||
|
const CXXMethodDecl *OverriddenMD = *i;
|
||||||
|
const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
|
||||||
|
assert(OverriddenMD->isCanonicalDecl() &&
|
||||||
|
"Should have the canonical decl of the overridden RD!");
|
||||||
|
|
||||||
|
if (OverriddenRD == PrimaryBase) {
|
||||||
|
// Check if converting from the return type of the method to the
|
||||||
|
// return type of the overridden method requires conversion.
|
||||||
|
QualType ReturnType =
|
||||||
|
MD->getType()->getAs<FunctionType>()->getResultType();
|
||||||
|
QualType OverriddenReturnType =
|
||||||
|
OverriddenMD->getType()->getAs<FunctionType>()->getResultType();
|
||||||
|
|
||||||
|
if (!TypeConversionRequiresAdjustment(CGM.getContext(),
|
||||||
|
ReturnType, OverriddenReturnType)) {
|
||||||
|
// This index is shared between the index in the vtable of the primary
|
||||||
|
// base class.
|
||||||
|
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
|
||||||
|
const CXXDestructorDecl *OverriddenDD =
|
||||||
|
cast<CXXDestructorDecl>(OverriddenMD);
|
||||||
|
|
||||||
|
// Add both the complete and deleting entries.
|
||||||
|
MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
|
||||||
|
getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
|
||||||
|
MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
|
||||||
|
getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
|
||||||
|
} else {
|
||||||
|
MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need to add an entry for this method.
|
||||||
|
ShouldAddEntryForMethod = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ShouldAddEntryForMethod)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
|
||||||
|
if (MD->isImplicit()) {
|
||||||
|
assert(!ImplicitVirtualDtor &&
|
||||||
|
"Did already see an implicit virtual dtor!");
|
||||||
|
ImplicitVirtualDtor = DD;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the complete dtor.
|
||||||
|
MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
|
||||||
|
|
||||||
|
// Add the deleting dtor.
|
||||||
|
MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
|
||||||
|
} else {
|
||||||
|
// Add the entry.
|
||||||
|
MethodVtableIndices[MD] = CurrentIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImplicitVirtualDtor) {
|
||||||
|
// Itanium C++ ABI 2.5.2:
|
||||||
|
// If a class has an implicitly-defined virtual destructor,
|
||||||
|
// its entries come after the declared virtual function pointers.
|
||||||
|
|
||||||
|
// Add the complete dtor.
|
||||||
|
MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
|
||||||
|
CurrentIndex++;
|
||||||
|
|
||||||
|
// Add the deleting dtor.
|
||||||
|
MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
|
||||||
|
CurrentIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
NumVirtualFunctionPointers[RD] = CurrentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t CGVtableInfo::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
|
||||||
|
llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
|
||||||
|
NumVirtualFunctionPointers.find(RD);
|
||||||
|
if (I != NumVirtualFunctionPointers.end())
|
||||||
|
return I->second;
|
||||||
|
|
||||||
|
ComputeMethodVtableIndices(RD);
|
||||||
|
|
||||||
|
I = NumVirtualFunctionPointers.find(RD);
|
||||||
|
assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!");
|
||||||
|
return I->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
|
||||||
MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD);
|
MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD);
|
||||||
if (I != MethodVtableIndices.end())
|
if (I != MethodVtableIndices.end())
|
||||||
return I->second;
|
return I->second;
|
||||||
|
|
||||||
const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
|
const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
|
||||||
|
|
||||||
std::vector<llvm::Constant *> methods;
|
ComputeMethodVtableIndices(RD);
|
||||||
// FIXME: This seems expensive. Can we do a partial job to get
|
|
||||||
// just this data.
|
|
||||||
VtableBuilder b(methods, RD, RD, 0, CGM);
|
|
||||||
D1(printf("vtable %s\n", RD->getNameAsCString()));
|
|
||||||
b.GenerateVtableForBase(RD);
|
|
||||||
b.GenerateVtableForVBases(RD);
|
|
||||||
|
|
||||||
MethodVtableIndices.insert(b.getIndex().begin(),
|
|
||||||
b.getIndex().end());
|
|
||||||
|
|
||||||
I = MethodVtableIndices.find(GD);
|
I = MethodVtableIndices.find(GD);
|
||||||
assert(I != MethodVtableIndices.end() && "Did not find index!");
|
assert(I != MethodVtableIndices.end() && "Did not find index!");
|
||||||
|
|
|
@ -80,6 +80,17 @@ class CGVtableInfo {
|
||||||
VirtualBaseClassIndiciesTy VirtualBaseClassIndicies;
|
VirtualBaseClassIndiciesTy VirtualBaseClassIndicies;
|
||||||
|
|
||||||
llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> Vtables;
|
llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> Vtables;
|
||||||
|
|
||||||
|
/// NumVirtualFunctionPointers - Contains the number of virtual function
|
||||||
|
/// pointers in the vtable for a given record decl.
|
||||||
|
llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
|
||||||
|
|
||||||
|
/// getNumVirtualFunctionPointers - Return the number of virtual function
|
||||||
|
/// pointers in the vtable for a given record decl.
|
||||||
|
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
|
||||||
|
|
||||||
|
void ComputeMethodVtableIndices(const CXXRecordDecl *RD);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CGVtableInfo(CodeGenModule &CGM)
|
CGVtableInfo(CodeGenModule &CGM)
|
||||||
: CGM(CGM) { }
|
: CGM(CGM) { }
|
||||||
|
@ -87,7 +98,7 @@ public:
|
||||||
/// getMethodVtableIndex - Return the index (relative to the vtable address
|
/// getMethodVtableIndex - Return the index (relative to the vtable address
|
||||||
/// point) where the function pointer for the given virtual function is
|
/// point) where the function pointer for the given virtual function is
|
||||||
/// stored.
|
/// stored.
|
||||||
int64_t getMethodVtableIndex(GlobalDecl GD);
|
uint64_t getMethodVtableIndex(GlobalDecl GD);
|
||||||
|
|
||||||
/// getVirtualBaseOffsetIndex - Return the index (relative to the vtable
|
/// getVirtualBaseOffsetIndex - Return the index (relative to the vtable
|
||||||
/// address point) where the offset of the virtual base that contains the
|
/// address point) where the offset of the virtual base that contains the
|
||||||
|
|
Loading…
Reference in New Issue