llvm::Constant * CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, const VTableComponent *Components, unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks, unsigned NumVTableThunks) { SmallVector<llvm::Constant *, 64> Inits; llvm::Type *Int8PtrTy = CGM.Int8PtrTy; llvm::Type *PtrDiffTy = CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); QualType ClassType = CGM.getContext().getTagDeclType(RD); llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(ClassType); unsigned NextVTableThunkIndex = 0; llvm::Constant *PureVirtualFn = 0, *DeletedVirtualFn = 0; for (unsigned I = 0; I != NumComponents; ++I) { VTableComponent Component = Components[I]; llvm::Constant *Init = 0; 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); 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_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 (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); 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); 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; } case VTableComponent::CK_UnusedFunctionPointer: Init = llvm::ConstantExpr::getNullValue(Int8PtrTy); break; }; Inits.push_back(Init); } llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents); return llvm::ConstantArray::get(ArrayType, Inits); }
llvm::Constant *CodeGenVTables::CreateVTableInitializer( const CXXRecordDecl *RD, const VTableComponent *Components, unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks, unsigned NumVTableThunks, llvm::Constant *RTTI) { SmallVector<llvm::Constant *, 64> Inits; llvm::Type *Int8PtrTy = CGM.Int8PtrTy; llvm::Type *PtrDiffTy = CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); unsigned NextVTableThunkIndex = 0; llvm::Constant *PureVirtualFn = nullptr, *DeletedVirtualFn = nullptr; for (unsigned I = 0; I != NumComponents; ++I) { VTableComponent Component = Components[I]; llvm::Constant *Init = nullptr; 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); 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_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<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; } case VTableComponent::CK_UnusedFunctionPointer: Init = llvm::ConstantExpr::getNullValue(Int8PtrTy); break; }; Inits.push_back(Init); } llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents); return llvm::ConstantArray::get(ArrayType, Inits); }