forked from OSchip/llvm-project
When emitting complete destructors for classes with virtual bases, compute
the offset to the virtual bases statically inside of relying on the virtual base offsets in the object's vtable(s). This is both more efficient and sound against the destructor's manipulation of the vtables. Also extract a few helper routines. Oh and we seem to pass all tests with an optimized clang now. llvm-svn: 96327
This commit is contained in:
parent
1e3715acc3
commit
6ce747220a
|
@ -19,11 +19,11 @@ using namespace clang;
|
|||
using namespace CodeGen;
|
||||
|
||||
static uint64_t
|
||||
ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
|
||||
ComputeNonVirtualBaseClassOffset(ASTContext &Context,
|
||||
const CXXBasePath &Path,
|
||||
unsigned Start) {
|
||||
uint64_t Offset = 0;
|
||||
|
||||
const CXXBasePath &Path = Paths.front();
|
||||
for (unsigned i = Start, e = Path.size(); i != e; ++i) {
|
||||
const CXXBasePathElement& Element = Path[i];
|
||||
|
||||
|
@ -57,7 +57,8 @@ CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class,
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0);
|
||||
uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(),
|
||||
Paths.front(), 0);
|
||||
if (!Offset)
|
||||
return 0;
|
||||
|
||||
|
@ -99,10 +100,46 @@ CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl,
|
|||
getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
|
||||
|
||||
uint64_t Offset =
|
||||
ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start);
|
||||
ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
|
||||
return ThunkAdjustment(Offset, VirtualOffset);
|
||||
}
|
||||
|
||||
/// Gets the address of a virtual base class within a complete object.
|
||||
/// This should only be used for (1) non-virtual bases or (2) virtual bases
|
||||
/// when the type is known to be complete (e.g. in complete destructors).
|
||||
///
|
||||
/// The object pointed to by 'This' is assumed to be non-null.
|
||||
llvm::Value *
|
||||
CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This,
|
||||
bool isBaseVirtual,
|
||||
const CXXRecordDecl *Derived,
|
||||
const CXXRecordDecl *Base) {
|
||||
// 'this' must be a pointer (in some address space) to Derived.
|
||||
assert(This->getType()->isPointerTy() &&
|
||||
cast<llvm::PointerType>(This->getType())->getElementType()
|
||||
== ConvertType(Derived));
|
||||
|
||||
// Compute the offset of the virtual base.
|
||||
uint64_t Offset;
|
||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);
|
||||
if (isBaseVirtual)
|
||||
Offset = Layout.getVBaseClassOffset(Base);
|
||||
else
|
||||
Offset = Layout.getBaseClassOffset(Base);
|
||||
|
||||
// Shift and cast down to the base type.
|
||||
// TODO: for complete types, this should be possible with a GEP.
|
||||
llvm::Value *V = This;
|
||||
if (Offset) {
|
||||
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
|
||||
V = Builder.CreateBitCast(V, Int8PtrTy);
|
||||
V = Builder.CreateConstInBoundsGEP1_64(V, Offset / 8);
|
||||
}
|
||||
V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo());
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
llvm::Value *
|
||||
CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
|
||||
const CXXRecordDecl *Class,
|
||||
|
@ -110,7 +147,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
|
|||
bool NullCheckValue) {
|
||||
QualType BTy =
|
||||
getContext().getCanonicalType(
|
||||
getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClass)));
|
||||
getContext().getTypeDeclType(BaseClass));
|
||||
const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
|
||||
|
||||
if (Class == BaseClass) {
|
||||
|
@ -141,7 +178,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
|
|||
}
|
||||
|
||||
uint64_t Offset =
|
||||
ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start);
|
||||
ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
|
||||
|
||||
if (!Offset && !VBase) {
|
||||
// Just cast back.
|
||||
|
@ -790,35 +827,18 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
|
|||
if (CtorType == Ctor_Base && isBaseVirtual)
|
||||
return;
|
||||
|
||||
// Compute the offset to the base; we do this directly instead of using
|
||||
// GetAddressOfBaseClass because the class doesn't have a vtable pointer
|
||||
// at this point.
|
||||
// FIXME: This could be refactored back into GetAddressOfBaseClass if it took
|
||||
// an extra parameter for whether the derived class is the complete object
|
||||
// class.
|
||||
const ASTRecordLayout &Layout =
|
||||
CGF.getContext().getASTRecordLayout(ClassDecl);
|
||||
uint64_t Offset;
|
||||
if (isBaseVirtual)
|
||||
Offset = Layout.getVBaseClassOffset(BaseClassDecl);
|
||||
else
|
||||
Offset = Layout.getBaseClassOffset(BaseClassDecl);
|
||||
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
|
||||
const llvm::Type *BaseClassType = CGF.ConvertType(QualType(BaseType, 0));
|
||||
llvm::Value *V = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy);
|
||||
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8);
|
||||
V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo());
|
||||
// We can pretend to be a complete class because it only matters for
|
||||
// virtual bases, and we only do virtual bases for complete ctors.
|
||||
llvm::Value *V = ThisPtr;
|
||||
V = CGF.GetAddressOfBaseOfCompleteClass(V, isBaseVirtual,
|
||||
ClassDecl, BaseClassDecl);
|
||||
|
||||
CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true);
|
||||
|
||||
if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor()) {
|
||||
// FIXME: Is this OK for C++0x delegating constructors?
|
||||
CodeGenFunction::EHCleanupBlock Cleanup(CGF);
|
||||
|
||||
llvm::Value *ThisPtr = CGF.LoadCXXThis();
|
||||
llvm::Value *V = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy);
|
||||
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset / 8);
|
||||
V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo());
|
||||
|
||||
CXXDestructorDecl *DD = BaseClassDecl->getDestructor(CGF.getContext());
|
||||
CGF.EmitCXXDestructorCall(DD, Dtor_Base, V);
|
||||
}
|
||||
|
@ -886,7 +906,6 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
|
|||
|
||||
/// EmitCtorPrologue - This routine generates necessary code to initialize
|
||||
/// base classes and non-static data members belonging to this constructor.
|
||||
/// FIXME: This needs to take a CXXCtorType.
|
||||
void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
|
||||
CXXCtorType CtorType) {
|
||||
const CXXRecordDecl *ClassDecl = CD->getParent();
|
||||
|
@ -1019,9 +1038,10 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
|
|||
if (BaseClassDecl->hasTrivialDestructor())
|
||||
continue;
|
||||
const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
|
||||
llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
|
||||
ClassDecl, BaseClassDecl,
|
||||
/*NullCheckValue=*/false);
|
||||
llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(),
|
||||
true,
|
||||
ClassDecl,
|
||||
BaseClassDecl);
|
||||
EmitCXXDestructorCall(D, Dtor_Base, V);
|
||||
}
|
||||
|
||||
|
|
|
@ -572,6 +572,9 @@ public:
|
|||
|
||||
const llvm::Type *ConvertTypeForMem(QualType T);
|
||||
const llvm::Type *ConvertType(QualType T);
|
||||
const llvm::Type *ConvertType(const TypeDecl *T) {
|
||||
return ConvertType(getContext().getTypeDeclType(T));
|
||||
}
|
||||
|
||||
/// LoadObjCSelf - Load the value of self. This function is only valid while
|
||||
/// generating code for an Objective-C method.
|
||||
|
@ -741,10 +744,15 @@ public:
|
|||
/// virtual bases.
|
||||
llvm::Value *LoadCXXVTT();
|
||||
|
||||
/// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a
|
||||
/// complete class down to one of its virtual bases.
|
||||
llvm::Value *GetAddressOfBaseOfCompleteClass(llvm::Value *Value,
|
||||
bool IsVirtual,
|
||||
const CXXRecordDecl *Derived,
|
||||
const CXXRecordDecl *Base);
|
||||
|
||||
/// GetAddressOfBaseClass - This function will add the necessary delta to the
|
||||
/// load of 'this' and returns address of the base class.
|
||||
// FIXME. This currently only does a derived to non-virtual base conversion.
|
||||
// Other kinds of conversions will come later.
|
||||
llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
|
||||
const CXXRecordDecl *ClassDecl,
|
||||
const CXXRecordDecl *BaseClassDecl,
|
||||
|
|
Loading…
Reference in New Issue