diff options
Diffstat (limited to 'llvm/lib/Transforms')
| -rw-r--r-- | llvm/lib/Transforms/IPO/GlobalDCE.cpp | 156 | ||||
| -rw-r--r-- | llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp | 41 |
2 files changed, 36 insertions, 161 deletions
diff --git a/llvm/lib/Transforms/IPO/GlobalDCE.cpp b/llvm/lib/Transforms/IPO/GlobalDCE.cpp index 466d18896ed..86b7f3e49ee 100644 --- a/llvm/lib/Transforms/IPO/GlobalDCE.cpp +++ b/llvm/lib/Transforms/IPO/GlobalDCE.cpp @@ -17,11 +17,9 @@ #include "llvm/Transforms/IPO/GlobalDCE.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/TypeMetadataUtils.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" -#include "llvm/IR/Operator.h" #include "llvm/Pass.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Utils/CtorUtils.h" @@ -31,15 +29,10 @@ using namespace llvm; #define DEBUG_TYPE "globaldce" -static cl::opt<bool> - ClEnableVFE("enable-vfe", cl::Hidden, cl::init(true), cl::ZeroOrMore, - cl::desc("Enable virtual function elimination")); - STATISTIC(NumAliases , "Number of global aliases removed"); STATISTIC(NumFunctions, "Number of functions removed"); STATISTIC(NumIFuncs, "Number of indirect functions removed"); STATISTIC(NumVariables, "Number of global variables removed"); -STATISTIC(NumVFuncs, "Number of virtual functions removed"); namespace { class GlobalDCELegacyPass : public ModulePass { @@ -125,15 +118,6 @@ void GlobalDCEPass::UpdateGVDependencies(GlobalValue &GV) { ComputeDependencies(User, Deps); Deps.erase(&GV); // Remove self-reference. for (GlobalValue *GVU : Deps) { - // If this is a dep from a vtable to a virtual function, and we have - // complete information about all virtual call sites which could call - // though this vtable, then skip it, because the call site information will - // be more precise. - if (VFESafeVTables.count(GVU) && isa<Function>(&GV)) { - LLVM_DEBUG(dbgs() << "Ignoring dep " << GVU->getName() << " -> " - << GV.getName() << "\n"); - continue; - } GVDependencies[GVU].insert(&GV); } } @@ -148,133 +132,12 @@ void GlobalDCEPass::MarkLive(GlobalValue &GV, if (Updates) Updates->push_back(&GV); if (Comdat *C = GV.getComdat()) { - for (auto &&CM : make_range(ComdatMembers.equal_range(C))) { + for (auto &&CM : make_range(ComdatMembers.equal_range(C))) MarkLive(*CM.second, Updates); // Recursion depth is only two because only // globals in the same comdat are visited. - } - } -} - -void GlobalDCEPass::ScanVTables(Module &M) { - SmallVector<MDNode *, 2> Types; - LLVM_DEBUG(dbgs() << "Building type info -> vtable map\n"); - - auto *LTOPostLinkMD = - cast_or_null<ConstantAsMetadata>(M.getModuleFlag("LTOPostLink")); - bool LTOPostLink = - LTOPostLinkMD && - (cast<ConstantInt>(LTOPostLinkMD->getValue())->getZExtValue() != 0); - - for (GlobalVariable &GV : M.globals()) { - Types.clear(); - GV.getMetadata(LLVMContext::MD_type, Types); - if (GV.isDeclaration() || Types.empty()) - continue; - - // Use the typeid metadata on the vtable to build a mapping from typeids to - // the list of (GV, offset) pairs which are the possible vtables for that - // typeid. - for (MDNode *Type : Types) { - Metadata *TypeID = Type->getOperand(1).get(); - - uint64_t Offset = - cast<ConstantInt>( - cast<ConstantAsMetadata>(Type->getOperand(0))->getValue()) - ->getZExtValue(); - - TypeIdMap[TypeID].insert(std::make_pair(&GV, Offset)); - } - - // If the type corresponding to the vtable is private to this translation - // unit, we know that we can see all virtual functions which might use it, - // so VFE is safe. - if (auto GO = dyn_cast<GlobalObject>(&GV)) { - GlobalObject::VCallVisibility TypeVis = GO->getVCallVisibility(); - if (TypeVis == GlobalObject::VCallVisibilityTranslationUnit || - (LTOPostLink && - TypeVis == GlobalObject::VCallVisibilityLinkageUnit)) { - LLVM_DEBUG(dbgs() << GV.getName() << " is safe for VFE\n"); - VFESafeVTables.insert(&GV); - } - } - } -} - -void GlobalDCEPass::ScanVTableLoad(Function *Caller, Metadata *TypeId, - uint64_t CallOffset) { - for (auto &VTableInfo : TypeIdMap[TypeId]) { - GlobalVariable *VTable = VTableInfo.first; - uint64_t VTableOffset = VTableInfo.second; - - Constant *Ptr = - getPointerAtOffset(VTable->getInitializer(), VTableOffset + CallOffset, - *Caller->getParent()); - if (!Ptr) { - LLVM_DEBUG(dbgs() << "can't find pointer in vtable!\n"); - VFESafeVTables.erase(VTable); - return; - } - - auto Callee = dyn_cast<Function>(Ptr->stripPointerCasts()); - if (!Callee) { - LLVM_DEBUG(dbgs() << "vtable entry is not function pointer!\n"); - VFESafeVTables.erase(VTable); - return; - } - - LLVM_DEBUG(dbgs() << "vfunc dep " << Caller->getName() << " -> " - << Callee->getName() << "\n"); - GVDependencies[Caller].insert(Callee); } } -void GlobalDCEPass::ScanTypeCheckedLoadIntrinsics(Module &M) { - LLVM_DEBUG(dbgs() << "Scanning type.checked.load intrinsics\n"); - Function *TypeCheckedLoadFunc = - M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load)); - - if (!TypeCheckedLoadFunc) - return; - - for (auto U : TypeCheckedLoadFunc->users()) { - auto CI = dyn_cast<CallInst>(U); - if (!CI) - continue; - - auto *Offset = dyn_cast<ConstantInt>(CI->getArgOperand(1)); - Value *TypeIdValue = CI->getArgOperand(2); - auto *TypeId = cast<MetadataAsValue>(TypeIdValue)->getMetadata(); - - if (Offset) { - ScanVTableLoad(CI->getFunction(), TypeId, Offset->getZExtValue()); - } else { - // type.checked.load with a non-constant offset, so assume every entry in - // every matching vtable is used. - for (auto &VTableInfo : TypeIdMap[TypeId]) { - VFESafeVTables.erase(VTableInfo.first); - } - } - } -} - -void GlobalDCEPass::AddVirtualFunctionDependencies(Module &M) { - if (!ClEnableVFE) - return; - - ScanVTables(M); - - if (VFESafeVTables.empty()) - return; - - ScanTypeCheckedLoadIntrinsics(M); - - LLVM_DEBUG( - dbgs() << "VFE safe vtables:\n"; - for (auto *VTable : VFESafeVTables) - dbgs() << " " << VTable->getName() << "\n"; - ); -} - PreservedAnalyses GlobalDCEPass::run(Module &M, ModuleAnalysisManager &MAM) { bool Changed = false; @@ -300,10 +163,6 @@ PreservedAnalyses GlobalDCEPass::run(Module &M, ModuleAnalysisManager &MAM) { if (Comdat *C = GA.getComdat()) ComdatMembers.insert(std::make_pair(C, &GA)); - // Add dependencies between virtual call sites and the virtual functions they - // might call, if we have that information. - AddVirtualFunctionDependencies(M); - // Loop over the module, adding globals which are obviously necessary. for (GlobalObject &GO : M.global_objects()) { Changed |= RemoveUnusedGlobalValue(GO); @@ -398,17 +257,8 @@ PreservedAnalyses GlobalDCEPass::run(Module &M, ModuleAnalysisManager &MAM) { }; NumFunctions += DeadFunctions.size(); - for (Function *F : DeadFunctions) { - if (!F->use_empty()) { - // Virtual functions might still be referenced by one or more vtables, - // but if we've proven them to be unused then it's safe to replace the - // virtual function pointers with null, allowing us to remove the - // function itself. - ++NumVFuncs; - F->replaceAllUsesWith(ConstantPointerNull::get(F->getType())); - } + for (Function *F : DeadFunctions) EraseUnusedGlobalValue(F); - } NumVariables += DeadGlobalVars.size(); for (GlobalVariable *GV : DeadGlobalVars) @@ -427,8 +277,6 @@ PreservedAnalyses GlobalDCEPass::run(Module &M, ModuleAnalysisManager &MAM) { ConstantDependenciesCache.clear(); GVDependencies.clear(); ComdatMembers.clear(); - TypeIdMap.clear(); - VFESafeVTables.clear(); if (Changed) return PreservedAnalyses::none(); diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp index 52a7dae533b..4055fe04999 100644 --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -496,6 +496,7 @@ struct DevirtModule { void buildTypeIdentifierMap( std::vector<VTableBits> &Bits, DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap); + Constant *getPointerAtOffset(Constant *I, uint64_t Offset); bool tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot, const std::set<TypeMemberInfo> &TypeMemberInfos, @@ -812,6 +813,38 @@ void DevirtModule::buildTypeIdentifierMap( } } +Constant *DevirtModule::getPointerAtOffset(Constant *I, uint64_t Offset) { + if (I->getType()->isPointerTy()) { + if (Offset == 0) + return I; + return nullptr; + } + + const DataLayout &DL = M.getDataLayout(); + + if (auto *C = dyn_cast<ConstantStruct>(I)) { + const StructLayout *SL = DL.getStructLayout(C->getType()); + if (Offset >= SL->getSizeInBytes()) + return nullptr; + + unsigned Op = SL->getElementContainingOffset(Offset); + return getPointerAtOffset(cast<Constant>(I->getOperand(Op)), + Offset - SL->getElementOffset(Op)); + } + if (auto *C = dyn_cast<ConstantArray>(I)) { + ArrayType *VTableTy = C->getType(); + uint64_t ElemSize = DL.getTypeAllocSize(VTableTy->getElementType()); + + unsigned Op = Offset / ElemSize; + if (Op >= C->getNumOperands()) + return nullptr; + + return getPointerAtOffset(cast<Constant>(I->getOperand(Op)), + Offset % ElemSize); + } + return nullptr; +} + bool DevirtModule::tryFindVirtualCallTargets( std::vector<VirtualCallTarget> &TargetsForSlot, const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset) { @@ -820,7 +853,7 @@ bool DevirtModule::tryFindVirtualCallTargets( return false; Constant *Ptr = getPointerAtOffset(TM.Bits->GV->getInitializer(), - TM.Offset + ByteOffset, M); + TM.Offset + ByteOffset); if (!Ptr) return false; @@ -1908,12 +1941,6 @@ bool DevirtModule::run() { for (VTableBits &B : Bits) rebuildGlobal(B); - // We have lowered or deleted the type checked load intrinsics, so we no - // longer have enough information to reason about the liveness of virtual - // function pointers in GlobalDCE. - for (GlobalVariable &GV : M.globals()) - GV.eraseMetadata(LLVMContext::MD_vcall_visibility); - return true; } |

