Skip to content

Commit 33c3862

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 `hasVectorInstruction` 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 0ed8194 commit 33c3862

27 files changed

+150
-107
lines changed

llvm/include/llvm/CodeGen/CodeGenPassBuilder.h

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

1182+
addPass(InitUndefPass())
1183+
;
11821184
addPass(ProcessImplicitDefsPass());
11831185

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

llvm/include/llvm/CodeGen/MachinePassRegistry.def

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

llvm/include/llvm/CodeGen/Passes.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ 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 Vector Instructions to ensure early-clobber is followed when using the greedy register allocator.
200+
extern char &InitUndefID;
201+
199202
/// FastRegisterAllocation Pass - This pass register allocates as fast as
200203
/// possible. It is best suited for debug code where live ranges are short.
201204
///
@@ -600,6 +603,9 @@ namespace llvm {
600603

601604
/// Lowers KCFI operand bundles for indirect calls.
602605
FunctionPass *createKCFIPass();
606+
607+
// Assigns a Pseudo Instruction to undef values in vector instructions to ensure that early-clobber is followed.
608+
FunctionPass *createInitUndefPass();
603609
} // End llvm namespace
604610

605611
#endif

llvm/include/llvm/CodeGen/TargetInstrInfo.h

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

2226+
virtual unsigned getUndefInitOpcode(unsigned RegClassID) const {
2227+
(void)RegClassID;
2228+
2229+
llvm_unreachable("Unexpected register class.");
2230+
}
2231+
2232+
virtual const TargetRegisterClass *
2233+
getVRLargestSuperClass(const TargetRegisterClass *RC) const {
2234+
llvm_unreachable("Unexpected target register class.");
2235+
}
2236+
2237+
virtual bool isVectorRegClass(const TargetRegisterClass *RC) const {
2238+
llvm_unreachable("Unexpected Register or MachineRegisterInfo");
2239+
}
2240+
2241+
virtual unsigned getNoRegisterValue() const {
2242+
llvm_unreachable("Unexpected target register class.");
2243+
}
2244+
22262245
private:
22272246
mutable std::unique_ptr<MIRFormatter> Formatter;
22282247
unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode;

llvm/include/llvm/CodeGen/TargetSubtargetInfo.h

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

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

332341
} // 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/lib/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ add_llvm_component_library(LLVMCodeGen
8888
IfConversion.cpp
8989
ImplicitNullChecks.cpp
9090
IndirectBrExpandPass.cpp
91+
InitUndef.cpp
9192
InlineSpiller.cpp
9293
InterferenceCache.cpp
9394
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: 56 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===- RISCVRVVInitUndef.cpp - Initialize undef vector value to pseudo ----===//
1+
//===- InitUndef.cpp - Initialize undef vector 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.
@@ -7,22 +7,21 @@
77
//===----------------------------------------------------------------------===//
88
//
99
// 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.
10+
// temporary pseudo instruction to prevent register allocation resulting in a
11+
// constraint violated result for vector instructions. It also rewrites the
12+
// 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 vector 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
@@ -39,23 +38,29 @@
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/Pass.h"
52+
4853
using namespace llvm;
4954

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

