EntryIndex DbgValueHistoryMap::startClobber(InlinedEntity Var,
const MachineInstr &MI) {
auto &Entries = VarEntries[Var];
+ // If an instruction clobbers multiple registers that the variable is
+ // described by, then we may have already created a clobbering instruction.
+ if (Entries.back().isClobber() && Entries.back().getInstr() == &MI)
+ return Entries.size() - 1;
Entries.emplace_back(&MI, Entry::Clobber);
return Entries.size() - 1;
}
EndIndex = Index;
}
-unsigned DbgValueHistoryMap::getRegisterForVar(InlinedEntity Var) const {
- const auto &I = VarEntries.find(Var);
- if (I == VarEntries.end())
- return 0;
- const auto &Entries = I->second;
- if (Entries.empty() || Entries.back().isClosed())
- return 0;
- if (Entries.back().isClobber())
- return 0;
- return isDescribedByReg(*Entries.back().getInstr());
-}
-
void DbgLabelInstrMap::addInstr(InlinedEntity Label, const MachineInstr &MI) {
assert(MI.isDebugLabel() && "not a DBG_LABEL");
LabelInstr[Label] = &MI;
VarSet.push_back(Var);
}
+/// Create a clobbering entry and end all open debug value entries
+/// for \p Var that are described by \p RegNo using that entry.
static void clobberRegEntries(InlinedEntity Var, unsigned RegNo,
const MachineInstr &ClobberingInstr,
DbgValueEntriesMap &LiveEntries,
DbgValueHistoryMap &HistMap) {
EntryIndex ClobberIndex = HistMap.startClobber(Var, ClobberingInstr);
- // TODO: Close all preceding live entries that are clobbered by this
- // instruction.
- EntryIndex ValueIndex = ClobberIndex - 1;
- auto &ValueEntry = HistMap.getEntry(Var, ValueIndex);
- ValueEntry.endEntry(ClobberIndex);
- LiveEntries[Var].erase(ValueIndex);
+ // Close all entries whose values are described by the register.
+ SmallVector<EntryIndex, 4> IndicesToErase;
+ for (auto Index : LiveEntries[Var]) {
+ auto &Entry = HistMap.getEntry(Var, Index);
+ assert(Entry.isDbgValue() && "Not a DBG_VALUE in LiveEntries");
+ if (isDescribedByReg(*Entry.getInstr()) == RegNo) {
+ IndicesToErase.push_back(Index);
+ Entry.endEntry(ClobberIndex);
+ }
+ }
+
+ // Drop all entries that have ended.
+ for (auto Index : IndicesToErase)
+ LiveEntries[Var].erase(Index);
}
/// Add a new debug value for \p Var. Closes all overlapping debug values.
RegDescribedVarsMap &RegVars,
DbgValueEntriesMap &LiveEntries,
DbgValueHistoryMap &HistMap) {
- // TODO: We should track all registers which this variable is currently
- // described by.
-
- if (unsigned PrevReg = HistMap.getRegisterForVar(Var))
- dropRegDescribedVar(RegVars, PrevReg, Var);
-
EntryIndex NewIndex;
if (HistMap.startDbgValue(Var, DV, NewIndex)) {
+ SmallDenseMap<unsigned, bool, 4> TrackedRegs;
+
// If we have created a new debug value entry, close all preceding
// live entries that overlap.
SmallVector<EntryIndex, 4> IndicesToErase;
auto &Entry = HistMap.getEntry(Var, Index);
assert(Entry.isDbgValue() && "Not a DBG_VALUE in LiveEntries");
const MachineInstr &DV = *Entry.getInstr();
- if (DIExpr->fragmentsOverlap(DV.getDebugExpression())) {
+ bool Overlaps = DIExpr->fragmentsOverlap(DV.getDebugExpression());
+ if (Overlaps) {
IndicesToErase.push_back(Index);
Entry.endEntry(NewIndex);
}
+ if (unsigned Reg = isDescribedByReg(DV))
+ TrackedRegs[Reg] |= !Overlaps;
+ }
+
+ // If the new debug value is described by a register, add tracking of
+ // that register if it is not already tracked.
+ if (unsigned NewReg = isDescribedByReg(DV)) {
+ if (!TrackedRegs.count(NewReg))
+ addRegDescribedVar(RegVars, NewReg, Var);
+ LiveEntries[Var].insert(NewIndex);
+ TrackedRegs[NewReg] = true;
}
+
+ // Drop tracking of registers that are no longer used.
+ for (auto I : TrackedRegs)
+ if (!I.second)
+ dropRegDescribedVar(RegVars, I.first, Var);
+
// Drop all entries that have ended, and mark the new entry as live.
for (auto Index : IndicesToErase)
LiveEntries[Var].erase(Index);
LiveEntries[Var].insert(NewIndex);
}
-
- if (unsigned NewReg = isDescribedByReg(DV))
- addRegDescribedVar(RegVars, NewReg, Var);
}
// Terminate the location range for variables described by register at
# return local[1];
# }
#
+# int test2() {
+# int local[3] = {global1, global2, global3};
+# ext3(local[0], local[1], local[2]);
+# return local[0];
+# }
+#
# Compiled using -O1 -g.
--- |
declare void @ext2(i32, i32)
+ ; Function Attrs: nounwind uwtable
+ define i32 @test2() #0 !dbg !18 {
+ entry:
+ %0 = load i32, i32* @global1, align 4, !dbg !20
+ call void @llvm.dbg.value(metadata i32 %0, metadata !19, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !20
+ %1 = load i32, i32* @global2, align 4, !dbg !20
+ call void @llvm.dbg.value(metadata i32 %1, metadata !19, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !20
+ %2 = load i32, i32* @global3, align 4, !dbg !20
+ call void @llvm.dbg.value(metadata i32 %2, metadata !19, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 32)), !dbg !20
+ tail call void @ext3(i32 %0, i32 %1, i32 %2) #3, !dbg !20
+ ret i32 %0, !dbg !21
+ }
+
+ declare void @ext3(i32, i32, i32)
+
; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
!15 = !DISubrange(count: 3)
!16 = !DILocation(line: 8, scope: !8)
!17 = !DILocation(line: 9, scope: !8)
+ !18 = distinct !DISubprogram(name: "test2", scope: !2, file: !2, line: 7, type: !9, scopeLine: 7, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !1, retainedNodes: !11)
+ !19 = !DILocalVariable(name: "local", scope: !18, file: !2, line: 8, type: !13)
+ !20 = !DILocation(line: 15, scope: !18)
+ !21 = !DILocation(line: 16, scope: !18)
...
---
# CHECK: callq ext2
# CHECK-NEXT: .Ltmp2:
+...
+---
+name: test2
+tracksRegLiveness: true
+body: |
+ bb.0.entry:
+ liveins: $rbx
+
+ frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp, debug-location !20
+ renamable $ebx = MOV32rm $rip, 1, $noreg, @global1, $noreg, debug-location !20 :: (dereferenceable load 4 from @global1)
+ DBG_VALUE $ebx, $noreg, !19, !DIExpression(DW_OP_LLVM_fragment, 0, 32), debug-location !20
+ renamable $esi = MOV32rm $rip, 1, $noreg, @global2, $noreg, debug-location !20 :: (dereferenceable load 4 from @global2)
+ DBG_VALUE $esi, $noreg, !19, !DIExpression(DW_OP_LLVM_fragment, 32, 32), debug-location !20
+ renamable $edx = MOV32rm $rip, 1, $noreg, @global3, $noreg, debug-location !20 :: (dereferenceable load 4 from @global3)
+ DBG_VALUE $edx, $noreg, !19, !DIExpression(DW_OP_LLVM_fragment, 64, 32), debug-location !20
+ $edi = MOV32rr $ebx, debug-location !20
+ CALL64pcrel32 @ext3, csr_64, implicit $rsp, implicit $ssp, implicit killed $edi, implicit $esi, implicit $edx, implicit-def $rsp, implicit-def $ssp, debug-location !20
+ $eax = MOV32rr killed $ebx, debug-location !20
+ $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !20
+ RETQ killed $eax, debug-location !21
+
+...
+
+# CHECK: .Ltmp4:
+# CHECK-NEXT: #DEBUG_VALUE: test2:local <- [DW_OP_LLVM_fragment 0 32] $ebx
+# CHECK: .Ltmp5:
+# CHECK-NEXT: #DEBUG_VALUE: test2:local <- [DW_OP_LLVM_fragment 32 32] $esi
+# CHECK: .Ltmp6:
+# CHECK-NEXT: #DEBUG_VALUE: test2:local <- [DW_OP_LLVM_fragment 64 32] $edx
+# CHECK: callq ext3
+# CHECK-NEXT: .Ltmp7:
+# CHECK: popq %rbx
+# CHECK-NEXT: .Ltmp8:
+
#### Location list for test1:local.
# Verify that a location list entry, which does not contain the fragment that
# CHECK-NEXT: .quad 0
# CHECK-NEXT: .quad 0
+#### Location list for test2:local.
+
+# Verify that the debug values that are described by $edi and $edx are
+# considered clobbered by the call to ext3(), leaving a location list entry
+# after the call where the first 32 bits are still described by $ebx.
+# That location list entry is valid until the restore of the register.
+
+# CHECK: .Ldebug_loc1:
+# CHECK-NEXT: .quad .Ltmp4-.Lfunc_begin0
+# CHECK-NEXT: .quad .Ltmp5-.Lfunc_begin0
+# CHECK-NEXT: .short 3 # Loc expr size
+# CHECK-NEXT: .byte 83 # super-register DW_OP_reg3
+# CHECK-NEXT: .byte 147 # DW_OP_piece
+# CHECK-NEXT: .byte 4 # 4
+# CHECK-NEXT: .quad .Ltmp5-.Lfunc_begin0
+# CHECK-NEXT: .quad .Ltmp6-.Lfunc_begin0
+# CHECK-NEXT: .short 6 # Loc expr size
+# CHECK-NEXT: .byte 83 # super-register DW_OP_reg3
+# CHECK-NEXT: .byte 147 # DW_OP_piece
+# CHECK-NEXT: .byte 4 # 4
+# CHECK-NEXT: .byte 84 # super-register DW_OP_reg4
+# CHECK-NEXT: .byte 147 # DW_OP_piece
+# CHECK-NEXT: .byte 4 # 4
+# CHECK-NEXT: .quad .Ltmp6-.Lfunc_begin0
+# CHECK-NEXT: .quad .Ltmp7-.Lfunc_begin0
+# CHECK-NEXT: .short 9 # Loc expr size
+# CHECK-NEXT: .byte 83 # super-register DW_OP_reg3
+# CHECK-NEXT: .byte 147 # DW_OP_piece
+# CHECK-NEXT: .byte 4 # 4
+# CHECK-NEXT: .byte 84 # super-register DW_OP_reg4
+# CHECK-NEXT: .byte 147 # DW_OP_piece
+# CHECK-NEXT: .byte 4 # 4
+# CHECK-NEXT: .byte 81 # super-register DW_OP_reg1
+# CHECK-NEXT: .byte 147 # DW_OP_piece
+# CHECK-NEXT: .byte 4 # 4
+# CHECK-NEXT: .quad .Ltmp7-.Lfunc_begin0
+# CHECK-NEXT: .quad .Ltmp8-.Lfunc_begin0
+# CHECK-NEXT: .short 3 # Loc expr size
+# CHECK-NEXT: .byte 83 # super-register DW_OP_reg3
+# CHECK-NEXT: .byte 147 # DW_OP_piece
+# CHECK-NEXT: .byte 4 # 4
+# CHECK-NEXT: .quad 0
+# CHECK-NEXT: .quad 0