[llvm] r309933 - [LiveDebugVariables] Use lexical scope to trim debug value live intervals

Robert Lougher via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 3 04:54:02 PDT 2017


Author: rlougher
Date: Thu Aug  3 04:54:02 2017
New Revision: 309933

URL: http://llvm.org/viewvc/llvm-project?rev=309933&view=rev
Log:
[LiveDebugVariables] Use lexical scope to trim debug value live intervals

The debug value live intervals computed by Live Debug Variables may extend
beyond the range of the debug location's lexical scope. In this case,
splitting of an interval can result in an interval outside of the scope being
created, causing extra unnecessary DBG_VALUEs to be emitted. To prevent this,
trim the intervals to the lexical scope.

This resolves PR33730.

Reviewers: aprantl

Differential Revision: https://reviews.llvm.org/D35953

Added:
    llvm/trunk/test/DebugInfo/X86/live-debug-variables.ll
Modified:
    llvm/trunk/lib/CodeGen/LiveDebugVariables.cpp
    llvm/trunk/test/DebugInfo/X86/dbg-value-dag-combine.ll

Modified: llvm/trunk/lib/CodeGen/LiveDebugVariables.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveDebugVariables.cpp?rev=309933&r1=309932&r2=309933&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/LiveDebugVariables.cpp (original)
+++ llvm/trunk/lib/CodeGen/LiveDebugVariables.cpp Thu Aug  3 04:54:02 2017
@@ -21,7 +21,9 @@
 
 #include "LiveDebugVariables.h"
 #include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/LexicalScopes.h"
 #include "llvm/CodeGen/LiveIntervalAnalysis.h"
 #include "llvm/CodeGen/MachineDominators.h"
 #include "llvm/CodeGen/MachineFunction.h"
@@ -101,6 +103,10 @@ class UserValue {
   /// Map of slot indices where this value is live.
   LocMap locInts;
 
+  /// Set of interval start indexes that have been trimmed to the
+  /// lexical scope.
+  SmallSet<SlotIndex, 2> trimmedDefs;
+
   /// coalesceLocation - After LocNo was changed, check if it has become
   /// identical to another location, and coalesce them. This may cause LocNo or
   /// a later location to be erased, but no earlier location will be erased.
@@ -229,7 +235,7 @@ public:
   /// computeIntervals - Compute the live intervals of all locations after
   /// collecting all their def points.
   void computeIntervals(MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
-                        LiveIntervals &LIS);
+                        LiveIntervals &LIS, LexicalScopes &LS);
 
   /// splitRegister - Replace OldReg ranges with NewRegs ranges where NewRegs is
   /// live. Returns true if any changes were made.
@@ -627,10 +633,9 @@ UserValue::addDefsFromCopies(LiveInterva
   }
 }
 
