summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/Scalar/ADCE.cpp
diff options
context:
space:
mode:
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>2016-03-29 22:57:12 +0000
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>2016-03-29 22:57:12 +0000
commite8eb94a9a5406f60d513132a6303e3a294b0f3e4 (patch)
treee7d47f6c0e8f5550f83a439faaa2a0dffb7ab1ba /llvm/lib/Transforms/Scalar/ADCE.cpp
parent44a2f7a298db043bad5305a138520ad7aa68a95c (diff)
downloadbcm5719-llvm-e8eb94a9a5406f60d513132a6303e3a294b0f3e4.tar.gz
bcm5719-llvm-e8eb94a9a5406f60d513132a6303e3a294b0f3e4.zip
ADCE: Remove debug info intrinsics in dead scopes
During ADCE, track which debug info scopes still have live references from the code, and delete debug info intrinsics for the dead ones. These intrinsics describe the locations of variables (in registers or stack slots). If there's no code left corresponding to a variable's scope, then there's no way to reference the variable in the debugger and it doesn't matter what its value is. I add a DEBUG printout when the described location in an SSA register, in case it helps some trying to track down why locations get lost. However, we still delete these; the scope itself isn't attached to any real code, so the ship has already sailed. llvm-svn: 264800
Diffstat (limited to 'llvm/lib/Transforms/Scalar/ADCE.cpp')
-rw-r--r--llvm/lib/Transforms/Scalar/ADCE.cpp66
1 files changed, 60 insertions, 6 deletions
diff --git a/llvm/lib/Transforms/Scalar/ADCE.cpp b/llvm/lib/Transforms/Scalar/ADCE.cpp
index f3ad9556080..d94f83d66c4 100644
--- a/llvm/lib/Transforms/Scalar/ADCE.cpp
+++ b/llvm/lib/Transforms/Scalar/ADCE.cpp
@@ -22,6 +22,7 @@
#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"
@@ -33,22 +34,55 @@ 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);
+}
+
static bool aggressiveDCE(Function& F) {
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()) {
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 +95,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) {
OpenPOWER on IntegriCloud