LLVM 18.0.0git
RISCVRVVInitUndef.cpp
Go to the documentation of this file.
1//===- RISCVRVVInitUndef.cpp - Initialize undef vector value to pseudo ----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
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.
14//
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
21// change the order of program or increase the register pressure, so ideally we
22// should model the constraint right, but before we model the constraint right,
23// it's the only way to prevent that happen.
24//
25// When we enable the subregister liveness option, it will also trigger same
26// issue due to the partial of register is undef. If we pseudoinit the whole
27// register, then it will generate redundant COPY instruction. Currently, it
28// will generate INSERT_SUBREG to make sure the whole register is occupied
29// when program encounter operation that has early-clobber constraint.
30//
31//
32// See also: https://github.com/llvm/llvm-project/issues/50157
33//
34// Additionally, this pass rewrites tied operands of vector instructions
35// from NoReg to IMPLICIT_DEF. (Not that this is a non-overlapping set of
36// operands to the above.) We use NoReg to side step a MachineCSE
37// optimization quality problem but need to convert back before
38// TwoAddressInstruction. See pr64282 for context.
39//
40//===----------------------------------------------------------------------===//
41
42#include "RISCV.h"
43#include "RISCVSubtarget.h"
44#include "llvm/ADT/SmallSet.h"
47using namespace llvm;
48
49#define DEBUG_TYPE "riscv-init-undef"
50#define RISCV_INIT_UNDEF_NAME "RISC-V init undef pass"
51
52namespace {
53
54class RISCVInitUndef : public MachineFunctionPass {
55 const TargetInstrInfo *TII;
57 const RISCVSubtarget *ST;
59
60 // Newly added vregs, assumed to be fully rewritten
62public:
63 static char ID;
64
65 RISCVInitUndef() : MachineFunctionPass(ID) {
67 }
68 bool runOnMachineFunction(MachineFunction &MF) override;
69
70 void getAnalysisUsage(AnalysisUsage &AU) const override {
71 AU.setPreservesCFG();
73 }
74
75 StringRef getPassName() const override { return RISCV_INIT_UNDEF_NAME; }
76
77private:
78 bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB,
79 const DeadLaneDetector &DLD);
80 bool handleImplicitDef(MachineBasicBlock &MBB,
82 bool isVectorRegClass(const Register R);
84 getVRLargestSuperClass(const TargetRegisterClass *RC) const;
85 bool handleSubReg(MachineFunction &MF, MachineInstr &MI,
86 const DeadLaneDetector &DLD);
87};
88
89} // end anonymous namespace
90
91char RISCVInitUndef::ID = 0;
92INITIALIZE_PASS(RISCVInitUndef, DEBUG_TYPE, RISCV_INIT_UNDEF_NAME, false, false)
93char &llvm::RISCVInitUndefID = RISCVInitUndef::ID;
94
96RISCVInitUndef::getVRLargestSuperClass(const TargetRegisterClass *RC) const {
97 if (RISCV::VRM8RegClass.hasSubClassEq(RC))
98 return &RISCV::VRM8RegClass;
99 if (RISCV::VRM4RegClass.hasSubClassEq(RC))
100 return &RISCV::VRM4RegClass;
101 if (RISCV::VRM2RegClass.hasSubClassEq(RC))
102 return &RISCV::VRM2RegClass;
103 if (RISCV::VRRegClass.hasSubClassEq(RC))
104 return &RISCV::VRRegClass;
105 return RC;
106}
107
108bool RISCVInitUndef::isVectorRegClass(const Register R) {
109 const TargetRegisterClass *RC = MRI->getRegClass(R);
110 return RISCV::VRRegClass.hasSubClassEq(RC) ||
111 RISCV::VRM2RegClass.hasSubClassEq(RC) ||
112 RISCV::VRM4RegClass.hasSubClassEq(RC) ||
113 RISCV::VRM8RegClass.hasSubClassEq(RC);
114}
115
116static unsigned getUndefInitOpcode(unsigned RegClassID) {
117 switch (RegClassID) {
118 case RISCV::VRRegClassID:
119 return RISCV::PseudoRVVInitUndefM1;
120 case RISCV::VRM2RegClassID:
121 return RISCV::PseudoRVVInitUndefM2;
122 case RISCV::VRM4RegClassID:
123 return RISCV::PseudoRVVInitUndefM4;
124 case RISCV::VRM8RegClassID:
125 return RISCV::PseudoRVVInitUndefM8;
126 default:
127 llvm_unreachable("Unexpected register class.");
128 }
129}
130
132 return llvm::any_of(MI.defs(), [](const MachineOperand &DefMO) {
133 return DefMO.isReg() && DefMO.isEarlyClobber();
134 });
135}
136
137bool RISCVInitUndef::handleImplicitDef(MachineBasicBlock &MBB,
139 assert(Inst->getOpcode() == TargetOpcode::IMPLICIT_DEF);
140
141 Register Reg = Inst->getOperand(0).getReg();
142 if (!Reg.isVirtual())
143 return false;
144
145 bool HasOtherUse = false;
147 for (MachineOperand &MO : MRI->use_nodbg_operands(Reg)) {
148 if (isEarlyClobberMI(*MO.getParent())) {
149 if (MO.isUse() && !MO.isTied())
150 UseMOs.push_back(&MO);
151 else
152 HasOtherUse = true;
153 }
154 }
155
156 if (UseMOs.empty())
157 return false;
158
160 dbgs() << "Emitting PseudoRVVInitUndef for implicit vector register "
161 << Reg << '\n');
162
163 const TargetRegisterClass *TargetRegClass =
164 getVRLargestSuperClass(MRI->getRegClass(Reg));
165 unsigned Opcode = getUndefInitOpcode(TargetRegClass->getID());
166
167 Register NewDest = Reg;
168 if (HasOtherUse) {
169 NewDest = MRI->createVirtualRegister(TargetRegClass);
170 // We don't have a way to update dead lanes, so keep track of the
171 // new register so that we avoid querying it later.
172 NewRegs.insert(NewDest);
173 }
174 BuildMI(MBB, Inst, Inst->getDebugLoc(), TII->get(Opcode), NewDest);
175
176 if (!HasOtherUse)
177 Inst = MBB.erase(Inst);
178
179 for (auto MO : UseMOs) {
180 MO->setReg(NewDest);
181 MO->setIsUndef(false);
182 }
183 return true;
184}
185
186bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
187 const DeadLaneDetector &DLD) {
188 bool Changed = false;
189
190 for (MachineOperand &UseMO : MI.uses()) {
191 if (!UseMO.isReg())
192 continue;
193 if (!UseMO.getReg().isVirtual())
194 continue;
195 if (UseMO.isTied())
196 continue;
197
198 Register Reg = UseMO.getReg();
199 if (NewRegs.count(Reg))
200 continue;
203
204 if (Info.UsedLanes == Info.DefinedLanes)
205 continue;
206
207 const TargetRegisterClass *TargetRegClass =
208 getVRLargestSuperClass(MRI->getRegClass(Reg));
209
210 LaneBitmask NeedDef = Info.UsedLanes & ~Info.DefinedLanes;
211
212 LLVM_DEBUG({
213 dbgs() << "Instruction has undef subregister.\n";
214 dbgs() << printReg(Reg, nullptr)
215 << " Used: " << PrintLaneMask(Info.UsedLanes)
216 << " Def: " << PrintLaneMask(Info.DefinedLanes)
217 << " Need Def: " << PrintLaneMask(NeedDef) << "\n";
218 });
219
220 SmallVector<unsigned> SubRegIndexNeedInsert;
221 TRI->getCoveringSubRegIndexes(*MRI, TargetRegClass, NeedDef,
222 SubRegIndexNeedInsert);
223
224 Register LatestReg = Reg;
225 for (auto ind : SubRegIndexNeedInsert) {
226 Changed = true;
227 const TargetRegisterClass *SubRegClass =
228 getVRLargestSuperClass(TRI->getSubRegisterClass(TargetRegClass, ind));
229 Register TmpInitSubReg = MRI->createVirtualRegister(SubRegClass);
230 BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
231 TII->get(getUndefInitOpcode(SubRegClass->getID())),
232 TmpInitSubReg);
233 Register NewReg = MRI->createVirtualRegister(TargetRegClass);
234 BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
235 TII->get(TargetOpcode::INSERT_SUBREG), NewReg)
236 .addReg(LatestReg)
237 .addReg(TmpInitSubReg)
238 .addImm(ind);
239 LatestReg = NewReg;
240 }
241
242 UseMO.setReg(LatestReg);
243 }
244
245 return Changed;
246}
247
248bool RISCVInitUndef::processBasicBlock(MachineFunction &MF,
250 const DeadLaneDetector &DLD) {
251 bool Changed = false;
252 for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
253 MachineInstr &MI = *I;
254
255 // If we used NoReg to represent the passthru, switch this back to being
256 // an IMPLICIT_DEF before TwoAddressInstructions.
257 unsigned UseOpIdx;
258 if (MI.getNumDefs() != 0 && MI.isRegTiedToUseOperand(0, &UseOpIdx)) {
259 MachineOperand &UseMO = MI.getOperand(UseOpIdx);
260 if (UseMO.getReg() == RISCV::NoRegister) {
261 const TargetRegisterClass *RC =
262 TII->getRegClass(MI.getDesc(), UseOpIdx, TRI, MF);
263 Register NewDest = MRI->createVirtualRegister(RC);
264 // We don't have a way to update dead lanes, so keep track of the
265 // new register so that we avoid querying it later.
266 NewRegs.insert(NewDest);
267 BuildMI(MBB, I, I->getDebugLoc(),
268 TII->get(TargetOpcode::IMPLICIT_DEF), NewDest);
269 UseMO.setReg(NewDest);
270 Changed = true;
271 }
272 }
273
274 if (ST->enableSubRegLiveness() && isEarlyClobberMI(MI))
275 Changed |= handleSubReg(MF, MI, DLD);
276 if (MI.isImplicitDef()) {
277 auto DstReg = MI.getOperand(0).getReg();
278 if (isVectorRegClass(DstReg))
279 Changed |= handleImplicitDef(MBB, I);
280 }
281 }
282 return Changed;
283}
284
285bool RISCVInitUndef::runOnMachineFunction(MachineFunction &MF) {
287 if (!ST->hasVInstructions())
288 return false;
289
290 MRI = &MF.getRegInfo();
291 TII = ST->getInstrInfo();
292 TRI = MRI->getTargetRegisterInfo();
293
294 bool Changed = false;
297
298 for (MachineBasicBlock &BB : MF)
299 Changed |= processBasicBlock(MF, BB, DLD);
300
301 return Changed;
302}
303
304FunctionPass *llvm::createRISCVInitUndefPass() { return new RISCVInitUndef(); }
unsigned const MachineRegisterInfo * MRI
aarch64 promote const
MachineBasicBlock & MBB
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
#define LLVM_DEBUG(X)
Definition: Debug.h:101
Analysis that tracks defined/used subregister lanes across COPY instructions and instructions that ge...
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition: MD5.cpp:58
unsigned const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
static bool isEarlyClobberMI(MachineInstr &MI)
static unsigned getUndefInitOpcode(unsigned RegClassID)
#define RISCV_INIT_UNDEF_NAME
#define DEBUG_TYPE
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallSet class.
Represent the analysis usage information of a pass.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:269
void computeSubRegisterLaneBitInfo()
Update the DefinedLanes and the UsedLanes for all virtual registers.
const VRegInfo & getVRegInfo(unsigned RegIdx) const
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
Representation of each machine instruction.
Definition: MachineInstr.h:68
MachineOperand class - Representation of each machine instruction operand.
void setReg(Register Reg)
Change the register this operand corresponds to.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
static unsigned virtReg2Index(Register Reg)
Convert a virtual register number to a 0-based index.
Definition: Register.h:77
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:135
bool empty() const
Definition: SmallVector.h:94
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
TargetInstrInfo - Interface to description of machine instruction set.
unsigned getID() const
Return the register class ID number.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
Reg
All possible values of the reg field in the ModR/M byte.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
void initializeRISCVInitUndefPass(PassRegistry &)
Printable PrintLaneMask(LaneBitmask LaneMask)
Create Printable object to print LaneBitmasks on a raw_ostream.
Definition: LaneBitmask.h:92
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1734
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
FunctionPass * createRISCVInitUndefPass()
Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
char & RISCVInitUndefID
Contains a bitmask of which lanes of a given virtual register are defined and which ones are actually...