#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"
/// 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.
/// 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.
}
}
-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).
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);
}
}
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);
--- /dev/null
+; 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)