-void
-UserValue::computeIntervals(MachineRegisterInfo &MRI,
-                            const TargetRegisterInfo &TRI,
-                            LiveIntervals &LIS) {
+void UserValue::computeIntervals(MachineRegisterInfo &MRI,
+                                 const TargetRegisterInfo &TRI,
+                                 LiveIntervals &LIS, LexicalScopes &LS) {
   SmallVector<std::pair<SlotIndex, unsigned>, 16> Defs;
 
   // Collect all defs to be extended (Skipping undefs).
@@ -672,17 +677,88 @@ UserValue::computeIntervals(MachineRegis
     extendDef(Idx, LocNo, LR, VNI, nullptr, LIS);
   }
 
-  // Finally, erase all the undefs.
+  // Erase all the undefs.
   for (LocMap::iterator I = locInts.begin(); I.valid();)
     if (I.value() == ~0u)
       I.erase();
     else
       ++I;
+
+  // The computed intervals may extend beyond the range of the debug
+  // location's lexical scope. In this case, splitting of an interval
+  // can result in an interval outside of the scope being created,
+  // causing extra unnecessary DBG_VALUEs to be emitted. To prevent
+  // this, trim the intervals to the lexical scope.
+
+  LexicalScope *Scope = LS.findLexicalScope(dl);
+  if (!Scope)
+    return;
+
+  SlotIndex PrevEnd;
+  LocMap::iterator I = locInts.begin();
+
+  // Iterate over the lexical scope ranges. Each time round the loop
+  // we check the intervals for overlap with the end of the previous
+  // range and the start of the next. The first range is handled as
+  // a special case where there is no PrevEnd.
+  for (const InsnRange &Range : Scope->getRanges()) {
+    SlotIndex RStart = LIS.getInstructionIndex(*Range.first);
+    SlotIndex REnd = LIS.getInstructionIndex(*Range.second);
+
+    // At the start of each iteration I has been advanced so that
+    // I.stop() >= PrevEnd. Check for overlap.
+    if (PrevEnd && I.start() < PrevEnd) {
+      SlotIndex IStop = I.stop();
+      unsigned LocNo = I.value();
+
+      // Stop overlaps previous end - trim the end of the interval to
+      // the scope range.
+      I.setStopUnchecked(PrevEnd);
+      ++I;
+
+      // If the interval also overlaps the start of the "next" (i.e.
+      // current) range create a new interval for the remainder (which
+      // may be further trimmed).
+      if (RStart < IStop)
+        I.insert(RStart, IStop, LocNo);
+    }
+
+    // Advance I so that I.stop() >= RStart, and check for overlap.
+    I.advanceTo(RStart);
+    if (!I.valid())
+      return;
+
+    if (I.start() < RStart) {
+      // Interval start overlaps range - trim to the scope range.
+      I.setStartUnchecked(RStart);
+      // Remember that this interval was trimmed.
+      trimmedDefs.insert(RStart);
+    }
+
+    // The end of a lexical scope range is the last instruction in the
+    // range. To convert to an interval we need the index of the
+    // instruction after it.
+    REnd = REnd.getNextIndex();
+
+    // Advance I to first interval outside current range.
+    I.advanceTo(REnd);
+    if (!I.valid())
+      return;
+
+    PrevEnd = REnd;
+  }
+
+  // Check for overlap with end of final range.
+  if (PrevEnd && I.start() < PrevEnd)
+    I.setStopUnchecked(PrevEnd);
 }
 
 void LDVImpl::computeIntervals() {
+  LexicalScopes LS;
+  LS.initialize(*MF);
+
   for (unsigned i = 0, e = userValues.size(); i != e; ++i) {
-    userValues[i]->computeIntervals(MF->getRegInfo(), *TRI, *LIS);
+    userValues[i]->computeIntervals(MF->getRegInfo(), *TRI, *LIS, LS);
     userValues[i]->mapVirtRegs(this);
   }
 }
@@ -957,6 +1033,13 @@ void UserValue::emitDebugValues(VirtRegM
     SlotIndex Start = I.start();
     SlotIndex Stop = I.stop();
     unsigned LocNo = I.value();
+
+    // If the interval start was trimmed to the lexical scope insert the
+    // DBG_VALUE at the previous index (otherwise it appears after the
+    // first instruction in the range).
+    if (trimmedDefs.count(Start))
+      Start = Start.getPrevIndex();
+
     DEBUG(dbgs() << "\t[" << Start << ';' << Stop << "):" << LocNo);
     MachineFunction::iterator MBB = LIS.getMBBFromIndex(Start)->getIterator();
     SlotIndex MBBEnd = LIS.getMBBEndIdx(&*MBB);

Modified: llvm/trunk/test/DebugInfo/X86/dbg-value-dag-combine.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/dbg-value-dag-combine.ll?rev=309933&r1=309932&r2=309933&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/dbg-value-dag-combine.ll (original)
+++ llvm/trunk/test/DebugInfo/X86/dbg-value-dag-combine.ll Thu Aug  3 04:54:02 2017
@@ -5,10 +5,11 @@ target triple = "i686-apple-darwin"
 
 ; There should be a DEBUG_VALUE for each call to llvm.dbg.value
 
-; CHECK:  ##DEBUG_VALUE: __OpenCL_test_kernel:ip <- 
-; CHECK:  ##DEBUG_VALUE: xxx <- 0
-; CHECK:  ##DEBUG_VALUE: gid <- %E{{..$}}
-; CHECK:  ##DEBUG_VALUE: idx <- %E{{..$}}
+; CHECK-LABEL: __OpenCL_test_kernel:
+; CHECK-DAG:  ##DEBUG_VALUE: __OpenCL_test_kernel:ip <- 
+; CHECK-DAG:  ##DEBUG_VALUE: xxx <- 0
+; CHECK-DAG:  ##DEBUG_VALUE: gid <- %E{{..$}}
+; CHECK-DAG:  ##DEBUG_VALUE: idx <- %E{{..$}}
 ; CHECK-NOT:  ##DEBUG_VALUE:
 
 declare <4 x i32> @__amdil_get_global_id_int()

Added: llvm/trunk/test/DebugInfo/X86/live-debug-variables.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/live-debug-variables.ll?rev=309933&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/live-debug-variables.ll (added)
+++ llvm/trunk/test/DebugInfo/X86/live-debug-variables.ll Thu Aug  3 04:54:02 2017
@@ -0,0 +1,77 @@
+; RUN: llc -mtriple=x86_64-linux-gnu -filetype=obj -o - %s | llvm-dwarfdump -debug-dump=loc - | FileCheck %s
+
+; The test inlines the function F four times, with each inlined variable for
+; "i4" sharing the same virtual register. This means the live interval of the
+; register spans all of the inlined callsites, extending beyond the lexical
+; scope of each. Later during register allocation the live interval is split
+; into multiple intervals. Check that this does not generate multiple entries
+; within the debug location (see PR33730).
+;
+; Generated from:
+;
+; extern int foobar(int, int, int, int, int);
+; 
+; int F(int i1, int i2, int i3, int i4, int i5) {
+;   return foobar(i1, i2, i3, i4, i5);
+; }
+; 
+; int foo(int a, int b, int c, int d, int e) {
+;   return F(a,b,c,d,e) +
+;          F(a,b,c,d,e) +
+;          F(a,b,c,d,e) +
+;          F(a,b,c,d,e);
+; }
+
+; CHECK: Beginning address offset
+; CHECK-NOT: Beginning address offset
+
+declare i32 @foobar(i32, i32, i32, i32, i32)
+
+define i32 @foo(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) !dbg !25 {
+entry:
+  tail call void @llvm.dbg.value(metadata i32 %d, i64 0, metadata !15, metadata !17) #3, !dbg !41
+  %call.i = tail call i32 @foobar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) #3, !dbg !43
+  %call.i21 = tail call i32 @foobar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) #3, !dbg !50
+  %add = add nsw i32 %call.i21, %call.i, !dbg !51
+  %call.i22 = tail call i32 @foobar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) #3, !dbg !58
+  %add3 = add nsw i32 %add, %call.i22, !dbg !59
+  %call.i23 = tail call i32 @foobar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) #3, !dbg !66
+  %add5 = add nsw i32 %add3, %call.i23, !dbg !67
+  ret i32 %add5, !dbg !68
+}
+
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 (trunk 308976)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "foo.c", directory: "")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 6.0.0 (trunk 308976)"}
+!7 = distinct !DISubprogram(name: "F", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10, !10, !10, !10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!15}
+!15 = !DILocalVariable(name: "i4", arg: 4, scope: !7, file: !1, line: 3, type: !10)
+!17 = !DIExpression()
+!25 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 7, type: !8, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !26)
+!26 = !{}
+!38 = distinct !DILocation(line: 8, column: 10, scope: !25)
+!41 = !DILocation(line: 3, column: 35, scope: !7, inlinedAt: !38)
+!43 = !DILocation(line: 4, column: 10, scope: !7, inlinedAt: !38)
+!45 = distinct !DILocation(line: 9, column: 10, scope: !25)
+!50 = !DILocation(line: 4, column: 10, scope: !7, inlinedAt: !45)
+!51 = !DILocation(line: 8, column: 23, scope: !25)
+!53 = distinct !DILocation(line: 10, column: 10, scope: !25)
+!58 = !DILocation(line: 4, column: 10, scope: !7, inlinedAt: !53)
+!59 = !DILocation(line: 9, column: 23, scope: !25)
+!61 = distinct !DILocation(line: 11, column: 10, scope: !25)
+!66 = !DILocation(line: 4, column: 10, scope: !7, inlinedAt: !61)
+!67 = !DILocation(line: 10, column: 23, scope: !25)
+!68 = !DILocation(line: 8, column: 3, scope: !25)




More information about the llvm-commits mailing list