5358
namespace {
5459

55-
class RISCVInitUndef : public MachineFunctionPass {
60+
class InitUndef : public MachineFunctionPass {
5661
const TargetInstrInfo *TII;
5762
MachineRegisterInfo *MRI;
58-
const RISCVSubtarget *ST;
63+
const TargetSubtargetInfo *ST;
5964
const TargetRegisterInfo *TRI;
6065

6166
// Newly added vregs, assumed to be fully rewritten
@@ -65,22 +70,19 @@ class RISCVInitUndef : public MachineFunctionPass {
6570
public:
6671
static char ID;
6772

68-
RISCVInitUndef() : MachineFunctionPass(ID) {}
73+
InitUndef() : MachineFunctionPass(ID) {}
6974
bool runOnMachineFunction(MachineFunction &MF) override;
7075

7176
void getAnalysisUsage(AnalysisUsage &AU) const override {
7277
AU.setPreservesCFG();
7378
MachineFunctionPass::getAnalysisUsage(AU);
7479
}
7580

76-
StringRef getPassName() const override { return RISCV_INIT_UNDEF_NAME; }
81+
StringRef getPassName() const override { return INIT_UNDEF_NAME; }
7782

7883
private:
7984
bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB,
8085
const DeadLaneDetector &DLD);
81-
bool isVectorRegClass(const Register R);
82-
const TargetRegisterClass *
83-
getVRLargestSuperClass(const TargetRegisterClass *RC) const;
8486
bool handleSubReg(MachineFunction &MF, MachineInstr &MI,
8587
const DeadLaneDetector &DLD);
8688
bool fixupIllOperand(MachineInstr *MI, MachineOperand &MO);
@@ -89,45 +91,9 @@ class RISCVInitUndef : public MachineFunctionPass {
8991

9092
} // end anonymous namespace
9193

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-
}
94+
char InitUndef::ID = 0;
95+
INITIALIZE_PASS(InitUndef, DEBUG_TYPE, INIT_UNDEF_NAME, false, false)
96+
char &llvm::InitUndefID = InitUndef::ID;
13197

13298
static bool isEarlyClobberMI(MachineInstr &MI) {
13399
return llvm::any_of(MI.defs(), [](const MachineOperand &DefMO) {
@@ -143,7 +109,7 @@ static bool findImplictDefMIFromReg(Register Reg, MachineRegisterInfo *MRI) {
143109
return false;
144110
}
145111

146-
bool RISCVInitUndef::handleReg(MachineInstr *MI) {
112+
bool InitUndef::handleReg(MachineInstr *MI) {
147113
bool Changed = false;
148114
for (auto &UseMO : MI->uses()) {
149115
if (!UseMO.isReg())
@@ -152,7 +118,7 @@ bool RISCVInitUndef::handleReg(MachineInstr *MI) {
152118
continue;
153119
if (!UseMO.getReg().isVirtual())
154120
continue;
155-
if (!isVectorRegClass(UseMO.getReg()))
121+
if (!TII->isVectorRegClass(MRI->getRegClass(UseMO.getReg())))
156122
continue;
157123

158124
if (UseMO.isUndef() || findImplictDefMIFromReg(UseMO.getReg(), MRI))
@@ -161,8 +127,8 @@ bool RISCVInitUndef::handleReg(MachineInstr *MI) {
161127
return Changed;
162128
}
163129

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

168134
for (MachineOperand &UseMO : MI.uses()) {
@@ -183,7 +149,7 @@ bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
183149
continue;
184150

185151
const TargetRegisterClass *TargetRegClass =
186-
getVRLargestSuperClass(MRI->getRegClass(Reg));
152+
TII->getVRLargestSuperClass(MRI->getRegClass(Reg));
187153

188154
LaneBitmask NeedDef = Info.UsedLanes & ~Info.DefinedLanes;
189155

@@ -202,11 +168,11 @@ bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
202168
Register LatestReg = Reg;
203169
for (auto ind : SubRegIndexNeedInsert) {
204170
Changed = true;
205-
const TargetRegisterClass *SubRegClass =
206-
getVRLargestSuperClass(TRI->getSubRegisterClass(TargetRegClass, ind));
171+
const TargetRegisterClass *SubRegClass = TII->getVRLargestSuperClass(
172+
TRI->getSubRegisterClass(TargetRegClass, ind));
207173
Register TmpInitSubReg = MRI->createVirtualRegister(SubRegClass);
208174
BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
209-
TII->get(getUndefInitOpcode(SubRegClass->getID())),
175+
TII->get(TII->getUndefInitOpcode(SubRegClass->getID())),
210176
TmpInitSubReg);
211177
Register NewReg = MRI->createVirtualRegister(TargetRegClass);
212178
BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
@@ -223,15 +189,16 @@ bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
223189
return Changed;
224190
}
225191

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

228194
LLVM_DEBUG(
229-
dbgs() << "Emitting PseudoRVVInitUndef for implicit vector register "
230-
<< MO.getReg() << '\n');
195+
dbgs()
196+
<< "Emitting PseudoInitUndef Instruction for implicit vector register "
197+
<< MO.getReg() << '\n');
231198

232199
const TargetRegisterClass *TargetRegClass =
233-
getVRLargestSuperClass(MRI->getRegClass(MO.getReg()));
234-
unsigned Opcode = getUndefInitOpcode(TargetRegClass->getID());
200+
TII->getVRLargestSuperClass(MRI->getRegClass(MO.getReg()));
201+
unsigned Opcode = TII->getUndefInitOpcode(TargetRegClass->getID());
235202
Register NewReg = MRI->createVirtualRegister(TargetRegClass);
236203
BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(Opcode), NewReg);
237204
MO.setReg(NewReg);
@@ -240,9 +207,8 @@ bool RISCVInitUndef::fixupIllOperand(MachineInstr *MI, MachineOperand &MO) {
240207
return true;
241208
}
242209

243-
bool RISCVInitUndef::processBasicBlock(MachineFunction &MF,
244-
MachineBasicBlock &MBB,
245-
const DeadLaneDetector &DLD) {
210+
bool InitUndef::processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB,
211+
const DeadLaneDetector &DLD) {
246212
bool Changed = false;
247213
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
248214
MachineInstr &MI = *I;
@@ -252,15 +218,15 @@ bool RISCVInitUndef::processBasicBlock(MachineFunction &MF,
252218
unsigned UseOpIdx;
253219
if (MI.getNumDefs() != 0 && MI.isRegTiedToUseOperand(0, &UseOpIdx)) {
254220
MachineOperand &UseMO = MI.getOperand(UseOpIdx);
255-
if (UseMO.getReg() == RISCV::NoRegister) {
221+
if (UseMO.getReg() == TII->getNoRegisterValue()) {
256222
const TargetRegisterClass *RC =
257-
TII->getRegClass(MI.getDesc(), UseOpIdx, TRI, MF);
223+
TII->getRegClass(MI.getDesc(), UseOpIdx, TRI, MF);
258224
Register NewDest = MRI->createVirtualRegister(RC);
259225
// We don't have a way to update dead lanes, so keep track of the
260226
// new register so that we avoid querying it later.
261227
NewRegs.insert(NewDest);
262-
BuildMI(MBB, I, I->getDebugLoc(),
263-
TII->get(TargetOpcode::IMPLICIT_DEF), NewDest);
228+
BuildMI(MBB, I, I->getDebugLoc(), TII->get(TargetOpcode::IMPLICIT_DEF),
229+
NewDest);
264230
UseMO.setReg(NewDest);
265231
Changed = true;
266232
}
@@ -275,8 +241,14 @@ bool RISCVInitUndef::processBasicBlock(MachineFunction &MF,
275241
return Changed;
276242
}
277243

278-
bool RISCVInitUndef::runOnMachineFunction(MachineFunction &MF) {
279-
ST = &MF.getSubtarget<RISCVSubtarget>();
244+
bool InitUndef::runOnMachineFunction(MachineFunction &MF) {
245+
ST = &MF.getSubtarget();
246+
247+
// This checks to ensure that the Subtarget being used has support for Vector
248+
// Instructions. The pass will exit if this is not the case, and provides
249+
// protection against unnecessary changing register definitions where this is
250+
// not needed. By default hasVInstructions will return false, only in the
251+
// Architecture specific subtarget override function can this return true.
280252
if (!ST->hasVInstructions())
281253
return false;
282254

@@ -297,5 +269,3 @@ bool RISCVInitUndef::runOnMachineFunction(MachineFunction &MF) {
297269

298270
return Changed;
299271
}
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
@@ -1424,6 +1424,8 @@ void TargetPassConfig::addFastRegAlloc() {
14241424
void TargetPassConfig::addOptimizedRegAlloc() {
14251425
addPass(&DetectDeadLanesID);
14261426

1427+
addPass(&InitUndefID);
1428+
14271429
addPass(&ProcessImplicitDefsID);
14281430

14291431
// LiveVariables currently requires pure SSA form.

llvm/lib/Target/RISCV/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ add_llvm_target(RISCVCodeGen
5151
RISCVMoveMerger.cpp
5252
RISCVPushPopOptimizer.cpp
5353
RISCVRegisterInfo.cpp
54-
RISCVRVVInitUndef.cpp
5554
RISCVSubtarget.cpp
5655
RISCVTargetMachine.cpp
5756
RISCVTargetObjectFile.cpp

0 commit comments

Comments
 (0)