Index: include/clang/AST/VTableBuilder.h =================================================================== --- include/clang/AST/VTableBuilder.h +++ include/clang/AST/VTableBuilder.h @@ -248,31 +248,12 @@ bool IsMicrosoftABI); ~VTableLayout(); - uint64_t getNumVTableComponents() const { - return NumVTableComponents; + ArrayRef vtable_components() const { + return {VTableComponents.get(), NumVTableComponents}; } - vtable_component_range vtable_components() const { - return vtable_component_range(vtable_component_begin(), - 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; + ArrayRef vtable_thunks() const { + return {VTableThunks.get(), NumVTableThunks}; } uint64_t getAddressPoint(BaseSubobject Base) const { Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -1576,7 +1576,7 @@ const VTableLayout &VFTLayout = CGM.getMicrosoftVTableContext().getVFTableLayout(RD, CharUnits::Zero()); unsigned VSlotCount = - VFTLayout.getNumVTableComponents() - CGM.getLangOpts().RTTIData; + VFTLayout.vtable_components().size() - CGM.getLangOpts().RTTIData; unsigned VTableWidth = PtrWidth * VSlotCount; // Create a very wide void* type and insert it directly in the element list. Index: lib/CodeGen/CGVTables.h =================================================================== --- lib/CodeGen/CGVTables.h +++ lib/CodeGen/CGVTables.h @@ -49,6 +49,8 @@ /// indices. SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices; + llvm::Constant *PureVirtualFn = nullptr, *DeletedVirtualFn = nullptr; + /// emitThunk - Emit a single thunk. void emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool ForVTable); @@ -56,15 +58,18 @@ /// the ABI. void maybeEmitThunkForVTable(GlobalDecl GD, const ThunkInfo &Thunk); + llvm::Constant *CreateVTableComponent(unsigned Idx, + const VTableLayout &VTLayout, + llvm::Constant *RTTI, + unsigned &NextVTableThunkIndex); + public: /// CreateVTableInitializer - Create a vtable initializer for the given record /// decl. /// \param Components - The vtable components; this is really an array of /// VTableComponents. - llvm::Constant *CreateVTableInitializer( - const CXXRecordDecl *RD, const VTableComponent *Components, - unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks, - unsigned NumVTableThunks, llvm::Constant *RTTI); + llvm::Constant *CreateVTableInitializer(const VTableLayout &VTLayout, + llvm::Constant *RTTI); CodeGenVTables(CodeGenModule &CGM); Index: lib/CodeGen/CGVTables.cpp =================================================================== --- lib/CodeGen/CGVTables.cpp +++ lib/CodeGen/CGVTables.cpp @@ -517,139 +517,124 @@ emitThunk(GD, Thunk, /*ForVTable=*/false); } -llvm::Constant *CodeGenVTables::CreateVTableInitializer( - const CXXRecordDecl *RD, const VTableComponent *Components, - unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks, - unsigned NumVTableThunks, llvm::Constant *RTTI) { - SmallVector Inits; - +llvm::Constant *CodeGenVTables::CreateVTableComponent( + unsigned Idx, const VTableLayout &VTLayout, llvm::Constant *RTTI, + unsigned &NextVTableThunkIndex) { + VTableComponent Component = VTLayout.vtable_components()[Idx]; llvm::Type *Int8PtrTy = CGM.Int8PtrTy; - - llvm::Type *PtrDiffTy = - CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); - unsigned NextVTableThunkIndex = 0; + auto OffsetConstant = [&](CharUnits Offset) { + llvm::Type *PtrDiffTy = + CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); + return llvm::ConstantExpr::getIntToPtr( + llvm::ConstantInt::get(PtrDiffTy, Offset.getQuantity()), Int8PtrTy); + }; + + switch (Component.getKind()) { + case VTableComponent::CK_VCallOffset: + return OffsetConstant(Component.getVCallOffset()); - llvm::Constant *PureVirtualFn = nullptr, *DeletedVirtualFn = nullptr; + case VTableComponent::CK_VBaseOffset: + return OffsetConstant(Component.getVBaseOffset()); - for (unsigned I = 0; I != NumComponents; ++I) { - VTableComponent Component = Components[I]; + case VTableComponent::CK_OffsetToTop: + return OffsetConstant(Component.getOffsetToTop()); - llvm::Constant *Init = nullptr; + case VTableComponent::CK_RTTI: + return RTTI; + case VTableComponent::CK_FunctionPointer: + case VTableComponent::CK_CompleteDtorPointer: + case VTableComponent::CK_DeletingDtorPointer: { + GlobalDecl GD; + + // Get the right global decl. switch (Component.getKind()) { - case VTableComponent::CK_VCallOffset: - Init = llvm::ConstantInt::get(PtrDiffTy, - 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); + default: + llvm_unreachable("Unexpected vtable component kind"); + case VTableComponent::CK_FunctionPointer: + GD = Component.getFunctionDecl(); break; - case VTableComponent::CK_OffsetToTop: - Init = llvm::ConstantInt::get(PtrDiffTy, - Component.getOffsetToTop().getQuantity()); - Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); + case VTableComponent::CK_CompleteDtorPointer: + GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete); break; - case VTableComponent::CK_RTTI: - Init = llvm::ConstantExpr::getBitCast(RTTI, Int8PtrTy); + case VTableComponent::CK_DeletingDtorPointer: + GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting); break; - case VTableComponent::CK_FunctionPointer: - case VTableComponent::CK_CompleteDtorPointer: - case VTableComponent::CK_DeletingDtorPointer: { - GlobalDecl GD; - - // Get the right global decl. - 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(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() - : (MD->hasAttr() || - !MD->hasAttr()); - if (!CanEmitMethod) { - Init = llvm::ConstantExpr::getNullValue(Int8PtrTy); - break; - } - // Method is acceptable, continue processing as usual. - } + 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(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() + : (MD->hasAttr() || !MD->hasAttr()); + if (!CanEmitMethod) + return llvm::ConstantExpr::getNullValue(Int8PtrTy); + // Method is acceptable, continue processing as usual. + } - if (cast(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(PureVirtualFn)) - F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn, - CGM.Int8PtrTy); - } - Init = PureVirtualFn; - } else if (cast(GD.getDecl())->isDeleted()) { - if (!DeletedVirtualFn) { - llvm::FunctionType *Ty = + auto SpecialVirtualFn = [&](llvm::Constant *&Cache, StringRef Name) { + if (!Cache) { + 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(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); + Cache = CGM.CreateRuntimeFunction(Ty, Name); + if (auto *F = dyn_cast(Cache)) + F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + Cache = llvm::ConstantExpr::getBitCast(Cache, CGM.Int8PtrTy); + } + return Cache; + }; - NextVTableThunkIndex++; - } else { - llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD); - - Init = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true); - } + if (cast(GD.getDecl())->isPure()) { + // We have a pure virtual member function. + return SpecialVirtualFn(PureVirtualFn, + CGM.getCXXABI().GetPureVirtualCallName()); + } else if (cast(GD.getDecl())->isDeleted()) { + return SpecialVirtualFn(DeletedVirtualFn, + CGM.getCXXABI().GetDeletedVirtualCallName()); + } else { + // 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); + } else { + llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD); - Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); + return CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true); } - break; } + } - case VTableComponent::CK_UnusedFunctionPointer: - Init = llvm::ConstantExpr::getNullValue(Int8PtrTy); - break; - }; - - Inits.push_back(Init); + case VTableComponent::CK_UnusedFunctionPointer: + return llvm::ConstantExpr::getNullValue(Int8PtrTy); } - - llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents); +} + +llvm::Constant * +CodeGenVTables::CreateVTableInitializer(const VTableLayout &VTLayout, + llvm::Constant *RTTI) { + SmallVector 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); } @@ -677,8 +662,8 @@ Base.getBase(), Out); StringRef Name = OutName.str(); - llvm::ArrayType *ArrayType = - llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout->getNumVTableComponents()); + llvm::ArrayType *ArrayType = + llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout->vtable_components().size()); // Construction vtable symbols are not part of the Itanium ABI, so we cannot // guarantee that they actually will be available externally. Instead, when @@ -700,10 +685,7 @@ CGM.getContext().getTagDeclType(Base.getBase())); // Create and set the initializer. - llvm::Constant *Init = CreateVTableInitializer( - Base.getBase(), VTLayout->vtable_component_begin(), - VTLayout->getNumVTableComponents(), VTLayout->vtable_thunk_begin(), - VTLayout->getNumVTableThunks(), RTTI); + llvm::Constant *Init = CreateVTableInitializer(*VTLayout, RTTI); VTable->setInitializer(Init); CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get()); Index: lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- lib/CodeGen/ItaniumCXXABI.cpp +++ lib/CodeGen/ItaniumCXXABI.cpp @@ -1462,9 +1462,7 @@ CGM.GetAddrOfRTTIDescriptor(CGM.getContext().getTagDeclType(RD)); // Create and set the initializer. - llvm::Constant *Init = CGVT.CreateVTableInitializer( - RD, VTLayout.vtable_component_begin(), VTLayout.getNumVTableComponents(), - VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks(), RTTI); + llvm::Constant *Init = CGVT.CreateVTableInitializer(VTLayout, RTTI); VTable->setInitializer(Init); // Set the correct linkage. @@ -1575,7 +1573,7 @@ ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext(); llvm::ArrayType *ArrayType = llvm::ArrayType::get( - CGM.Int8PtrTy, VTContext.getVTableLayout(RD).getNumVTableComponents()); + CGM.Int8PtrTy, VTContext.getVTableLayout(RD).vtable_components().size()); VTable = CGM.CreateOrReplaceCXXRuntimeVariable( Name, ArrayType, llvm::GlobalValue::ExternalLinkage); Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -1575,10 +1575,7 @@ [](const VTableComponent &VTC) { return VTC.isRTTIKind(); })) RTTI = getMSCompleteObjectLocator(RD, Info); - llvm::Constant *Init = CGVT.CreateVTableInitializer( - RD, VTLayout.vtable_component_begin(), - VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(), - VTLayout.getNumVTableThunks(), RTTI); + llvm::Constant *Init = CGVT.CreateVTableInitializer(VTLayout, RTTI); VTable->setInitializer(Init); @@ -1701,7 +1698,8 @@ uint64_t NumVTableSlots = VTContext.getVFTableLayout(RD, VFPtr->FullOffsetInMDC) - .getNumVTableComponents(); + .vtable_components() + .size(); llvm::GlobalValue::LinkageTypes VTableLinkage = VTableAliasIsRequred ? llvm::GlobalValue::PrivateLinkage : VFTableLinkage;