Skip to content

Commit cb57b7a

Browse files
committed
[MachineLateInstrsCleanup] Improve compile time for huge functions.
It was discovered that this pass could be slow on huge functions, meaning 20% compile time instead of the usual ~0.5% (with a test case spending ~19 mins just in the backend). The problem related to the necessary clearing of earlier kill flags when a redundant instruction is removed. With this patch, the handling of kill flags is now done by maintaining a map instead of scanning backwards in the function. This remedies the compile time on the huge file fully. Reviewed By: vpykhtin, arsenm Differential Revision: https://reviews.llvm.org/D147532 Resolves #61397
1 parent 7cba800 commit cb57b7a

File tree

1 file changed

+58
-44
lines changed

1 file changed

+58
-44
lines changed

llvm/lib/CodeGen/MachineLateInstrsCleanup.cpp

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,31 @@ class MachineLateInstrsCleanup : public MachineFunctionPass {
4242
const TargetRegisterInfo *TRI = nullptr;
4343
const TargetInstrInfo *TII = nullptr;
4444

45-
// Data structures to map regs to their definitions per MBB.
46-
using Reg2DefMap = std::map<Register, MachineInstr*>;
47-
std::vector<Reg2DefMap> RegDefs;
45+
// Data structures to map regs to their definitions and kills per MBB.
46+
struct Reg2MIMap : public SmallDenseMap<Register, MachineInstr *> {
47+
MachineInstr *get(Register Reg) {
48+
auto I = find(Reg);
49+
return I != end() ? I->second : nullptr;
50+
}
51+
52+
bool hasIdentical(Register Reg, MachineInstr *ArgMI) {
53+
MachineInstr *MI = get(Reg);
54+
return MI && MI->isIdenticalTo(*ArgMI);
55+
}
56+
};
57+
58+
std::vector<Reg2MIMap> RegDefs;
59+
std::vector<Reg2MIMap> RegKills;
4860

4961
// Walk through the instructions in MBB and remove any redundant
5062
// instructions.
5163
bool processBlock(MachineBasicBlock *MBB);
5264

65+
void removeRedundantDef(MachineInstr *MI);
66+
void clearKillsForDef(Register Reg, MachineBasicBlock *MBB,
67+
MachineBasicBlock::iterator I,
68+
BitVector &VisitedPreds);
69+
5370
public:
5471
static char ID; // Pass identification, replacement for typeid
5572

@@ -88,6 +105,8 @@ bool MachineLateInstrsCleanup::runOnMachineFunction(MachineFunction &MF) {
88105

89106
RegDefs.clear();
90107
RegDefs.resize(MF.getNumBlockIDs());
108+
RegKills.clear();
109+
RegKills.resize(MF.getNumBlockIDs());
91110

92111
// Visit all MBBs in an order that maximises the reuse from predecessors.
93112
bool Changed = false;
@@ -102,41 +121,36 @@ bool MachineLateInstrsCleanup::runOnMachineFunction(MachineFunction &MF) {
102121
// in MBB and if needed continue in predecessors until a use/def of Reg is
103122
// encountered. This seems to be faster in practice than tracking kill flags
104123
// in a map.
105-
static void clearKillsForDef(Register Reg, MachineBasicBlock *MBB,
106-
MachineBasicBlock::iterator I,
107-
BitVector &VisitedPreds,
108-
const TargetRegisterInfo *TRI) {
124+
void MachineLateInstrsCleanup::
125+
clearKillsForDef(Register Reg, MachineBasicBlock *MBB,
126+
MachineBasicBlock::iterator I,
127+
BitVector &VisitedPreds) {
109128
VisitedPreds.set(MBB->getNumber());
110-
while (I != MBB->begin()) {
111-
--I;
112-
bool Found = false;
113-
for (auto &MO : I->operands())
114-
if (MO.isReg() && TRI->regsOverlap(MO.getReg(), Reg)) {
115-
if (MO.isDef())
116-
return;
117-
if (MO.readsReg()) {
118-
MO.setIsKill(false);
119-
Found = true; // Keep going for an implicit kill of the super-reg.
120-
}
121-
}
122-
if (Found)
123-
return;
129+
130+
// Kill flag in MBB
131+
if (MachineInstr *KillMI = RegKills[MBB->getNumber()].get(Reg)) {
132+
KillMI->clearRegisterKills(Reg, TRI);
133+
return;
124134
}
125135

136+
// Def in MBB (missing kill flag)
137+
if (MachineInstr *DefMI = RegDefs[MBB->getNumber()].get(Reg))
138+
if (DefMI->getParent() == MBB)
139+
return;
140+
126141
// If an earlier def is not in MBB, continue in predecessors.
127142
if (!MBB->isLiveIn(Reg))
128143
MBB->addLiveIn(Reg);
129144
assert(!MBB->pred_empty() && "Predecessor def not found!");
130145
for (MachineBasicBlock *Pred : MBB->predecessors())
131146
if (!VisitedPreds.test(Pred->getNumber()))
132-
clearKillsForDef(Reg, Pred, Pred->end(), VisitedPreds, TRI);
147+
clearKillsForDef(Reg, Pred, Pred->end(), VisitedPreds);
133148
}
134149

135-
static void removeRedundantDef(MachineInstr *MI,
136-
const TargetRegisterInfo *TRI) {
150+
void MachineLateInstrsCleanup::removeRedundantDef(MachineInstr *MI) {
137151
Register Reg = MI->getOperand(0).getReg();
138152
BitVector VisitedPreds(MI->getMF()->getNumBlockIDs());
139-
clearKillsForDef(Reg, MI->getParent(), MI->getIterator(), VisitedPreds, TRI);
153+
clearKillsForDef(Reg, MI->getParent(), MI->getIterator(), VisitedPreds);
140154
MI->eraseFromParent();
141155
++NumRemoved;
142156
}
@@ -172,7 +186,8 @@ static bool isCandidate(const MachineInstr *MI, Register &DefedReg,
172186

173187
bool MachineLateInstrsCleanup::processBlock(MachineBasicBlock *MBB) {
174188
bool Changed = false;
175-
Reg2DefMap &MBBDefs = RegDefs[MBB->getNumber()];
189+
Reg2MIMap &MBBDefs = RegDefs[MBB->getNumber()];
190+
Reg2MIMap &MBBKills = RegKills[MBB->getNumber()];
176191

177192
// Find reusable definitions in the predecessor(s).
178193
if (!MBB->pred_empty() && !MBB->isEHPad() &&
@@ -182,9 +197,7 @@ bool MachineLateInstrsCleanup::processBlock(MachineBasicBlock *MBB) {
182197
if (llvm::all_of(
183198
drop_begin(MBB->predecessors()),
184199
[&, &Reg = Reg, &DefMI = DefMI](const MachineBasicBlock *Pred) {
185-
auto PredDefI = RegDefs[Pred->getNumber()].find(Reg);
186-
return PredDefI != RegDefs[Pred->getNumber()].end() &&
187-
DefMI->isIdenticalTo(*PredDefI->second);
200+
return RegDefs[Pred->getNumber()].hasIdentical(Reg, DefMI);
188201
})) {
189202
MBBDefs[Reg] = DefMI;
190203
LLVM_DEBUG(dbgs() << "Reusable instruction from pred(s): in "
@@ -201,38 +214,39 @@ bool MachineLateInstrsCleanup::processBlock(MachineBasicBlock *MBB) {
201214
// it) are valid.
202215
if (MI.modifiesRegister(FrameReg, TRI)) {
203216
MBBDefs.clear();
217+
MBBKills.clear();
204218
continue;
205219
}
206220

207221
Register DefedReg;
208222
bool IsCandidate = isCandidate(&MI, DefedReg, FrameReg);
209223

210224
// Check for an earlier identical and reusable instruction.
211-
if (IsCandidate) {
212-
auto DefI = MBBDefs.find(DefedReg);
213-
if (DefI != MBBDefs.end() && MI.isIdenticalTo(*DefI->second)) {
214-
LLVM_DEBUG(dbgs() << "Removing redundant instruction in "
215-
<< printMBBReference(*MBB) << ": " << MI;);
216-
removeRedundantDef(&MI, TRI);
217-
Changed = true;
218-
continue;
219-
}
225+
if (IsCandidate && MBBDefs.hasIdentical(DefedReg, &MI)) {
226+
LLVM_DEBUG(dbgs() << "Removing redundant instruction in "
227+
<< printMBBReference(*MBB) << ": " << MI;);
228+
removeRedundantDef(&MI);
229+
Changed = true;
230+
continue;
220231
}
221232

222233
// Clear any entries in map that MI clobbers.
223-
for (auto DefI = MBBDefs.begin(); DefI != MBBDefs.end();) {
224-
Register Reg = DefI->first;
225-
if (MI.modifiesRegister(Reg, TRI))
226-
DefI = MBBDefs.erase(DefI);
227-
else
228-
++DefI;
234+
for (auto DefI : llvm::make_early_inc_range(MBBDefs)) {
235+
Register Reg = DefI.first;
236+
if (MI.modifiesRegister(Reg, TRI)) {
237+
MBBDefs.erase(Reg);
238+
MBBKills.erase(Reg);
239+
} else if (MI.findRegisterUseOperandIdx(Reg, false /*isKill*/, TRI) != -1)
240+
// Keep track of the last use seen so far.
241+
MBBKills[Reg] = &MI;
229242
}
230243

231244
// Record this MI for potential later reuse.
232245
if (IsCandidate) {
233246
LLVM_DEBUG(dbgs() << "Found interesting instruction in "
234247
<< printMBBReference(*MBB) << ": " << MI;);
235248
MBBDefs[DefedReg] = &MI;
249+
assert(!MBBKills.count(DefedReg) && "Should already have been removed.");
236250
}
237251
}
238252

0 commit comments

Comments
 (0)