Skip to content

Commit a71030b

Browse files
committed
[CodeGen] Convert RISCV Init Undef pass to support any architecture
Currently this pass is designed for RISC-V only, however this is not the only architecture with the bug reported in issue #50157. We can convert the exisiting pass to be generic, using some of the existing Parent classes rather than RISC-V specific classes to bring the same functionality to other Architectures. The pass has been refactored, removing the RISC-V specific functions and data-types and replacing them with datatypes that will support all architectures and virtual functions in the respecitive classes that allow support for the pass to be added. By default, this pass will not run on on all architectures, only those that have the `supportsInitUndef` function impletmented. This commit will only refactor the exisiting code and add the pass in as a CodeGen pass rather than target specific. To add support for other architectures, this should be done in new, following commits. This will allow for the pass to be used by any architecture. With the correct overriding functions, other architectures can be supported to provide the same functionality as was added to fix issue that was reported in Issue #50157. This is still a temporary measure, and a better more permenant fix should be found, but for the time being this will allow for the correct early-clobber contraint to be followed when defined in vector instructions.
1 parent 275729a commit a71030b

29 files changed

+142
-109
lines changed

llvm/include/llvm/CodeGen/Passes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ namespace llvm {
196196
/// This pass reads flow sensitive profile.
197197
extern char &MIRProfileLoaderPassID;
198198

199+
// This pass gives undef values a Pseudo Instruction definition for
200+
// Instructions to ensure early-clobber is followed when using the greedy
201+
// register allocator.
202+
extern char &InitUndefID;
203+
199204
/// FastRegisterAllocation Pass - This pass register allocates as fast as
200205
/// possible. It is best suited for debug code where live ranges are short.
201206
///

llvm/include/llvm/CodeGen/TargetInstrInfo.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,6 +2223,15 @@ class TargetInstrInfo : public MCInstrInfo {
22232223
llvm_unreachable("unknown number of operands necessary");
22242224
}
22252225

2226+
/// Gets the opcode for the Pseudo Instruction used to initialize
2227+
/// the undef value. If no Instruction is available, this will
2228+
/// fail compilation.
2229+
virtual unsigned getUndefInitOpcode(unsigned RegClassID) const {
2230+
(void)RegClassID;
2231+
2232+
llvm_unreachable("Unexpected register class.");
2233+
}
2234+
22262235
private:
22272236
mutable std::unique_ptr<MIRFormatter> Formatter;
22282237
unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode;

llvm/include/llvm/CodeGen/TargetRegisterInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,14 @@ class TargetRegisterInfo : public MCRegisterInfo {
11731173
virtual bool isNonallocatableRegisterCalleeSave(MCRegister Reg) const {
11741174
return false;
11751175
}
1176+
1177+
/// Returns the Register Class that is being initialized. There
1178+
/// should be a Pseudo Instruction for the different register
1179+
/// classes for the different register types that are introduced.
1180+
virtual const TargetRegisterClass *
1181+
getTargetRegisterClass(const TargetRegisterClass *RC) const {
1182+
llvm_unreachable("Unexpected target register class.");
1183+
}
11761184
};
11771185

11781186
//===----------------------------------------------------------------------===//

llvm/include/llvm/CodeGen/TargetSubtargetInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,14 @@ class TargetSubtargetInfo : public MCSubtargetInfo {
327327

328328
/// Get the list of MacroFusion predicates.
329329
virtual std::vector<MacroFusionPredTy> getMacroFusions() const { return {}; };
330+
331+
// supportsInitUndef is used to determine if an architecture supports
332+
// the Init Undef Pass. By default, it is assumed that it will not support the
333+
// pass, with architecture specific overrides providing the information where
334+
// they are implemented. This was originally used in RISC-V's Init Undef pass
335+
// but has been moved to be a virtual function when the pass was refactored to
336+
// support multiple architectures.
337+
virtual bool supportsInitUndef() const { return false; }
330338
};
331339

332340
} // end namespace llvm

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ void initializeTLSVariableHoistLegacyPassPass(PassRegistry &);
301301
void initializeTwoAddressInstructionPassPass(PassRegistry&);
302302
void initializeTypeBasedAAWrapperPassPass(PassRegistry&);
303303
void initializeTypePromotionLegacyPass(PassRegistry&);
304+
void initializeInitUndefPass(PassRegistry &);
304305
void initializeUniformityInfoWrapperPassPass(PassRegistry &);
305306
void initializeUnifyLoopExitsLegacyPassPass(PassRegistry &);
306307
void initializeUnpackMachineBundlesPass(PassRegistry&);

