CodeGen: Clean up implementation of vtable initializer builder. NFC.

- Simplify signature of CreateVTableInitializer function.
- Move vtable component builder to a separate function.
- Remove unnecessary accessors from VTableLayout class.

This is in preparation for a future change that will alter the type of the
vtable initializer.

Differential Revision: https://reviews.llvm.org/D22642

llvm-svn: 280897
This commit is contained in:
Peter Collingbourne 2016-09-08 01:14:39 +00:00
parent 0053c0b679
commit e53683f97b
6 changed files with 129 additions and 172 deletions

View File

@ -218,12 +218,6 @@ private:
class VTableLayout { class VTableLayout {
public: public:
typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy; typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy;
typedef const VTableComponent *vtable_component_iterator;
typedef const VTableThunkTy *vtable_thunk_iterator;
typedef llvm::iterator_range<vtable_component_iterator>
vtable_component_range;
typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
private: private:
@ -248,31 +242,12 @@ public:
bool IsMicrosoftABI); bool IsMicrosoftABI);
~VTableLayout(); ~VTableLayout();
uint64_t getNumVTableComponents() const { ArrayRef<VTableComponent> vtable_components() const {
return NumVTableComponents; return {VTableComponents.get(), NumVTableComponents};
} }
vtable_component_range vtable_components() const { ArrayRef<VTableThunkTy> vtable_thunks() const {
return vtable_component_range(vtable_component_begin(), return {VTableThunks.get(), NumVTableThunks};
vtable_component_end());
}
vtable_component_iterator vtable_component_begin() const {
return VTableComponents.get();
}
vtable_component_iterator vtable_component_end() const {
return VTableComponents.get() + NumVTableComponents;
}
uint64_t getNumVTableThunks() const { return NumVTableThunks; }
vtable_thunk_iterator vtable_thunk_begin() const {
return VTableThunks.get();
}
vtable_thunk_iterator vtable_thunk_end() const {
return VTableThunks.get() + NumVTableThunks;
} }
uint64_t getAddressPoint(BaseSubobject Base) const { uint64_t getAddressPoint(BaseSubobject Base) const {

View File

@ -1576,7 +1576,7 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit,
const VTableLayout &VFTLayout = const VTableLayout &VFTLayout =
CGM.getMicrosoftVTableContext().getVFTableLayout(RD, CharUnits::Zero()); CGM.getMicrosoftVTableContext().getVFTableLayout(RD, CharUnits::Zero());
unsigned VSlotCount = unsigned VSlotCount =
VFTLayout.getNumVTableComponents() - CGM.getLangOpts().RTTIData; VFTLayout.vtable_components().size() - CGM.getLangOpts().RTTIData;
unsigned VTableWidth = PtrWidth * VSlotCount; unsigned VTableWidth = PtrWidth * VSlotCount;
// Create a very wide void* type and insert it directly in the element list. // Create a very wide void* type and insert it directly in the element list.

View File

@ -517,139 +517,121 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD)
emitThunk(GD, Thunk, /*ForVTable=*/false); emitThunk(GD, Thunk, /*ForVTable=*/false);
} }
llvm::Constant *CodeGenVTables::CreateVTableInitializer( llvm::Constant *CodeGenVTables::CreateVTableComponent(
const CXXRecordDecl *RD, const VTableComponent *Components, unsigned Idx, const VTableLayout &VTLayout, llvm::Constant *RTTI,
unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks, unsigned &NextVTableThunkIndex) {
unsigned NumVTableThunks, llvm::Constant *RTTI) { VTableComponent Component = VTLayout.vtable_components()[Idx];
SmallVector<llvm::Constant *, 64> Inits;
llvm::Type *Int8PtrTy = CGM.Int8PtrTy; auto OffsetConstant = [&](CharUnits Offset) {
return llvm::ConstantExpr::getIntToPtr(
llvm::ConstantInt::get(CGM.PtrDiffTy, Offset.getQuantity()),
CGM.Int8PtrTy);
};
llvm::Type *PtrDiffTy = switch (Component.getKind()) {
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); case VTableComponent::CK_VCallOffset:
return OffsetConstant(Component.getVCallOffset());
unsigned NextVTableThunkIndex = 0; case VTableComponent::CK_VBaseOffset:
return OffsetConstant(Component.getVBaseOffset());
llvm::Constant *PureVirtualFn = nullptr, *DeletedVirtualFn = nullptr; case VTableComponent::CK_OffsetToTop:
return OffsetConstant(Component.getOffsetToTop());
for (unsigned I = 0; I != NumComponents; ++I) { case VTableComponent::CK_RTTI:
VTableComponent Component = Components[I]; return RTTI;
llvm::Constant *Init = nullptr; case VTableComponent::CK_FunctionPointer:
case VTableComponent::CK_CompleteDtorPointer:
case VTableComponent::CK_DeletingDtorPointer: {
GlobalDecl GD;
// Get the right global decl.
switch (Component.getKind()) { switch (Component.getKind()) {
case VTableComponent::CK_VCallOffset: default:
Init = llvm::ConstantInt::get(PtrDiffTy, llvm_unreachable("Unexpected vtable component kind");
Component.getVCallOffset().getQuantity());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
case VTableComponent::CK_VBaseOffset:
Init = llvm::ConstantInt::get(PtrDiffTy,
Component.getVBaseOffset().getQuantity());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
case VTableComponent::CK_OffsetToTop:
Init = llvm::ConstantInt::get(PtrDiffTy,
Component.getOffsetToTop().getQuantity());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
case VTableComponent::CK_RTTI:
Init = llvm::ConstantExpr::getBitCast(RTTI, Int8PtrTy);
break;
case VTableComponent::CK_FunctionPointer: case VTableComponent::CK_FunctionPointer:
GD = Component.getFunctionDecl();
break;
case VTableComponent::CK_CompleteDtorPointer: case VTableComponent::CK_CompleteDtorPointer:
case VTableComponent::CK_DeletingDtorPointer: { GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete);
GlobalDecl GD; break;
case VTableComponent::CK_DeletingDtorPointer:
// Get the right global decl. GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting);
switch (Component.getKind()) {
default:
llvm_unreachable("Unexpected vtable component kind");
case VTableComponent::CK_FunctionPointer:
GD = Component.getFunctionDecl();
break;
case VTableComponent::CK_CompleteDtorPointer:
GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete);
break;
case VTableComponent::CK_DeletingDtorPointer:
GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting);
break;
}
if (CGM.getLangOpts().CUDA) {
// Emit NULL for methods we can't codegen on this
// side. Otherwise we'd end up with vtable with unresolved
// references.
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
// OK on device side: functions w/ __device__ attribute
// OK on host side: anything except __device__-only functions.
bool CanEmitMethod = CGM.getLangOpts().CUDAIsDevice
? MD->hasAttr<CUDADeviceAttr>()
: (MD->hasAttr<CUDAHostAttr>() ||
!MD->hasAttr<CUDADeviceAttr>());
if (!CanEmitMethod) {
Init = llvm::ConstantExpr::getNullValue(Int8PtrTy);
break;
}
// Method is acceptable, continue processing as usual.
}
if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) {
// We have a pure virtual member function.
if (!PureVirtualFn) {
llvm::FunctionType *Ty =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
StringRef PureCallName = CGM.getCXXABI().GetPureVirtualCallName();
PureVirtualFn = CGM.CreateRuntimeFunction(Ty, PureCallName);
if (auto *F = dyn_cast<llvm::Function>(PureVirtualFn))
F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn,
CGM.Int8PtrTy);
}
Init = PureVirtualFn;
} else if (cast<CXXMethodDecl>(GD.getDecl())->isDeleted()) {
if (!DeletedVirtualFn) {
llvm::FunctionType *Ty =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
StringRef DeletedCallName =
CGM.getCXXABI().GetDeletedVirtualCallName();
DeletedVirtualFn = CGM.CreateRuntimeFunction(Ty, DeletedCallName);
if (auto *F = dyn_cast<llvm::Function>(DeletedVirtualFn))
F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
DeletedVirtualFn = llvm::ConstantExpr::getBitCast(DeletedVirtualFn,
CGM.Int8PtrTy);
}
Init = DeletedVirtualFn;
} else {
// Check if we should use a thunk.
if (NextVTableThunkIndex < NumVTableThunks &&
VTableThunks[NextVTableThunkIndex].first == I) {
const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second;
maybeEmitThunkForVTable(GD, Thunk);
Init = CGM.GetAddrOfThunk(GD, Thunk);
NextVTableThunkIndex++;
} else {
llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD);
Init = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
}
Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
}
break; break;
} }
case VTableComponent::CK_UnusedFunctionPointer: if (CGM.getLangOpts().CUDA) {
Init = llvm::ConstantExpr::getNullValue(Int8PtrTy); // Emit NULL for methods we can't codegen on this
break; // side. Otherwise we'd end up with vtable with unresolved
// references.
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
// OK on device side: functions w/ __device__ attribute
// OK on host side: anything except __device__-only functions.
bool CanEmitMethod =
CGM.getLangOpts().CUDAIsDevice
? MD->hasAttr<CUDADeviceAttr>()
: (MD->hasAttr<CUDAHostAttr>() || !MD->hasAttr<CUDADeviceAttr>());
if (!CanEmitMethod)
return llvm::ConstantExpr::getNullValue(CGM.Int8PtrTy);
// Method is acceptable, continue processing as usual.
}
auto SpecialVirtualFn = [&](llvm::Constant *&Cache, StringRef Name) {
if (!Cache) {
llvm::FunctionType *Ty =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
Cache = CGM.CreateRuntimeFunction(Ty, Name);
if (auto *F = dyn_cast<llvm::Function>(Cache))
F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
Cache = llvm::ConstantExpr::getBitCast(Cache, CGM.Int8PtrTy);
}
return Cache;
}; };
Inits.push_back(Init); if (cast<CXXMethodDecl>(GD.getDecl())->isPure())
// We have a pure virtual member function.
return SpecialVirtualFn(PureVirtualFn,
CGM.getCXXABI().GetPureVirtualCallName());
if (cast<CXXMethodDecl>(GD.getDecl())->isDeleted())
return SpecialVirtualFn(DeletedVirtualFn,
CGM.getCXXABI().GetDeletedVirtualCallName());
// Check if we should use a thunk.
if (NextVTableThunkIndex < VTLayout.vtable_thunks().size() &&
VTLayout.vtable_thunks()[NextVTableThunkIndex].first == Idx) {
const ThunkInfo &Thunk =
VTLayout.vtable_thunks()[NextVTableThunkIndex].second;
maybeEmitThunkForVTable(GD, Thunk);
NextVTableThunkIndex++;
return CGM.GetAddrOfThunk(GD, Thunk);
}
llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD);
return CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
} }
llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents); case VTableComponent::CK_UnusedFunctionPointer:
return llvm::ConstantExpr::getNullValue(CGM.Int8PtrTy);
}
}
llvm::Constant *
CodeGenVTables::CreateVTableInitializer(const VTableLayout &VTLayout,
llvm::Constant *RTTI) {
SmallVector<llvm::Constant *, 64> Inits;
unsigned NextVTableThunkIndex = 0;
for (unsigned I = 0, E = VTLayout.vtable_components().size(); I != E; ++I) {
llvm::Constant *Init =
CreateVTableComponent(I, VTLayout, RTTI, NextVTableThunkIndex);
Inits.push_back(llvm::ConstantExpr::getBitCast(Init, CGM.Int8PtrTy));
}
llvm::ArrayType *ArrayType =
llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout.vtable_components().size());
return llvm::ConstantArray::get(ArrayType, Inits); return llvm::ConstantArray::get(ArrayType, Inits);
} }
@ -678,7 +660,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
StringRef Name = OutName.str(); StringRef Name = OutName.str();
llvm::ArrayType *ArrayType = llvm::ArrayType *ArrayType =
llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout->getNumVTableComponents()); llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout->vtable_components().size());
// Construction vtable symbols are not part of the Itanium ABI, so we cannot // Construction vtable symbols are not part of the Itanium ABI, so we cannot
// guarantee that they actually will be available externally. Instead, when // guarantee that they actually will be available externally. Instead, when
@ -700,10 +682,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
CGM.getContext().getTagDeclType(Base.getBase())); CGM.getContext().getTagDeclType(Base.getBase()));
// Create and set the initializer. // Create and set the initializer.
llvm::Constant *Init = CreateVTableInitializer( llvm::Constant *Init = CreateVTableInitializer(*VTLayout, RTTI);
Base.getBase(), VTLayout->vtable_component_begin(),
VTLayout->getNumVTableComponents(), VTLayout->vtable_thunk_begin(),
VTLayout->getNumVTableThunks(), RTTI);
VTable->setInitializer(Init); VTable->setInitializer(Init);
CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get()); CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get());

