Index: llvm/trunk/lib/CodeGen/LiveDebugVariables.cpp =================================================================== --- llvm/trunk/lib/CodeGen/LiveDebugVariables.cpp +++ llvm/trunk/lib/CodeGen/LiveDebugVariables.cpp @@ -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 @@ /// 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 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 @@ /// 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 @@ } } -void -UserValue::computeIntervals(MachineRegisterInfo &MRI, - const TargetRegisterInfo &TRI, - LiveIntervals &LIS) { +void UserValue::computeIntervals(MachineRegisterInfo &MRI, + const TargetRegisterInfo &TRI, + LiveIntervals &LIS, LexicalScopes &LS) { SmallVector, 16> Defs; // Collect all defs to be extended (Skipping undefs). @@ -672,17 +677,88 @@ 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 @@ 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); Index: llvm/trunk/test/DebugInfo/X86/dbg-value-dag-combine.ll =================================================================== --- llvm/trunk/test/DebugInfo/X86/dbg-value-dag-combine.ll +++ llvm/trunk/test/DebugInfo/X86/dbg-value-dag-combine.ll @@ -5,10 +5,11 @@ ; 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() Index: llvm/trunk/test/DebugInfo/X86/live-debug-variables.ll =================================================================== --- llvm/trunk/test/DebugInfo/X86/live-debug-variables.ll +++ llvm/trunk/test/DebugInfo/X86/live-debug-variables.ll @@ -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)