Skip to content

Commit 08e5a1d

Browse files
author
Jeff Niu
authored
[llvm][NVPTX] Fix quadratic runtime in ProxyRegErasure (#105730)
This pass performs RAUW by walking the machine function for each RAUW operation. For large functions, this runtime in this pass starts to blow up. Linearize the pass by batching the RAUW ops at once.
1 parent 25d976b commit 08e5a1d

File tree

1 file changed

+28
-32
lines changed

1 file changed

+28
-32
lines changed

llvm/lib/Target/NVPTX/NVPTXProxyRegErasure.cpp

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ void initializeNVPTXProxyRegErasurePass(PassRegistry &);
3434
namespace {
3535

3636
struct NVPTXProxyRegErasure : public MachineFunctionPass {
37-
public:
3837
static char ID;
3938
NVPTXProxyRegErasure() : MachineFunctionPass(ID) {
4039
initializeNVPTXProxyRegErasurePass(*PassRegistry::getPassRegistry());
@@ -49,23 +48,22 @@ struct NVPTXProxyRegErasure : public MachineFunctionPass {
4948
void getAnalysisUsage(AnalysisUsage &AU) const override {
5049
MachineFunctionPass::getAnalysisUsage(AU);
5150
}
52-
53-
private:
54-
void replaceMachineInstructionUsage(MachineFunction &MF, MachineInstr &MI);
55-
56-
void replaceRegisterUsage(MachineInstr &Instr, MachineOperand &From,
57-
MachineOperand &To);
5851
};
5952

6053
} // namespace
6154

6255
char NVPTXProxyRegErasure::ID = 0;
6356

64-
INITIALIZE_PASS(NVPTXProxyRegErasure, "nvptx-proxyreg-erasure", "NVPTX ProxyReg Erasure", false, false)
57+
INITIALIZE_PASS(NVPTXProxyRegErasure, "nvptx-proxyreg-erasure",
58+
"NVPTX ProxyReg Erasure", false, false)
6559

6660
bool NVPTXProxyRegErasure::runOnMachineFunction(MachineFunction &MF) {
6761
SmallVector<MachineInstr *, 16> RemoveList;
6862

63+
// ProxyReg instructions forward a register as another: `%dst = mov.iN %src`.
64+
// Bulk RAUW the `%dst` registers in two passes over the machine function.
65+
DenseMap<Register, Register> RAUWBatch;
66+
6967
for (auto &BB : MF) {
7068
for (auto &MI : BB) {
7169
switch (MI.getOpcode()) {
@@ -74,44 +72,42 @@ bool NVPTXProxyRegErasure::runOnMachineFunction(MachineFunction &MF) {
7472
case NVPTX::ProxyRegI32:
7573
case NVPTX::ProxyRegI64:
7674
case NVPTX::ProxyRegF32:
77-
case NVPTX::ProxyRegF64:
78-
replaceMachineInstructionUsage(MF, MI);
75+
case NVPTX::ProxyRegF64: {
76+
auto &InOp = *MI.uses().begin();
77+
auto &OutOp = *MI.defs().begin();
78+
assert(InOp.isReg() && "ProxyReg input should be a register.");
79+
assert(OutOp.isReg() && "ProxyReg output should be a register.");
7980
RemoveList.push_back(&MI);
81+
RAUWBatch.try_emplace(OutOp.getReg(), InOp.getReg());
8082
break;
8183
}
84+
}
8285
}
8386
}
8487

88+
// If there were no proxy instructions, exit early.
89+
if (RemoveList.empty())
90+
return false;
91+
92+
// Erase the proxy instructions first.
8593
for (auto *MI : RemoveList) {
8694
MI->eraseFromParent();
8795
}
8896

89-
return !RemoveList.empty();
90-
}
91-
92-
void NVPTXProxyRegErasure::replaceMachineInstructionUsage(MachineFunction &MF,
93-
MachineInstr &MI) {
94-
auto &InOp = *MI.uses().begin();
95-
auto &OutOp = *MI.defs().begin();
96-
97-
assert(InOp.isReg() && "ProxyReg input operand should be a register.");
98-
assert(OutOp.isReg() && "ProxyReg output operand should be a register.");
99-
97+
// Now go replace the registers.
10098
for (auto &BB : MF) {
101-
for (auto &I : BB) {
102-
replaceRegisterUsage(I, OutOp, InOp);
99+
for (auto &MI : BB) {
100+
for (auto &Op : MI.uses()) {
101+
if (!Op.isReg())
102+
continue;
103+
auto it = RAUWBatch.find(Op.getReg());
104+
if (it != RAUWBatch.end())
105+
Op.setReg(it->second);
106+
}
103107
}
104108
}
105-
}
106109

107-
void NVPTXProxyRegErasure::replaceRegisterUsage(MachineInstr &Instr,
108-
MachineOperand &From,
109-
MachineOperand &To) {
110-
for (auto &Op : Instr.uses()) {
111-
if (Op.isReg() && Op.getReg() == From.getReg()) {
112-
Op.setReg(To.getReg());
113-
}
114-
}
110+
return true;
115111
}
116112

117113
MachineFunctionPass *llvm::createNVPTXProxyRegErasurePass() {

0 commit comments

Comments
 (0)