Skip to content

Commit f5e1b71

Browse files
committed
[DebugInfo] MachineSink: find more DBG_VALUEs to sink
In the Pre-RA machine sinker, previously we were relying on all DBG_VALUEs being immediately after the instruction that defined their operands. This isn't a valid assumption, as a variable location change doesn't necessarily correspond to where the value is computed. In this patch, we collect DBG_VALUEs that might need sinking as we walk through a block, and sink all of them if their defining instruction is sunk. This patch adds some copy propagation too, so that if we sink a copy inst, the now non-dominated paths can use the copy source for the variable location. Differential Revision: https://reviews.llvm.org/D58386
1 parent 1ebd4a2 commit f5e1b71

File tree

2 files changed

+191
-15
lines changed

2 files changed

+191
-15
lines changed

llvm/lib/CodeGen/MachineSink.cpp

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ namespace {
105105
using AllSuccsCache =
106106
std::map<MachineBasicBlock *, SmallVector<MachineBasicBlock *, 4>>;
107107

108+
// Remember debug uses of vregs seen, so we know what to sink out of blocks.
109+
DenseMap<unsigned, TinyPtrVector<MachineInstr *>> SeenDbgUsers;
110+
108111
public:
109112
static char ID; // Pass identification
110113

@@ -132,6 +135,7 @@ namespace {
132135

133136
private:
134137
bool ProcessBlock(MachineBasicBlock &MBB);
138+
void ProcessDbgInst(MachineInstr &MI);
135139
bool isWorthBreakingCriticalEdge(MachineInstr &MI,
136140
MachineBasicBlock *From,
137141
MachineBasicBlock *To);
@@ -153,8 +157,14 @@ namespace {
153157
MachineBasicBlock *To,
154158
bool BreakPHIEdge);
155159
bool SinkInstruction(MachineInstr &MI, bool &SawStore,
156-
157160
AllSuccsCache &AllSuccessors);
161+
162+
/// If we sink a COPY inst, some debug users of it's destination may no
163+
/// longer be dominated by the COPY, and will eventually be dropped.
164+
/// This is easily rectified by forwarding the non-dominated debug uses
165+
/// to the copy source.
166+
void SalvageUnsunkDebugUsersOfCopy(MachineInstr &,
167+
MachineBasicBlock *TargetBlock);
158168
bool AllUsesDominatedByBlock(unsigned Reg, MachineBasicBlock *MBB,
159169
MachineBasicBlock *DefMBB,
160170
bool &BreakPHIEdge, bool &LocalUse) const;
@@ -367,8 +377,11 @@ bool MachineSinking::ProcessBlock(MachineBasicBlock &MBB) {
367377
if (!ProcessedBegin)
368378
--I;
369379

370-
if (MI.isDebugInstr())
380+
if (MI.isDebugInstr()) {
381+
if (MI.isDebugValue())
382+
ProcessDbgInst(MI);
371383
continue;
384+
}
372385

373386
bool Joined = PerformTrivialForwardCoalescing(MI, &MBB);
374387
if (Joined) {
@@ -384,9 +397,23 @@ bool MachineSinking::ProcessBlock(MachineBasicBlock &MBB) {
384397
// If we just processed the first instruction in the block, we're done.
385398
} while (!ProcessedBegin);
386399

400+
SeenDbgUsers.clear();
401+
387402
return MadeChange;
388403
}
389404

405+
void MachineSinking::ProcessDbgInst(MachineInstr &MI) {
406+
// When we see DBG_VALUEs for registers, record any vreg it reads, so that
407+
// we know what to sink if the vreg def sinks.
408+
assert(MI.isDebugValue() && "Expected DBG_VALUE for processing");
409+
410+
MachineOperand &MO = MI.getOperand(0);
411+
if (!MO.isReg() || !MO.getReg().isVirtual())
412+
return;
413+
414+
SeenDbgUsers[MO.getReg()].push_back(&MI);
415+
}
416+
390417
bool MachineSinking::isWorthBreakingCriticalEdge(MachineInstr &MI,
391418
MachineBasicBlock *From,
392419
MachineBasicBlock *To) {
@@ -731,22 +758,13 @@ static bool SinkingPreventsImplicitNullCheck(MachineInstr &MI,
731758
MBP.LHS.getReg() == BaseOp->getReg();
732759
}
733760

734-
/// Sink an instruction and its associated debug instructions. If the debug
735-
/// instructions to be sunk are already known, they can be provided in DbgVals.
761+
/// Sink an instruction and its associated debug instructions.
736762
static void performSink(MachineInstr &MI, MachineBasicBlock &SuccToSinkTo,
737763
MachineBasicBlock::iterator InsertPos,
738-
SmallVectorImpl<MachineInstr *> *DbgVals = nullptr) {
764+
SmallVectorImpl<MachineInstr *> &DbgValuesToSink) {
739765
const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
740766
const TargetInstrInfo &TII = *MI.getMF()->getSubtarget().getInstrInfo();
741767

742-
// If debug values are provided use those, otherwise call collectDebugValues.
743-
SmallVector<MachineInstr *, 2> DbgValuesToSink;
744-
if (DbgVals)
745-
DbgValuesToSink.insert(DbgValuesToSink.begin(),
746-
DbgVals->begin(), DbgVals->end());
747-
else
748-
MI.collectDebugValues(DbgValuesToSink);
749-
750768
// If we cannot find a location to use (merge with), then we erase the debug
751769
// location to prevent debug-info driven tools from potentially reporting
752770
// wrong location information.
@@ -929,7 +947,25 @@ bool MachineSinking::SinkInstruction(MachineInstr &MI, bool &SawStore,
929947
while (InsertPos != SuccToSinkTo->end() && InsertPos->isPHI())
930948
++InsertPos;
931949

932-
performSink(MI, *SuccToSinkTo, InsertPos);
950+
// Collect debug users of any vreg that this inst defines.
951+
SmallVector<MachineInstr *, 4> DbgUsersToSink;
952+
for (auto &MO : MI.operands()) {
953+
if (!MO.isReg() || !MO.isDef() || !MO.getReg().isVirtual())
954+
continue;
955+
if (!SeenDbgUsers.count(MO.getReg()))
956+
continue;
957+
958+
auto &Users = SeenDbgUsers[MO.getReg()];
959+
DbgUsersToSink.insert(DbgUsersToSink.end(), Users.begin(), Users.end());
960+
}
961+
962+
// After sinking, some debug users may not be dominated any more. If possible,
963+
// copy-propagate their operands. As it's expensive, don't do this if there's
964+
// no debuginfo in the program.
965+
if (MI.getMF()->getFunction().getSubprogram() && MI.isCopy())
966+
SalvageUnsunkDebugUsersOfCopy(MI, SuccToSinkTo);
967+
968+
performSink(MI, *SuccToSinkTo, InsertPos, DbgUsersToSink);
933969

934970
// Conservatively, clear any kill flags, since it's possible that they are no
935971
// longer correct.
@@ -944,6 +980,41 @@ bool MachineSinking::SinkInstruction(MachineInstr &MI, bool &SawStore,
944980
return true;
945981
}
946982

983+
void MachineSinking::SalvageUnsunkDebugUsersOfCopy(
984+
MachineInstr &MI, MachineBasicBlock *TargetBlock) {
985+
assert(MI.isCopy());
986+
assert(MI.getOperand(1).isReg());
987+
988+
// Enumerate all users of vreg operands that are def'd. Skip those that will
989+
// be sunk. For the rest, if they are not dominated by the block we will sink
990+
// MI into, propagate the copy source to them.
991+
SmallVector<MachineInstr *, 4> DbgDefUsers;
992+
const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
993+
for (auto &MO : MI.operands()) {
994+
if (!MO.isReg() || !MO.isDef() || !MO.getReg().isVirtual())
995+
continue;
996+
for (auto &User : MRI.use_instructions(MO.getReg())) {
997+
if (!User.isDebugValue() || DT->dominates(TargetBlock, User.getParent()))
998+
continue;
999+
1000+
// If is in same block, will either sink or be use-before-def.
1001+
if (User.getParent() == MI.getParent())
1002+
continue;
1003+
1004+
assert(User.getOperand(0).isReg() &&
1005+
"DBG_VALUE user of vreg, but non reg operand?");
1006+
DbgDefUsers.push_back(&User);
1007+
}
1008+
}
1009+
1010+
// Point the users of this copy that are no longer dominated, at the source
1011+
// of the copy.
1012+
for (auto *User : DbgDefUsers) {
1013+
User->getOperand(0).setReg(MI.getOperand(1).getReg());
1014+
User->getOperand(0).setSubReg(MI.getOperand(1).getSubReg());
1015+
}
1016+
}
1017+
9471018
//===----------------------------------------------------------------------===//
9481019
// This pass is not intended to be a replacement or a complete alternative
9491020
// for the pre-ra machine sink pass. It is only designed to sink COPY
@@ -1253,7 +1324,7 @@ bool PostRAMachineSinking::tryToSinkCopy(MachineBasicBlock &CurBB,
12531324
// block.
12541325
clearKillFlags(MI, CurBB, UsedOpsInCopy, UsedRegUnits, TRI);
12551326
MachineBasicBlock::iterator InsertPos = SuccBB->getFirstNonPHI();
1256-
performSink(*MI, *SuccBB, InsertPos, &DbgValsToSink);
1327+
performSink(*MI, *SuccBB, InsertPos, DbgValsToSink);
12571328
updateLiveIn(MI, SuccBB, UsedOpsInCopy, DefedRegsInCopy);
12581329

12591330
Changed = true;
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# RUN: llc -mtriple=x86_64-unknown-unknown -run-pass=machine-sink -o - %s | FileCheck %s
2+
# Check various things when we sink machine instructions:
3+
# a) DBG_VALUEs should sink with defs
4+
# b) Undefs should be left behind
5+
# c) DBG_VALUEs not immediately following the defining inst should sink too
6+
# d) If we generate debug-use-before-defs through sinking, and can copy
7+
# propagate to a different value, we should do that.
8+
--- |
9+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
10+
target triple = "x86_64-unknown-linux-gnu"
11+
12+
@x = common local_unnamed_addr global i32 0, align 4, !dbg !0
13+
14+
; Function Attrs: noreturn nounwind uwtable
15+
define void @Process(i32* nocapture readonly %p) local_unnamed_addr !dbg !9 {
16+
; Stripped
17+
entry:
18+
br label %nou
19+
nou:
20+
br label %exit
21+
exit:
22+
ret void
23+
}
24+
25+
; Function Attrs: nounwind readnone
26+
declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
27+
28+
!llvm.dbg.cu = !{!1}
29+
!llvm.module.flags = !{!6, !7}
30+
!llvm.ident = !{!8}
31+
32+
!0 = !DIGlobalVariableExpression(var: !DIGlobalVariable(name: "x", scope: !1, file: !2, line: 1, type: !5, isLocal: false, isDefinition: true), expr: !DIExpression())
33+
!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, globals: !4)
34+
!2 = !DIFile(filename: "t.c", directory: "")
35+
!3 = !{}
36+
!4 = !{!0}
37+
!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
38+
!6 = !{i32 2, !"Dwarf Version", i32 4}
39+
!7 = !{i32 2, !"Debug Info Version", i32 3}
40+
!8 = !{!"clang version 4.0.0 "}
41+
!9 = distinct !DISubprogram(name: "Process", scope: !2, file: !2, line: 2, type: !10, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !1, retainedNodes: !15)
42+
!10 = !DISubroutineType(types: !11)
43+
!11 = !{null, !12}
44+
!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64)
45+
!13 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !14)
46+
!14 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
47+
!15 = !{!16}
48+
!16 = !DILocalVariable(name: "p", arg: 1, scope: !9, file: !2, line: 2, type: !12)
49+
!17 = !DIExpression()
50+
!18 = !DILocation(line: 2, column: 34, scope: !9)
51+
!28 = !DILexicalBlockFile(scope: !9, file: !2, discriminator: 1)
52+
53+
; CHECK: [[VARNUM:![0-9]+]] = !DILocalVariable(name: "p",
54+
55+
...
56+
---
57+
name: Process
58+
tracksRegLiveness: true
59+
liveins:
60+
- { reg: '$rdi', virtual-reg: '%2' }
61+
- { reg: '$rsi', virtual-reg: '%2' }
62+
body: |
63+
bb.0.entry:
64+
successors: %bb.1.nou(0x80000000), %bb.2.exit
65+
liveins: $rdi, $esi
66+
67+
; This block should have the vreg copy sunk from it, the DBG_VALUE with it,
68+
; and a copy-prop'd DBG_VALUE left over.
69+
; CHECK-LABEL: bb.0.entry:
70+
; CHECK: [[ARG0VREG:%[0-9]+]]:gr64 = COPY $rdi
71+
; CHECK-NEXT: CMP32ri $esi, 0
72+
; CHECK-NEXT: DBG_VALUE [[ARG0VREG]], $noreg, [[VARNUM]]
73+
; CHECK-NEXT: JCC_1 %bb.1, 4
74+
; CHECK-NEXT: JMP_1
75+
76+
%2:gr64 = COPY $rdi
77+
%5:gr64 = COPY %2
78+
CMP32ri $esi, 0, implicit-def $eflags
79+
DBG_VALUE %5, $noreg, !16, !17, debug-location !18
80+
JCC_1 %bb.1.nou, 4, implicit $eflags
81+
JMP_1 %bb.2.exit
82+
83+
bb.1.nou:
84+
successors: %bb.2.exit(0x80000000)
85+
86+
; This block should receive the sunk copy and DBG_VALUE
87+
; CHECK-LABEL: bb.1.nou:
88+
; CHECK: [[SUNKVREG:%[0-9]+]]:gr64 = COPY [[ARG0VREG]]
89+
; CHECK-NEXT: DBG_VALUE [[SUNKVREG]], $noreg, [[VARNUM]]
90+
; CHECK-NEXT: ADD64ri8
91+
; CHECK-NEXT: JMP_1
92+
%1:gr64 = ADD64ri8 %5, 4, implicit-def dead $eflags
93+
JMP_1 %bb.2.exit
94+
95+
bb.2.exit:
96+
; The DBG_VALUE below should have its operand copy-propagated after
97+
; the copy to %5 is sunk.
98+
; CHECK-LABEL: bb.2.exit:
99+
; CHECK: DBG_VALUE [[ARG0VREG]], $noreg, [[VARNUM]]
100+
; CHECK-NEXT: $rax = MOV64rr [[ARG0VREG]]
101+
; CHECK-NEXT: RET 0
102+
DBG_VALUE %5, _, !16, !17, debug-location !18
103+
$rax = MOV64rr %2
104+
RET 0
105+
...

0 commit comments

Comments
 (0)