Skip to content

Commit 85318ba

Browse files
authored
[MachineLateInstrsCleanup] Handle multiple kills for a preceding definition. (#119132)
When removing a redundant definition in order to reuse an earlier identical one it is necessary to remove any earlier kill flag as well. Previously, the assumption has been that any register that kills the defined Reg is enough to handle for this purpose, but this is actually not quite enough. A kill of a super-register does not necessarily imply that all of its subregs (including Reg) is defined at that point: a partial definition of a register is legal. This means Reg may have been killed earlier and is not live at that point. This patch changes the tracking of kill flags to allow for multiple flags to be removed: instead of remembering just the single / latest kill flag, a vector is now used to track and remove them all. TinyPtrVector seems ideal for this as there are only very rarely more than one kill flag, and it doesn't seem to give much difference in compile time. The kill flags handling here is making this pass much more complicated than it would have to be. This pass does not depend on kill flags for its own use, so an interesting alternative to all this handling would be to just remove them all. If there actually is a serious user, maybe that pass could instead recompute them. Also adding an assertion which is unrelated to kill flags, but it seems to make sense (according to liberal assertion policy), to verify that the preceding definition is in fact identical in clearKillsForDef(). Fixes #117783
1 parent 28ffa7f commit 85318ba

File tree

2 files changed

+100
-18
lines changed

2 files changed

+100
-18
lines changed

llvm/lib/CodeGen/MachineLateInstrsCleanup.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,17 @@ class MachineLateInstrsCleanup {
4848
return MI && MI->isIdenticalTo(*ArgMI);
4949
}
5050
};
51-
51+
typedef SmallDenseMap<Register, TinyPtrVector<MachineInstr *>> Reg2MIVecMap;
5252
std::vector<Reg2MIMap> RegDefs;
53-
std::vector<Reg2MIMap> RegKills;
53+
std::vector<Reg2MIVecMap> RegKills;
5454

5555
// Walk through the instructions in MBB and remove any redundant
5656
// instructions.
5757
bool processBlock(MachineBasicBlock *MBB);
5858

5959
void removeRedundantDef(MachineInstr *MI);
6060
void clearKillsForDef(Register Reg, MachineBasicBlock *MBB,
61-
BitVector &VisitedPreds);
61+
BitVector &VisitedPreds, MachineInstr *ToRemoveMI);
6262