View File

@ -49,6 +49,12 @@ class CodeGenVTables {
/// indices. /// indices.
SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices; SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices;
/// Cache for the pure virtual member call function.
llvm::Constant *PureVirtualFn = nullptr;
/// Cache for the deleted virtual member call function.
llvm::Constant *DeletedVirtualFn = nullptr;
/// emitThunk - Emit a single thunk. /// emitThunk - Emit a single thunk.
void emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool ForVTable); void emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool ForVTable);
@ -56,15 +62,16 @@ class CodeGenVTables {
/// the ABI. /// the ABI.
void maybeEmitThunkForVTable(GlobalDecl GD, const ThunkInfo &Thunk); void maybeEmitThunkForVTable(GlobalDecl GD, const ThunkInfo &Thunk);
llvm::Constant *CreateVTableComponent(unsigned Idx,
const VTableLayout &VTLayout,
llvm::Constant *RTTI,
unsigned &NextVTableThunkIndex);
public: public:
/// CreateVTableInitializer - Create a vtable initializer for the given record /// CreateVTableInitializer - Create a vtable initializer with the given
/// decl. /// layout.
/// \param Components - The vtable components; this is really an array of llvm::Constant *CreateVTableInitializer(const VTableLayout &VTLayout,
/// VTableComponents. llvm::Constant *RTTI);
llvm::Constant *CreateVTableInitializer(
const CXXRecordDecl *RD, const VTableComponent *Components,
unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks,
unsigned NumVTableThunks, llvm::Constant *RTTI);
CodeGenVTables(CodeGenModule &CGM); CodeGenVTables(CodeGenModule &CGM);

View File

@ -1462,9 +1462,7 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
CGM.GetAddrOfRTTIDescriptor(CGM.getContext().getTagDeclType(RD)); CGM.GetAddrOfRTTIDescriptor(CGM.getContext().getTagDeclType(RD));
// Create and set the initializer. // Create and set the initializer.
llvm::Constant *Init = CGVT.CreateVTableInitializer( llvm::Constant *Init = CGVT.CreateVTableInitializer(VTLayout, RTTI);
RD, VTLayout.vtable_component_begin(), VTLayout.getNumVTableComponents(),
VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks(), RTTI);
VTable->setInitializer(Init); VTable->setInitializer(Init);
// Set the correct linkage. // Set the correct linkage.
@ -1575,7 +1573,7 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext(); ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext();
llvm::ArrayType *ArrayType = llvm::ArrayType::get( llvm::ArrayType *ArrayType = llvm::ArrayType::get(
CGM.Int8PtrTy, VTContext.getVTableLayout(RD).getNumVTableComponents()); CGM.Int8PtrTy, VTContext.getVTableLayout(RD).vtable_components().size());
VTable = CGM.CreateOrReplaceCXXRuntimeVariable( VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
Name, ArrayType, llvm::GlobalValue::ExternalLinkage); Name, ArrayType, llvm::GlobalValue::ExternalLinkage);

