Skip to content

Commit 68ac02c

Browse files
committed
[DebugInstrRef] Pass DBG_INSTR_REFs through register allocation
Both FastRegAlloc and LiveDebugVariables/greedy need to cope with DBG_INSTR_REFs. None of them actually need to take any action, other than passing DBG_INSTR_REFs through: variable location information doesn't refer to any registers at this stage. LiveDebugVariables stashes the instruction information in a tuple, then re-creates it later. This is only necessary as the register allocator doesn't expect to see any debug instructions while it's working. No equivalence classes or interval splitting is required at all! No changes are needed for the fast register allocator, as it just ignores debug instructions. The test added checks that both of them preserve DBG_INSTR_REFs. This also expands ScheduleDAGInstrs.cpp to treat DBG_INSTR_REFs the same as DBG_VALUEs when rescheduling instructions around. The current movement of DBG_VALUEs around is less than ideal, but it's not a regression to make DBG_INSTR_REFs subject to the same movement. Differential Revision: https://reviews.llvm.org/D85757
1 parent d6efc87 commit 68ac02c

File tree

3 files changed

+195
-1
lines changed

3 files changed

+195
-1
lines changed

llvm/lib/CodeGen/LiveDebugVariables.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,11 @@ class LDVImpl {
395395
LiveIntervals *LIS;
396396
const TargetRegisterInfo *TRI;
397397

398+
using StashedInstrRef =
399+
std::tuple<unsigned, unsigned, const DILocalVariable *,
400+
const DIExpression *, DebugLoc>;
401+
std::map<SlotIndex, std::vector<StashedInstrRef>> StashedInstrReferences;
402+
398403
/// Whether emitDebugValues is called.
399404
bool EmitDone = false;
400405

@@ -431,6 +436,16 @@ class LDVImpl {
431436
/// \returns True if the DBG_VALUE instruction should be deleted.
432437
bool handleDebugValue(MachineInstr &MI, SlotIndex Idx);
433438

439+
/// Track a DBG_INSTR_REF. This needs to be removed from the MachineFunction
440+
/// during regalloc -- but there's no need to maintain live ranges, as we
441+
/// refer to a value rather than a location.
442+
///
443+
/// \param MI DBG_INSTR_REF instruction
444+
/// \param Idx Last valid SlotIndex before instruction
445+
///
446+
/// \returns True if the DBG_VALUE instruction should be deleted.
447+
bool handleDebugInstrRef(MachineInstr &MI, SlotIndex Idx);
448+
434449
/// Add DBG_LABEL instruction to UserLabel.
435450
///
436451
/// \param MI DBG_LABEL instruction
@@ -459,6 +474,7 @@ class LDVImpl {
459474
/// Release all memory.
460475
void clear() {
461476
MF = nullptr;
477+
StashedInstrReferences.clear();
462478
userValues.clear();
463479
userLabels.clear();
464480
virtRegToEqClass.clear();
@@ -666,6 +682,19 @@ bool LDVImpl::handleDebugValue(MachineInstr &MI, SlotIndex Idx) {
666682
return true;
667683
}
668684

685+
bool LDVImpl::handleDebugInstrRef(MachineInstr &MI, SlotIndex Idx) {
686+
assert(MI.isDebugRef());
687+
unsigned InstrNum = MI.getOperand(0).getImm();
688+
unsigned OperandNum = MI.getOperand(1).getImm();
689+
auto *Var = MI.getDebugVariable();
690+
auto *Expr = MI.getDebugExpression();
691+
auto &DL = MI.getDebugLoc();
692+
StashedInstrRef Stashed =
693+
std::make_tuple(InstrNum, OperandNum, Var, Expr, DL);
694+
StashedInstrReferences[Idx].push_back(Stashed);
695+
return true;
696+
}
697+
669698
bool LDVImpl::handleDebugLabel(MachineInstr &MI, SlotIndex Idx) {
670699
// DBG_LABEL label
671700
if (MI.getNumOperands() != 1 || !MI.getOperand(0).isMetadata()) {
@@ -713,6 +742,7 @@ bool LDVImpl::collectDebugValues(MachineFunction &mf) {
713742
// Only handle DBG_VALUE in handleDebugValue(). Skip all other
714743
// kinds of debug instructions.
715744
if ((MBBI->isDebugValue() && handleDebugValue(*MBBI, Idx)) ||
745+
(MBBI->isDebugRef() && handleDebugInstrRef(*MBBI, Idx)) ||
716746
(MBBI->isDebugLabel() && handleDebugLabel(*MBBI, Idx))) {
717747
MBBI = MBB->erase(MBBI);
718748
Changed = true;
@@ -1435,6 +1465,28 @@ void LDVImpl::emitDebugValues(VirtRegMap *VRM) {
14351465
LLVM_DEBUG(userLabel->print(dbgs(), TRI));
14361466
userLabel->emitDebugLabel(*LIS, *TII);
14371467
}
1468+
1469+
LLVM_DEBUG(dbgs() << "********** EMITTING INSTR REFERENCES **********\n");
1470+
1471+
// Re-insert any DBG_INSTR_REFs back in the position they were. Ordering
1472+
// is preserved by vector.
1473+
auto Slots = LIS->getSlotIndexes();
1474+
const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_INSTR_REF);
1475+
for (auto &P : StashedInstrReferences) {
1476+
const SlotIndex &Idx = P.first;
1477+
auto *MBB = Slots->getMBBFromIndex(Idx);
1478+
MachineBasicBlock::iterator insertPos = findInsertLocation(MBB, Idx, *LIS);
1479+
for (auto &Stashed : P.second) {
1480+
auto MIB = BuildMI(*MF, std::get<4>(Stashed), RefII);
1481+
MIB.addImm(std::get<0>(Stashed));
1482+
MIB.addImm(std::get<1>(Stashed));
1483+
MIB.addMetadata(std::get<2>(Stashed));
1484+
MIB.addMetadata(std::get<3>(Stashed));
1485+
MachineInstr *New = MIB;
1486+
MBB->insert(insertPos, New);
1487+
}
1488+
}
1489+
14381490
EmitDone = true;
14391491
}
14401492

llvm/lib/CodeGen/ScheduleDAGInstrs.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ void ScheduleDAGInstrs::buildSchedGraph(AAResults *AA,
807807
DbgMI = nullptr;
808808
}
809809

810-
if (MI.isDebugValue()) {
810+
if (MI.isDebugValue() || MI.isDebugRef()) {
811811
DbgMI = &MI;
812812
continue;
813813
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# RUN: llc -start-after=phi-node-elimination -stop-after=virtregrewriter %s -mtriple=x86_64-unknown-unknown -o - -experimental-debug-variable-locations | FileCheck %s
2+
# RUN: llc -O0 -start-after=phi-node-elimination -stop-after=regallocfast %s -mtriple=x86_64-unknown-unknown -o - -experimental-debug-variable-locations | FileCheck %s --check-prefix=FASTREG
3+
#
4+
# Test that DBG_INSTR_REFs can pass through livedebugvariables to the end of
5+
# regalloc without problem. Program body copied from
6+
# livedebugvars-crossbb-interval.mir.
7+
#
8+
# CHECK-LABEL: bb.0:
9+
# CHECK: DBG_INSTR_REF 1, 0
10+
# CHECK-NEXT: JMP_1
11+
# CHECK-LABEL: bb.1:
12+
# CHECK: DBG_INSTR_REF 2, 0
13+
# CHECK-NEXT: JMP_1
14+
# CHECK-LABEL: bb.2:
15+
# CHECK: DBG_INSTR_REF 3, 0
16+
# CHECK-NEXT: CALL64pcrel32
17+
# CHECK-LABEL: bb.3:
18+
# CHECK: DBG_INSTR_REF 4, 0
19+
# CHECK-NEXT: JMP_1
20+
#
21+
#
22+
# The fast register allocator puts some spills in -- these are no-ops as far
23+
# as the slot indexes are concerned. It doesn't matter which side of spills
24+
# the DBG_INSTR_REF lands on.
25+
#
26+
# FASTREG-LABEL: bb.0:
27+
# FASTREG-DAG: DBG_INSTR_REF 1, 0
28+
# FASTREG-DAG: MOV64mr
29+
# FASTREG-DAG: MOV32mr
30+
# FASTREG-NEXT: JMP_1
31+
# FASTREG-LABEL: bb.1:
32+
# FASTREG: DBG_INSTR_REF 2, 0
33+
# FASTREG-NEXT: JMP_1
34+
# FASTREG-LABEL: bb.2:
35+
# FASTREG: DBG_INSTR_REF 3, 0
36+
# FASTREG-NEXT: CALL64pcrel32
37+
# FASTREG-LABEL: bb.3:
38+
# FASTREG-DAG: MOV32rm
39+
# FASTREG-DAG: DBG_INSTR_REF 4, 0
40+
# FASTREG-DAG: MOV32mr
41+
# FASTREG-NEXT: JMP_1
42+
# FASTREG-LABEL: bb.4:
43+
# FASTREG: DBG_INSTR_REF 5, 0
44+
# FASTREG-NEXT: RETQ
45+
46+
--- |
47+
; ModuleID = 'tmp.ll'
48+
source_filename = "tmp.ll"
49+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
50+
51+
%struct.a = type { i32 }
52+
53+
; Function Attrs: nounwind ssp
54+
define i32 @bar() !dbg !4 {
55+
ret i32 0, !dbg !18
56+
}
57+
58+
declare i32 @foo();
59+
60+
; Function Attrs: nounwind readnone speculatable willreturn
61+
declare void @llvm.dbg.value(metadata, metadata, metadata)
62+
63+
!llvm.dbg.cu = !{!0}
64+
!llvm.module.flags = !{!3}
65+
66+
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "asdf", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2)
67+
!1 = !DIFile(filename: "bar.c", directory: "asdf")
68+
!2 = !{}
69+
!3 = !{i32 1, !"Debug Info Version", i32 3}
70+
!4 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 5, type: !5, virtualIndex: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
71+
!5 = !DISubroutineType(types: !6)
72+
!6 = !{!7}
73+
!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
74+
!8 = !{!9, !14}
75+
!9 = !DILocalVariable(name: "b", arg: 1, scope: !4, file: !1, line: 5, type: !10)
76+
!10 = !DIDerivedType(tag: DW_TAG_pointer_type, scope: !0, baseType: !11, size: 64, align: 64)
77+
!11 = !DICompositeType(tag: DW_TAG_structure_type, name: "a", scope: !0, file: !1, line: 1, size: 32, align: 32, elements: !12)
78+
!12 = !{!13}
79+
!13 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !1, file: !1, line: 2, baseType: !7, size: 32, align: 32)
80+
!14 = !DILocalVariable(name: "x", scope: !15, file: !1, line: 6, type: !7)
81+
!15 = distinct !DILexicalBlock(scope: !4, file: !1, line: 5, column: 22)
82+
!16 = !DILocation(line: 5, column: 19, scope: !4)
83+
!17 = !DILocation(line: 6, column: 14, scope: !15)
84+
!18 = !DILocation(line: 8, column: 2, scope: !15)
85+
!19 = !DILocation(line: 7, column: 2, scope: !15)
86+
87+
...
88+
---
89+
name: bar
90+
alignment: 16
91+
tracksRegLiveness: true
92+
registers:
93+
- { id: 0, class: gr64 }
94+
- { id: 1, class: gr32 }
95+
- { id: 2, class: gr64 }
96+
- { id: 3, class: gr64 }
97+
- { id: 4, class: gr32 }
98+
- { id: 5, class: gr32 }
99+
- { id: 6, class: gr32 }
100+
- { id: 7, class: gr32 }
101+
liveins:
102+
- { reg: '$rdi', virtual-reg: '%2' }
103+
- { reg: '$esi', virtual-reg: '%4' }
104+
frameInfo:
105+
hasCalls: true
106+
machineFunctionInfo: {}
107+
body: |
108+
bb.0:
109+
liveins: $rdi, $esi
110+
111+
%4:gr32 = COPY $esi
112+
%2:gr64 = COPY $rdi
113+
%3:gr64 = COPY killed %2
114+
%5:gr32 = COPY killed %4
115+
DBG_INSTR_REF 1, 0, !9, !DIExpression(), debug-location !16
116+
JMP_1 %bb.3
117+
118+
bb.1:
119+
DBG_INSTR_REF 2, 0, !9, !DIExpression(), debug-location !16
120+
JMP_1 %bb.4
121+
122+
bb.2:
123+
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp, debug-location !19
124+
$edi = COPY %6, debug-location !19
125+
$al = MOV8ri 0, debug-location !19
126+
DBG_INSTR_REF 3, 0, !9, !DIExpression(), debug-location !16
127+
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $al, implicit $edi, implicit-def $eax, debug-location !19
128+
ADJCALLSTACKUP64 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp, debug-location !19
129+
%7:gr32 = COPY $eax, debug-location !19
130+
JMP_1 %bb.1
131+
132+
bb.3:
133+
%6:gr32 = MOV32rm %3, 1, $noreg, 0, $noreg, debug-location !17
134+
DBG_INSTR_REF 4, 0, !9, !DIExpression(), debug-location !16
135+
JMP_1 %bb.2
136+
137+
bb.4:
138+
$eax = COPY %5, debug-location !18
139+
DBG_INSTR_REF 5, 0, !9, !DIExpression(), debug-location !16
140+
RETQ implicit $eax, debug-location !18
141+
142+
...

0 commit comments

Comments
 (0)