summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms')
-rw-r--r--llvm/lib/Transforms/IPO/GlobalDCE.cpp156
-rw-r--r--llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp41
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;
}
OpenPOWER on IntegriCloud