llvm/include/llvm/Passes/CodeGenPassBuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,8 @@ void CodeGenPassBuilder<Derived>::addOptimizedRegAlloc(
11551155
AddMachinePass &addPass) const {
11561156
addPass(DetectDeadLanesPass());
11571157

1158+
addPass(InitUndefPass());
1159+
11581160
addPass(ProcessImplicitDefsPass());
11591161

11601162
// Edge splitting is smarter with machine loop info.

llvm/include/llvm/Passes/MachinePassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ DUMMY_MACHINE_FUNCTION_PASS("fs-profile-loader", MIRProfileLoaderNewPass,
181181
DUMMY_MACHINE_FUNCTION_PASS("funclet-layout", FuncletLayoutPass, ())
182182
DUMMY_MACHINE_FUNCTION_PASS("gc-empty-basic-blocks", GCEmptyBasicBlocksPass, ())
183183
DUMMY_MACHINE_FUNCTION_PASS("implicit-null-checks", ImplicitNullChecksPass, ())
184+
DUMMY_MACHINE_FUNCTION_PASS("init-undef", InitUndefPass, ())
184185
DUMMY_MACHINE_FUNCTION_PASS("instruction-select", InstructionSelectPass, ())
185186
DUMMY_MACHINE_FUNCTION_PASS("irtranslator", IRTranslatorPass, ())
186187
DUMMY_MACHINE_FUNCTION_PASS("kcfi", MachineKCFIPass, ())

llvm/lib/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ add_llvm_component_library(LLVMCodeGen
7575
IfConversion.cpp
7676
ImplicitNullChecks.cpp
7777
IndirectBrExpandPass.cpp
78+
InitUndef.cpp
7879
InlineSpiller.cpp
7980
InterferenceCache.cpp
8081
InterleavedAccessPass.cpp

llvm/lib/CodeGen/CodeGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
5454
initializeIfConverterPass(Registry);
5555
initializeImplicitNullChecksPass(Registry);
5656
initializeIndirectBrExpandLegacyPassPass(Registry);
57+
initializeInitUndefPass(Registry);
5758
initializeInterleavedLoadCombinePass(Registry);
5859
initializeInterleavedAccessPass(Registry);
5960
initializeJMCInstrumenterPass(Registry);
Lines changed: 58 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
1-
//===- RISCVRVVInitUndef.cpp - Initialize undef vector value to pseudo ----===//
1+
//===- InitUndef.cpp - Initialize undef value to pseudo ----===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
88
//
9-
// This file implements a function pass that initializes undef vector value to
10-
// temporary pseudo instruction and remove it in expandpseudo pass to prevent
11-
// register allocation resulting in a constraint violated result for vector
12-
// instruction. It also rewrites the NoReg tied operand back to an
13-
// IMPLICIT_DEF.
9+
// This file implements a function pass that initializes undef value to
10+
// temporary pseudo instruction to prevent register allocation resulting in a
11+
// constraint violated result for the particular instruction. It also rewrites
12+
// the NoReg tied operand back to an IMPLICIT_DEF.
1413
//
15-
// RISC-V vector instruction has register overlapping constraint for certain
16-
// instructions, and will cause illegal instruction trap if violated, we use
17-
// early clobber to model this constraint, but it can't prevent register
18-
// allocator allocated same or overlapped if the input register is undef value,
19-
// so convert IMPLICIT_DEF to temporary pseudo instruction and remove it later
20-
// could prevent that happen, it's not best way to resolve this, and it might
14+
// Certain instructions have register overlapping constraints, and
15+
// will cause illegal instruction trap if violated, we use early clobber to
16+
// model this constraint, but it can't prevent register allocator allocating
17+
// same or overlapped if the input register is undef value, so convert
18+
// IMPLICIT_DEF to temporary pseudo instruction and remove it later could
19+
// prevent that happen, it's not best way to resolve this, and it might
2120
// change the order of program or increase the register pressure, so ideally we
2221
// should model the constraint right, but before we model the constraint right,
2322
// it's the only way to prevent that happen.
2423
//
25-
// When we enable the subregister liveness option, it will also trigger same
24+
// When we enable the subregister liveness option, it will also trigger the same
2625
// issue due to the partial of register is undef. If we pseudoinit the whole
2726
// register, then it will generate redundant COPY instruction. Currently, it
2827
// will generate INSERT_SUBREG to make sure the whole register is occupied
@@ -31,31 +30,38 @@
3130
//
3231
// See also: https://github.com/llvm/llvm-project/issues/50157
3332
//
34-
// Additionally, this pass rewrites tied operands of vector instructions
33+
// Additionally, this pass rewrites tied operands of instructions
3534
// from NoReg to IMPLICIT_DEF. (Not that this is a non-overlapping set of
3635
// operands to the above.) We use NoReg to side step a MachineCSE
3736
// optimization quality problem but need to convert back before
3837
// TwoAddressInstruction. See pr64282 for context.
3938
//
4039
//===----------------------------------------------------------------------===//
4140

42-
#include "RISCV.h"
43-
#include "RISCVSubtarget.h"
4441
#include "llvm/ADT/SmallSet.h"
4542
#include "llvm/ADT/SmallVector.h"
4643
#include "llvm/CodeGen/DetectDeadLanes.h"
44+
#include "llvm/CodeGen/MachineFunction.h"
4745
#include "llvm/CodeGen/MachineFunctionPass.h"
46+
#include "llvm/CodeGen/MachineRegisterInfo.h"
47+
#include "llvm/CodeGen/TargetInstrInfo.h"
48+
#include "llvm/CodeGen/TargetRegisterInfo.h"
49+
#include "llvm/CodeGen/TargetSubtargetInfo.h"
50+
#include "llvm/InitializePasses.h"
51+
#include "llvm/MC/MCRegister.h"
52+
#include "llvm/Pass.h"
53+
4854
using namespace llvm;
4955

50-
#define DEBUG_TYPE "riscv-init-undef"
51-
#define RISCV_INIT_UNDEF_NAME "RISC-V init undef pass"
56+
#define DEBUG_TYPE "init-undef"
57+
#define INIT_UNDEF_NAME "Init Undef Pass"
5258

5359
namespace {
5460

55-
class RISCVInitUndef : public MachineFunctionPass {
61+
class InitUndef : public MachineFunctionPass {
5662
const TargetInstrInfo *TII;
5763
MachineRegisterInfo *MRI;
58-
const RISCVSubtarget *ST;
64+
const TargetSubtargetInfo *ST;
5965
const TargetRegisterInfo *TRI;
6066

6167
// Newly added vregs, assumed to be fully rewritten
@@ -65,22 +71,19 @@ class RISCVInitUndef : public MachineFunctionPass {
6571
public:
6672
static char ID;
6773

68-
RISCVInitUndef() : MachineFunctionPass(ID) {}
74+
InitUndef() : MachineFunctionPass(ID) {}
6975
bool runOnMachineFunction(MachineFunction &MF) override;
7076

7177
void getAnalysisUsage(AnalysisUsage &AU) const override {
7278
AU.setPreservesCFG();
7379
MachineFunctionPass::getAnalysisUsage(AU);
7480
}
7581

76-
StringRef getPassName() const override { return RISCV_INIT_UNDEF_NAME; }
82+
StringRef getPassName() const override { return INIT_UNDEF_NAME; }
7783

7884
private:
7985
bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB,
8086
const DeadLaneDetector &DLD);
81-
bool isVectorRegClass(const Register R);
82-
const TargetRegisterClass *
83-
getVRLargestSuperClass(const TargetRegisterClass *RC) const;
8487
bool handleSubReg(MachineFunction &MF, MachineInstr &MI,
8588
const DeadLaneDetector &DLD);
8689
bool fixupIllOperand(MachineInstr *MI, MachineOperand &MO);
@@ -89,45 +92,9 @@ class RISCVInitUndef : public MachineFunctionPass {
8992

9093
} // end anonymous namespace
9194

92-
char RISCVInitUndef::ID = 0;
93-
INITIALIZE_PASS(RISCVInitUndef, DEBUG_TYPE, RISCV_INIT_UNDEF_NAME, false, false)
94-
char &llvm::RISCVInitUndefID = RISCVInitUndef::ID;
95-
96-
const TargetRegisterClass *
97-
RISCVInitUndef::getVRLargestSuperClass(const TargetRegisterClass *RC) const {
98-
if (RISCV::VRM8RegClass.hasSubClassEq(RC))
99-
return &RISCV::VRM8RegClass;
100-
if (RISCV::VRM4RegClass.hasSubClassEq(RC))
101-
return &RISCV::VRM4RegClass;
102-
if (RISCV::VRM2RegClass.hasSubClassEq(RC))
103-
return &RISCV::VRM2RegClass;
104-
if (RISCV::VRRegClass.hasSubClassEq(RC))
105-
return &RISCV::VRRegClass;
106-
return RC;
107-
}
108-
109-
bool RISCVInitUndef::isVectorRegClass(const Register R) {
110-
const TargetRegisterClass *RC = MRI->getRegClass(R);
111-
return RISCV::VRRegClass.hasSubClassEq(RC) ||
112-
RISCV::VRM2RegClass.hasSubClassEq(RC) ||
113-
RISCV::VRM4RegClass.hasSubClassEq(RC) ||
114-
RISCV::VRM8RegClass.hasSubClassEq(RC);
115-
}
116-
117-
static unsigned getUndefInitOpcode(unsigned RegClassID) {
118-
switch (RegClassID) {
119-
case RISCV::VRRegClassID:
120-
return RISCV::PseudoRVVInitUndefM1;
121-
case RISCV::VRM2RegClassID:
122-
return RISCV::PseudoRVVInitUndefM2;
123-
case RISCV::VRM4RegClassID:
124-
return RISCV::PseudoRVVInitUndefM4;
125-
case RISCV::VRM8RegClassID:
126-
return RISCV::PseudoRVVInitUndefM8;
127-
default:
128-
llvm_unreachable("Unexpected register class.");
129-
}
130-
}
95+
char InitUndef::ID = 0;
96+
INITIALIZE_PASS(InitUndef, DEBUG_TYPE, INIT_UNDEF_NAME, false, false)
97+
char &llvm::InitUndefID = InitUndef::ID;
13198

13299
static bool isEarlyClobberMI(MachineInstr &MI) {
133100
return llvm::any_of(MI.defs(), [](const MachineOperand &DefMO) {
@@ -143,7 +110,7 @@ static bool findImplictDefMIFromReg(Register Reg, MachineRegisterInfo *MRI) {
143110
return false;
144111
}
145112

146-
bool RISCVInitUndef::handleReg(MachineInstr *MI) {
113+
bool InitUndef::handleReg(MachineInstr *MI) {
147114
bool Changed = false;
148115
for (auto &UseMO : MI->uses()) {
149116
if (!UseMO.isReg())
@@ -152,17 +119,15 @@ bool RISCVInitUndef::handleReg(MachineInstr *MI) {
152119
continue;
153120
if (!UseMO.getReg().isVirtual())
154121
continue;
155-
if (!isVectorRegClass(UseMO.getReg()))
156-
continue;
157122

158123
if (UseMO.isUndef() || findImplictDefMIFromReg(UseMO.getReg(), MRI))
159124
Changed |= fixupIllOperand(MI, UseMO);
160125
}
161126
return Changed;
162127
}
163128

164-
bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
165-
const DeadLaneDetector &DLD) {
129+
bool InitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
130+
const DeadLaneDetector &DLD) {
166131
bool Changed = false;
167132

168133
for (MachineOperand &UseMO : MI.uses()) {
@@ -183,7 +148,7 @@ bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
183148
continue;
184149

185150
const TargetRegisterClass *TargetRegClass =
186-
getVRLargestSuperClass(MRI->getRegClass(Reg));
151+
TRI->getTargetRegisterClass(MRI->getRegClass(Reg));
187152

188153
LaneBitmask NeedDef = Info.UsedLanes & ~Info.DefinedLanes;
189154

@@ -202,11 +167,11 @@ bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
202167
Register LatestReg = Reg;
203168
for (auto ind : SubRegIndexNeedInsert) {
204169
Changed = true;
205-
const TargetRegisterClass *SubRegClass =
206-
getVRLargestSuperClass(TRI->getSubRegisterClass(TargetRegClass, ind));
170+
const TargetRegisterClass *SubRegClass = TRI->getTargetRegisterClass(
171+
TRI->getSubRegisterClass(TargetRegClass, ind));
207172
Register TmpInitSubReg = MRI->createVirtualRegister(SubRegClass);
208173
BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
209-
TII->get(getUndefInitOpcode(SubRegClass->getID())),
174+
TII->get(TII->getUndefInitOpcode(SubRegClass->getID())),
210175
TmpInitSubReg);
211176
Register NewReg = MRI->createVirtualRegister(TargetRegClass);
212177
BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
@@ -223,15 +188,15 @@ bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
223188
return Changed;
224189
}
225190

226-
bool RISCVInitUndef::fixupIllOperand(MachineInstr *MI, MachineOperand &MO) {
191+
bool InitUndef::fixupIllOperand(MachineInstr *MI, MachineOperand &MO) {
227192

228193
LLVM_DEBUG(
229-
dbgs() << "Emitting PseudoRVVInitUndef for implicit vector register "
194+
dbgs() << "Emitting PseudoInitUndef Instruction for implicit register "
230195
<< MO.getReg() << '\n');
231196

232197
const TargetRegisterClass *TargetRegClass =
233-
getVRLargestSuperClass(MRI->getRegClass(MO.getReg()));
234-
unsigned Opcode = getUndefInitOpcode(TargetRegClass->getID());
198+
TRI->getTargetRegisterClass(MRI->getRegClass(MO.getReg()));
199+
unsigned Opcode = TII->getUndefInitOpcode(TargetRegClass->getID());
235200
Register NewReg = MRI->createVirtualRegister(TargetRegClass);
236201
BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(Opcode), NewReg);
237202
MO.setReg(NewReg);
@@ -240,9 +205,8 @@ bool RISCVInitUndef::fixupIllOperand(MachineInstr *MI, MachineOperand &MO) {
240205
return true;
241206
}
242207

243-
bool RISCVInitUndef::processBasicBlock(MachineFunction &MF,
244-
MachineBasicBlock &MBB,
245-
const DeadLaneDetector &DLD) {
208+
bool InitUndef::processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB,
209+
const DeadLaneDetector &DLD) {
246210
bool Changed = false;
247211
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
248212
MachineInstr &MI = *I;
@@ -252,15 +216,15 @@ bool RISCVInitUndef::processBasicBlock(MachineFunction &MF,
252216
unsigned UseOpIdx;
253217
if (MI.getNumDefs() != 0 && MI.isRegTiedToUseOperand(0, &UseOpIdx)) {
254218
MachineOperand &UseMO = MI.getOperand(UseOpIdx);
255-
if (UseMO.getReg() == RISCV::NoRegister) {
219+
if (UseMO.getReg() == MCRegister::NoRegister) {
256220
const TargetRegisterClass *RC =
257-
TII->getRegClass(MI.getDesc(), UseOpIdx, TRI, MF);
221+
TII->getRegClass(MI.getDesc(), UseOpIdx, TRI, MF);
258222
Register NewDest = MRI->createVirtualRegister(RC);
259223
// We don't have a way to update dead lanes, so keep track of the
260224
// new register so that we avoid querying it later.
261225
NewRegs.insert(NewDest);
262-
BuildMI(MBB, I, I->getDebugLoc(),
263-
TII->get(TargetOpcode::IMPLICIT_DEF), NewDest);
226+
BuildMI(MBB, I, I->getDebugLoc(), TII->get(TargetOpcode::IMPLICIT_DEF),
227+
NewDest);
264228
UseMO.setReg(NewDest);
265229
Changed = true;
266230
}
@@ -275,9 +239,16 @@ bool RISCVInitUndef::processBasicBlock(MachineFunction &MF,
275239
return Changed;
276240
}
277241

278-
bool RISCVInitUndef::runOnMachineFunction(MachineFunction &MF) {
279-
ST = &MF.getSubtarget<RISCVSubtarget>();
280-
if (!ST->hasVInstructions())
242+
bool InitUndef::runOnMachineFunction(MachineFunction &MF) {
243+
ST = &MF.getSubtarget();
244+
245+
// supportsInitUndef is implemented to reflect if an architecture has support
246+
// for the InitUndef pass. Support comes from having the relevant Pseudo
247+
// instructions that can be used to initialize the register. The function
248+
// returns false by default so requires an implementation per architecture.
249+
// Support can be added by overriding the function in a way that best fits
250+
// the architecture.
251+
if (!ST->supportsInitUndef())
281252
return false;
282253

283254
MRI = &MF.getRegInfo();
@@ -297,5 +268,3 @@ bool RISCVInitUndef::runOnMachineFunction(MachineFunction &MF) {
297268

298269
return Changed;
299270
}
300-
301-
FunctionPass *llvm::createRISCVInitUndefPass() { return new RISCVInitUndef(); }

llvm/lib/CodeGen/TargetPassConfig.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,6 +1427,8 @@ void TargetPassConfig::addFastRegAlloc() {
14271427
void TargetPassConfig::addOptimizedRegAlloc() {
14281428
addPass(&DetectDeadLanesID);
14291429

1430+
addPass(&InitUndefID);
1431+
14301432
addPass(&ProcessImplicitDefsID);
14311433

14321434
// LiveVariables currently requires pure SSA form.

0 commit comments

Comments
 (0)