6363
public:
6464
bool run(MachineFunction &MF);
@@ -135,33 +135,39 @@ bool MachineLateInstrsCleanup::run(MachineFunction &MF) {
135135
// definition.
136136
void MachineLateInstrsCleanup::clearKillsForDef(Register Reg,
137137
MachineBasicBlock *MBB,
138-
BitVector &VisitedPreds) {
138+
BitVector &VisitedPreds,
139+
MachineInstr *ToRemoveMI) {
139140
VisitedPreds.set(MBB->getNumber());
140141

141-
// Kill flag in MBB
142-
if (MachineInstr *KillMI = RegKills[MBB->getNumber()].lookup(Reg)) {
143-
KillMI->clearRegisterKills(Reg, TRI);
144-
return;
145-
}
142+
// Clear kill flag(s) in MBB, that have been seen after the preceding
143+
// definition. If Reg or one of its subregs was killed, it would actually
144+
// be ok to stop after removing that (and any other) kill-flag, but it
145+
// doesn't seem noticeably faster while it would be a bit more complicated.
146+
Reg2MIVecMap &MBBKills = RegKills[MBB->getNumber()];
147+
if (auto Kills = MBBKills.find(Reg); Kills != MBBKills.end())
148+
for (auto *KillMI : Kills->second)
149+
KillMI->clearRegisterKills(Reg, TRI);
146150

147-
// Def in MBB (missing kill flag)
148-
if (MachineInstr *DefMI = RegDefs[MBB->getNumber()].lookup(Reg))
149-
if (DefMI->getParent() == MBB)
150-
return;
151+
// Definition in current MBB: done.
152+
Reg2MIMap &MBBDefs = RegDefs[MBB->getNumber()];
153+
MachineInstr *DefMI = MBBDefs[Reg];
154+
assert(DefMI->isIdenticalTo(*ToRemoveMI) && "Previous def not identical?");
155+
if (DefMI->getParent() == MBB)
156+
return;
151157

152158
// If an earlier def is not in MBB, continue in predecessors.
153159
if (!MBB->isLiveIn(Reg))
154160
MBB->addLiveIn(Reg);
155161
assert(!MBB->pred_empty() && "Predecessor def not found!");
156162
for (MachineBasicBlock *Pred : MBB->predecessors())
157163
if (!VisitedPreds.test(Pred->getNumber()))
158-
clearKillsForDef(Reg, Pred, VisitedPreds);
164+
clearKillsForDef(Reg, Pred, VisitedPreds, ToRemoveMI);
159165
}
160166

161167
void MachineLateInstrsCleanup::removeRedundantDef(MachineInstr *MI) {
162168
Register Reg = MI->getOperand(0).getReg();
163169
BitVector VisitedPreds(MI->getMF()->getNumBlockIDs());
164-
clearKillsForDef(Reg, MI->getParent(), VisitedPreds);
170+
clearKillsForDef(Reg, MI->getParent(), VisitedPreds, MI);
165171
MI->eraseFromParent();
166172
++NumRemoved;
167173
}
@@ -197,7 +203,7 @@ static bool isCandidate(const MachineInstr *MI, Register &DefedReg,
197203
bool MachineLateInstrsCleanup::processBlock(MachineBasicBlock *MBB) {
198204
bool Changed = false;
199205
Reg2MIMap &MBBDefs = RegDefs[MBB->getNumber()];
200-
Reg2MIMap &MBBKills = RegKills[MBB->getNumber()];
206+
Reg2MIVecMap &MBBKills = RegKills[MBB->getNumber()];
201207

202208
// Find reusable definitions in the predecessor(s).
203209
if (!MBB->pred_empty() && !MBB->isEHPad() &&
@@ -247,8 +253,8 @@ bool MachineLateInstrsCleanup::processBlock(MachineBasicBlock *MBB) {
247253
MBBDefs.erase(Reg);
248254
MBBKills.erase(Reg);
249255
} else if (MI.findRegisterUseOperandIdx(Reg, TRI, true /*isKill*/) != -1)
250-
// Keep track of register kills.
251-
MBBKills[Reg] = &MI;
256+
// Keep track of all instructions that fully or partially kills Reg.
257+
MBBKills[Reg].push_back(&MI);
252258
}
253259

254260
// Record this MI for potential later reuse.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
2+
# RUN: llc -mtriple=s390x-linux-gnu -run-pass=machine-latecleanup %s -o - -mcpu=z16 \
3+
# RUN: -verify-machineinstrs 2>&1 | FileCheck %s
4+
5+
# Kill flag of $r0q (super-reg) needs to be removed, and $r0l needs to be added as live-in.
6+
---
7+
name: fun0
8+
tracksRegLiveness: true
9+
body: |
10+
; CHECK-LABEL: name: fun0
11+
; CHECK: bb.0:
12+
; CHECK-NEXT: successors: %bb.1(0x80000000)
13+
; CHECK-NEXT: {{ $}}
14+
; CHECK-NEXT: renamable $r0l = LHIMux -1
15+
; CHECK-NEXT: J %bb.1
16+
; CHECK-NEXT: {{ $}}
17+
; CHECK-NEXT: bb.1:
18+
; CHECK-NEXT: liveins: $r0l
19+
; CHECK-NEXT: {{ $}}
20+
; CHECK-NEXT: renamable $r1d = LGFI 0
21+
; CHECK-NEXT: ST128 renamable $r0q, $r15d, 168, $noreg
22+
; CHECK-NEXT: ST killed renamable $r0l, $r15d, 160, $noreg
23+
; CHECK-NEXT: Return
24+
bb.0:
25+
renamable $r0l = LHIMux -1
26+
J %bb.1
27+
28+
bb.1:
29+
renamable $r1d = LGFI 0
30+
ST128 killed renamable $r0q, $r15d, 168, $noreg
31+
renamable $r0l = LHIMux -1
32+
ST killed renamable $r0l, $r15d, 160, $noreg
33+
Return
34+
...
35+
36+
# Kill flags of both $r1d and $r0q (super-reg) need to be removed.
37+
---
38+
name: fun1
39+
tracksRegLiveness: true
40+
body: |
41+
bb.0:
42+
; CHECK-LABEL: name: fun1
43+
; CHECK: renamable $r1d = LLILL 1
44+
; CHECK-NEXT: STG renamable $r1d, killed $r15d, 8, $noreg
45+
; CHECK-NEXT: renamable $r0d = LLILL 0
46+
; CHECK-NEXT: ST128 renamable $r0q, $r15d, 0, $noreg
47+
; CHECK-NEXT: STG killed renamable $r1d, killed $r15d, 8, $noreg
48+
; CHECK-NEXT: Return
49+
renamable $r1d = LLILL 1
50+
STG killed renamable $r1d, killed $r15d, 8, $noreg
51+
renamable $r0d = LLILL 0
52+
ST128 killed renamable $r0q, $r15d, 0, $noreg
53+
renamable $r1d = LLILL 1
54+
STG killed renamable $r1d, killed $r15d, 8, $noreg
55+
Return
56+
...
57+
58+
# Kill flags of both $r1l (subreg) and $r1d need to be removed.
59+
---
60+
name: fun2
61+
tracksRegLiveness: true
62+
body: |
63+
bb.0:
64+
; CHECK-LABEL: name: fun2
65+
; CHECK: renamable $r1d = LLILL 1
66+
; CHECK-NEXT: ST renamable $r1l, $r15d, 0, $noreg
67+
; CHECK-NEXT: STG renamable $r1d, $r15d, 8, $noreg
68+
; CHECK-NEXT: STG killed renamable $r1d, $r15d, 16, $noreg
69+
; CHECK-NEXT: Return
70+
renamable $r1d = LLILL 1
71+
ST killed renamable $r1l, $r15d, 0, $noreg
72+
STG killed renamable $r1d, $r15d, 8, $noreg
73+
renamable $r1d = LLILL 1
74+
STG killed renamable $r1d, $r15d, 16, $noreg
75+
Return
76+
...

0 commit comments

Comments
 (0)