View File

@ -1575,10 +1575,7 @@ void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
[](const VTableComponent &VTC) { return VTC.isRTTIKind(); })) [](const VTableComponent &VTC) { return VTC.isRTTIKind(); }))
RTTI = getMSCompleteObjectLocator(RD, Info); RTTI = getMSCompleteObjectLocator(RD, Info);
llvm::Constant *Init = CGVT.CreateVTableInitializer( llvm::Constant *Init = CGVT.CreateVTableInitializer(VTLayout, RTTI);
RD, VTLayout.vtable_component_begin(),
VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(),
VTLayout.getNumVTableThunks(), RTTI);
VTable->setInitializer(Init); VTable->setInitializer(Init);
@ -1701,7 +1698,8 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
uint64_t NumVTableSlots = uint64_t NumVTableSlots =
VTContext.getVFTableLayout(RD, VFPtr->FullOffsetInMDC) VTContext.getVFTableLayout(RD, VFPtr->FullOffsetInMDC)
.getNumVTableComponents(); .vtable_components()
.size();
llvm::GlobalValue::LinkageTypes VTableLinkage = llvm::GlobalValue::LinkageTypes VTableLinkage =
VTableAliasIsRequred ? llvm::GlobalValue::PrivateLinkage : VFTableLinkage; VTableAliasIsRequred ? llvm::GlobalValue::PrivateLinkage : VFTableLinkage;