[llvm] r264800 - ADCE: Remove debug info intrinsics in dead scopes

Duncan P. N. Exon Smith via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 29 15:57:12 PDT 2016


Author: dexonsmith
Date: Tue Mar 29 17:57:12 2016
New Revision: 264800

URL: http://llvm.org/viewvc/llvm-project?rev=264800&view=rev
Log:
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.

Added:
    llvm/trunk/test/Transforms/ADCE/debug-info-intrinsic.ll
Modified:
    llvm/trunk/lib/Transforms/Scalar/ADCE.cpp
    llvm/trunk/test/Assembler/2010-02-05-FunctionLocalMetadataBecomesNull.ll

Modified: llvm/trunk/lib/Transforms/Scalar/ADCE.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/ADCE.cpp?rev=264800&r1=264799&r2=264800&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/ADCE.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/ADCE.cpp Tue Mar 29 17:57:12 2016
@@ -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) {

Modified: llvm/trunk/test/Assembler/2010-02-05-FunctionLocalMetadataBecomesNull.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/2010-02-05-FunctionLocalMetadataBecomesNull.ll?rev=264800&r1=264799&r2=264800&view=diff
==============================================================================
--- llvm/trunk/test/Assembler/2010-02-05-FunctionLocalMetadataBecomesNull.ll (original)
+++ llvm/trunk/test/Assembler/2010-02-05-FunctionLocalMetadataBecomesNull.ll Tue Mar 29 17:57:12 2016
@@ -19,7 +19,7 @@ define i32 @main() nounwind readonly !db
   %v2 = ptrtoint %struct.test* %v1 to i64 ; <i64> [#uses=1]
   %v3 = sub i64 %v2, ptrtoint ([10 x %struct.test]* @TestArray to i64) ; <i64> [#uses=1]
   store i64 %v3, i64* %diff1, align 8
-  ret i32 4
+  ret i32 4, !dbg !DILocation(scope: !1)
 }
 
 declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone

Added: llvm/trunk/test/Transforms/ADCE/debug-info-intrinsic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ADCE/debug-info-intrinsic.ll?rev=264800&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/ADCE/debug-info-intrinsic.ll (added)
+++ llvm/trunk/test/Transforms/ADCE/debug-info-intrinsic.ll Tue Mar 29 17:57:12 2016
@@ -0,0 +1,101 @@
+; RUN: opt -adce -S < %s | FileCheck %s
+; Test that debug info intrinsics in dead scopes get eliminated by -adce.
+
+; Generated with 'clang -g -S -emit-llvm | opt -mem2reg -inline' at r262899
+; (before -adce was augmented) and then hand-reduced.  This was the input:
+;
+;;void sink(void);
+;;
+;;void variable_in_unused_subscope(void) {
+;;  { int i = 0; }
+;;  sink();
+;;}
+;;
+;;void variable_in_parent_scope(void) {
+;;  int i = 0;
+;;  { sink(); }
+;;}
+;;
+;;static int empty_function_with_unused_variable(void) {
+;;  { int i = 0; }
+;;  return 0;
+;;}
+;;
+;;void calls_empty_function_with_unused_variable_in_unused_subscope(void) {
+;;  { empty_function_with_unused_variable(); }
+;;  sink();
+;;}
+
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
+
+declare void @sink()
+
+; CHECK-LABEL: define void @variable_in_unused_subscope(
+define void @variable_in_unused_subscope() !dbg !4 {
+; CHECK-NEXT: entry:
+; CHECK-NEXT:   call void @sink
+; CHECK-NEXT:   ret void
+entry:
+  call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !15, metadata !17), !dbg !18
+  call void @sink(), !dbg !19
+  ret void, !dbg !20
+}
+
+; CHECK-LABEL: define void @variable_in_parent_scope(
+define void @variable_in_parent_scope() !dbg !7 {
+; CHECK-NEXT: entry:
+; CHECK-NEXT:   call void @llvm.dbg.value
+; CHECK-NEXT:   call void @sink
+; CHECK-NEXT:   ret void
+entry:
+  call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !21, metadata !17), !dbg !22
+  call void @sink(), !dbg !23
+  ret void, !dbg !25
+}
+
+; CHECK-LABEL: define void @calls_empty_function_with_unused_variable_in_unused_subscope(
+define void @calls_empty_function_with_unused_variable_in_unused_subscope() !dbg !8 {
+; CHECK-NEXT: entry:
+; CHECK-NEXT:   call void @sink
+; CHECK-NEXT:   ret void
+entry:
+  call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !26, metadata !17), !dbg !28
+  call void @sink(), !dbg !31
+  ret void, !dbg !32
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3)
+!1 = !DIFile(filename: "t.c", directory: "/path/to/test/Transforms/ADCE")
+!2 = !{}
+!3 = !{!4, !7, !8, !10}
+!4 = distinct !DISubprogram(name: "variable_in_unused_subscope", scope: !1, file: !1, line: 3, type: !5, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, variables: !2)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null}
+!7 = distinct !DISubprogram(name: "variable_in_parent_scope", scope: !1, file: !1, line: 8, type: !5, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, variables: !2)
+!8 = distinct !DISubprogram(name: "calls_empty_function_with_unused_variable_in_unused_subscope", scope: !1, file: !1, line: 18, type: !5, isLocal: false, isDefinition: true, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false, variables: !2)
+!10 = distinct !DISubprogram(name: "empty_function_with_unused_variable", scope: !1, file: !1, line: 13, type: !11, isLocal: true, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: false, variables: !2)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13}
+!13 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!14 = !{i32 2, !"Debug Info Version", i32 3}
+!15 = !DILocalVariable(name: "i", scope: !16, file: !1, line: 4, type: !13)
+!16 = distinct !DILexicalBlock(scope: !4, file: !1, line: 4, column: 3)
+!17 = !DIExpression()
+!18 = !DILocation(line: 4, column: 9, scope: !16)
+!19 = !DILocation(line: 5, column: 3, scope: !4)
+!20 = !DILocation(line: 6, column: 1, scope: !4)
+!21 = !DILocalVariable(name: "i", scope: !7, file: !1, line: 9, type: !13)
+!22 = !DILocation(line: 9, column: 7, scope: !7)
+!23 = !DILocation(line: 10, column: 5, scope: !24)
+!24 = distinct !DILexicalBlock(scope: !7, file: !1, line: 10, column: 3)
+!25 = !DILocation(line: 11, column: 1, scope: !7)
+!26 = !DILocalVariable(name: "i", scope: !27, file: !1, line: 14, type: !13)
+!27 = distinct !DILexicalBlock(scope: !10, file: !1, line: 14, column: 3)
+!28 = !DILocation(line: 14, column: 9, scope: !27, inlinedAt: !29)
+!29 = distinct !DILocation(line: 19, column: 5, scope: !30)
+!30 = distinct !DILexicalBlock(scope: !8, file: !1, line: 19, column: 3)
+!31 = !DILocation(line: 20, column: 3, scope: !8)
+!32 = !DILocation(line: 21, column: 1, scope: !8)




More information about the llvm-commits mailing list