diff options
Diffstat (limited to 'lib/Transforms/Scalar/ADCE.cpp')
-rw-r--r-- | lib/Transforms/Scalar/ADCE.cpp | 98 |
1 files changed, 86 insertions, 12 deletions
diff --git a/lib/Transforms/Scalar/ADCE.cpp b/lib/Transforms/Scalar/ADCE.cpp index 590a52da6b192..0eed0240c7416 100644 --- a/lib/Transforms/Scalar/ADCE.cpp +++ b/lib/Transforms/Scalar/ADCE.cpp @@ -22,10 +22,12 @@ #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/Pass.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Transforms/Scalar.h" using namespace llvm; @@ -33,22 +35,70 @@ using namespace llvm; STATISTIC(NumRemoved, "Number of instructions removed"); +static void collectLiveScopes(const DILocalScope &LS, + SmallPtrSetImpl<const Metadata *> &AliveScopes) { + if (!AliveScopes.insert(&LS).second) + return; + + if (isa<DISubprogram>(LS)) + return; + + // Tail-recurse through the scope chain. + collectLiveScopes(cast<DILocalScope>(*LS.getScope()), AliveScopes); +} + +static void collectLiveScopes(const DILocation &DL, + SmallPtrSetImpl<const Metadata *> &AliveScopes) { + // Even though DILocations are not scopes, shove them into AliveScopes so we + // don't revisit them. + if (!AliveScopes.insert(&DL).second) + return; + + // Collect live scopes from the scope chain. + collectLiveScopes(*DL.getScope(), AliveScopes); + + // Tail-recurse through the inlined-at chain. + if (const DILocation *IA = DL.getInlinedAt()) + collectLiveScopes(*IA, AliveScopes); +} + +// Check if this instruction is a runtime call for value profiling and +// if it's instrumenting a constant. +static bool isInstrumentsConstant(Instruction &I) { + if (CallInst *CI = dyn_cast<CallInst>(&I)) + if (Function *Callee = CI->getCalledFunction()) + if (Callee->getName().equals(getInstrProfValueProfFuncName())) + if (isa<Constant>(CI->getArgOperand(0))) + return true; + return false; +} + static bool aggressiveDCE(Function& F) { - SmallPtrSet<Instruction*, 128> Alive; + SmallPtrSet<Instruction*, 32> Alive; SmallVector<Instruction*, 128> Worklist; // Collect the set of "root" instructions that are known live. for (Instruction &I : instructions(F)) { - if (isa<TerminatorInst>(I) || isa<DbgInfoIntrinsic>(I) || I.isEHPad() || - I.mayHaveSideEffects()) { + if (isa<TerminatorInst>(I) || I.isEHPad() || I.mayHaveSideEffects()) { + // Skip any value profile instrumentation calls if they are + // instrumenting constants. + if (isInstrumentsConstant(I)) + continue; Alive.insert(&I); Worklist.push_back(&I); } } - // Propagate liveness backwards to operands. + // Propagate liveness backwards to operands. Keep track of live debug info + // scopes. + SmallPtrSet<const Metadata *, 32> AliveScopes; while (!Worklist.empty()) { Instruction *Curr = Worklist.pop_back_val(); + + // Collect the live debug info scopes attached to this instruction. + if (const DILocation *DL = Curr->getDebugLoc()) + collectLiveScopes(*DL, AliveScopes); + for (Use &OI : Curr->operands()) { if (Instruction *Inst = dyn_cast<Instruction>(OI)) if (Alive.insert(Inst).second) @@ -61,10 +111,30 @@ static bool aggressiveDCE(Function& F) { // value of the function, and may therefore be deleted safely. // NOTE: We reuse the Worklist vector here for memory efficiency. for (Instruction &I : instructions(F)) { - if (!Alive.count(&I)) { - Worklist.push_back(&I); - I.dropAllReferences(); + // Check if the instruction is alive. + if (Alive.count(&I)) + continue; + + if (auto *DII = dyn_cast<DbgInfoIntrinsic>(&I)) { + // Check if the scope of this variable location is alive. + if (AliveScopes.count(DII->getDebugLoc()->getScope())) + continue; + + // Fallthrough and drop the intrinsic. + DEBUG({ + // If intrinsic is pointing at a live SSA value, there may be an + // earlier optimization bug: if we know the location of the variable, + // why isn't the scope of the location alive? + if (Value *V = DII->getVariableLocation()) + if (Instruction *II = dyn_cast<Instruction>(V)) + if (Alive.count(II)) + dbgs() << "Dropping debug info for " << *DII << "\n"; + }); } + + // Prepare to delete. + Worklist.push_back(&I); + I.dropAllReferences(); } for (Instruction *&I : Worklist) { @@ -75,10 +145,14 @@ static bool aggressiveDCE(Function& F) { return !Worklist.empty(); } -PreservedAnalyses ADCEPass::run(Function &F) { - if (aggressiveDCE(F)) - return PreservedAnalyses::none(); - return PreservedAnalyses::all(); +PreservedAnalyses ADCEPass::run(Function &F, FunctionAnalysisManager &) { + if (!aggressiveDCE(F)) + return PreservedAnalyses::all(); + + // FIXME: This should also 'preserve the CFG'. + auto PA = PreservedAnalyses(); + PA.preserve<GlobalsAA>(); + return PA; } namespace { @@ -89,7 +163,7 @@ struct ADCELegacyPass : public FunctionPass { } bool runOnFunction(Function& F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; return aggressiveDCE(F); } |