LLVM 22.0.0git
SPIRVPostLegalizer.cpp
Go to the documentation of this file.
1//===-- SPIRVPostLegalizer.cpp - amend info after legalization -*- C++ -*-===//
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// The pass partially applies pre-legalization logic to new instructions
10// inserted as a result of legalization:
11// - assigns SPIR-V types to registers for new instructions.
12// - inserts ASSIGN_TYPE pseudo-instructions required for type folding.
13//
14//===----------------------------------------------------------------------===//
15
16#include "SPIRV.h"
17#include "SPIRVSubtarget.h"
18#include "SPIRVUtils.h"
20#include "llvm/IR/IntrinsicsSPIRV.h"
21#include "llvm/Support/Debug.h"
22#include <stack>
23
24#define DEBUG_TYPE "spirv-postlegalizer"
25
26using namespace llvm;
27
28namespace {
29class SPIRVPostLegalizer : public MachineFunctionPass {
30public:
31 static char ID;
32 SPIRVPostLegalizer() : MachineFunctionPass(ID) {}
33 bool runOnMachineFunction(MachineFunction &MF) override;
34};
35} // namespace
36
37namespace llvm {
38// Defined in SPIRVPreLegalizer.cpp.
39extern void updateRegType(Register Reg, Type *Ty, SPIRVType *SpirvTy,
44 SPIRVType *KnownResType);
45} // namespace llvm
46
50 const LLT &Ty = MIB.getMRI()->getType(ResVReg);
51 return GR->getOrCreateSPIRVIntegerType(Ty.getScalarSizeInBits(), MIB);
52}
53
57 unsigned OpIdx) {
58 Register OpReg = I->getOperand(OpIdx).getReg();
59 if (SPIRVType *OpType = GR->getSPIRVTypeForVReg(OpReg)) {
60 if (SPIRVType *CompType = GR->getScalarOrVectorComponentType(OpType)) {
61 Register ResVReg = I->getOperand(0).getReg();
62 const LLT &ResLLT = MIB.getMRI()->getType(ResVReg);
63 if (ResLLT.isVector())
64 return GR->getOrCreateSPIRVVectorType(CompType, ResLLT.getNumElements(),
65 MIB, false);
66 return CompType;
67 }
68 }
69 return nullptr;
70}
71
75 unsigned StartOp, unsigned EndOp) {
76 SPIRVType *ResType = nullptr;
77 for (unsigned i = StartOp; i < EndOp; ++i) {
78 if (SPIRVType *Type = deduceTypeFromSingleOperand(I, MIB, GR, i)) {
79#ifdef EXPENSIVE_CHECKS
80 assert(!ResType || Type == ResType && "Conflicting type from operands.");
81 ResType = Type;
82#else
83 return Type;
84#endif
85 }
86 }
87 return ResType;
88}
89
91 Register UseRegister,
93 MachineIRBuilder &MIB) {
94 for (const MachineOperand &MO : Use->defs()) {
95 if (!MO.isReg())
96 continue;
97 if (SPIRVType *OpType = GR->getSPIRVTypeForVReg(MO.getReg())) {
98 if (SPIRVType *CompType = GR->getScalarOrVectorComponentType(OpType)) {
99 const LLT &ResLLT = MIB.getMRI()->getType(UseRegister);
100 if (ResLLT.isVector())
102 CompType, ResLLT.getNumElements(), MIB, false);
103 return CompType;
104 }
105 }
106 }
107 return nullptr;
108}
109
112 MachineIRBuilder &MIB) {
114 for (MachineInstr &Use : MRI.use_nodbg_instructions(Reg)) {
115 SPIRVType *ResType = nullptr;
116 LLVM_DEBUG(dbgs() << "Looking at use " << Use);
117 switch (Use.getOpcode()) {
118 case TargetOpcode::G_BUILD_VECTOR:
119 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
120 case TargetOpcode::G_UNMERGE_VALUES:
121 case TargetOpcode::G_ADD:
122 case TargetOpcode::G_SUB:
123 case TargetOpcode::G_MUL:
124 case TargetOpcode::G_SDIV:
125 case TargetOpcode::G_UDIV:
126 case TargetOpcode::G_SREM:
127 case TargetOpcode::G_UREM:
128 case TargetOpcode::G_FADD:
129 case TargetOpcode::G_FSUB:
130 case TargetOpcode::G_FMUL:
131 case TargetOpcode::G_FDIV:
132 case TargetOpcode::G_FREM:
133 case TargetOpcode::G_FMA:
134 case TargetOpcode::COPY:
135 case TargetOpcode::G_STRICT_FMA:
136 ResType = deduceTypeFromResultRegister(&Use, Reg, GR, MIB);
137 break;
138 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
139 case TargetOpcode::G_INTRINSIC: {
140 auto IntrinsicID = cast<GIntrinsic>(Use).getIntrinsicID();
141 if (IntrinsicID == Intrinsic::spv_insertelt) {
142 if (Reg == Use.getOperand(2).getReg())
143 ResType = deduceTypeFromResultRegister(&Use, Reg, GR, MIB);
144 } else if (IntrinsicID == Intrinsic::spv_extractelt) {
145 if (Reg == Use.getOperand(2).getReg())
146 ResType = deduceTypeFromResultRegister(&Use, Reg, GR, MIB);
147 }
148 break;
149 }
150 }
151 if (ResType) {
152 LLVM_DEBUG(dbgs() << "Deduced type from use " << *ResType);
153 return ResType;
154 }
155 }
156 return nullptr;
157}
158
161 MachineIRBuilder &MIB) {
162 Register ResVReg = I->getOperand(0).getReg();
163 switch (I->getOpcode()) {
164 case TargetOpcode::G_CONSTANT:
165 case TargetOpcode::G_ANYEXT:
166 return deduceIntTypeFromResult(ResVReg, MIB, GR);
167 case TargetOpcode::G_BUILD_VECTOR:
168 return deduceTypeFromOperandRange(I, MIB, GR, 1, I->getNumOperands());
169 case TargetOpcode::G_SHUFFLE_VECTOR:
170 return deduceTypeFromOperandRange(I, MIB, GR, 1, 3);
171 default:
172 if (I->getNumDefs() == 1 && I->getNumOperands() > 1 &&
173 I->getOperand(1).isReg())
174 return deduceTypeFromSingleOperand(I, MIB, GR, 1);
175 return nullptr;
176 }
177}
178
181 MachineIRBuilder &MIB) {
183 Register SrcReg = I->getOperand(I->getNumOperands() - 1).getReg();
184 SPIRVType *ScalarType = nullptr;
185 if (SPIRVType *DefType = GR->getSPIRVTypeForVReg(SrcReg)) {
186 assert(DefType->getOpcode() == SPIRV::OpTypeVector);
187 ScalarType = GR->getSPIRVTypeForVReg(DefType->getOperand(1).getReg());
188 }
189
190 if (!ScalarType) {
191 // If we could not deduce the type from the source, try to deduce it from
192 // the uses of the results.
193 for (unsigned i = 0; i < I->getNumDefs(); ++i) {
194 Register DefReg = I->getOperand(i).getReg();
195 ScalarType = deduceTypeFromUses(DefReg, MF, GR, MIB);
196 if (ScalarType) {
197 ScalarType = GR->getScalarOrVectorComponentType(ScalarType);
198 break;
199 }
200 }
201 }
202
203 if (!ScalarType)
204 return false;
205
206 for (unsigned i = 0; i < I->getNumOperands(); ++i) {
207 Register DefReg = I->getOperand(i).getReg();
208 if (GR->getSPIRVTypeForVReg(DefReg))
209 continue;
210
211 LLT DefLLT = MRI.getType(DefReg);
212 SPIRVType *ResType =
213 DefLLT.isVector()
215 ScalarType, DefLLT.getNumElements(), *I,
217 : ScalarType;
218 setRegClassType(DefReg, ResType, GR, &MRI, MF);
219 }
220 return true;
221}
222
225 MachineIRBuilder &MIB) {
226 LLVM_DEBUG(dbgs() << "\nProcessing instruction: " << *I);
228 Register ResVReg = I->getOperand(0).getReg();
229
230 // G_UNMERGE_VALUES is handled separately because it has multiple definitions,
231 // unlike the other instructions which have a single result register. The main
232 // deduction logic is designed for the single-definition case.
233 if (I->getOpcode() == TargetOpcode::G_UNMERGE_VALUES)
234 return deduceAndAssignTypeForGUnmerge(I, MF, GR, MIB);
235
236 LLVM_DEBUG(dbgs() << "Inferring type from operands\n");
237 SPIRVType *ResType = deduceResultTypeFromOperands(I, GR, MIB);
238 if (!ResType) {
239 LLVM_DEBUG(dbgs() << "Inferring type from uses\n");
240 ResType = deduceTypeFromUses(ResVReg, MF, GR, MIB);
241 }
242
243 if (!ResType)
244 return false;
245
246 LLVM_DEBUG(dbgs() << "Assigned type to " << *I << ": " << *ResType);
247 GR->assignSPIRVTypeToVReg(ResType, ResVReg, MF);
248
249 if (!MRI.getRegClassOrNull(ResVReg)) {
250 LLVM_DEBUG(dbgs() << "Updating the register class.\n");
251 setRegClassType(ResVReg, ResType, GR, &MRI, *GR->CurMF, true);
252 }
253 return true;
254}
255
258 LLVM_DEBUG(dbgs() << "Checking if instruction requires a SPIR-V type: "
259 << I;);
260 if (I.getNumDefs() == 0) {
261 LLVM_DEBUG(dbgs() << "Instruction does not have a definition.\n");
262 return false;
263 }
264
265 if (!I.isPreISelOpcode()) {
266 LLVM_DEBUG(dbgs() << "Instruction is not a generic instruction.\n");
267 return false;
268 }
269
270 Register ResultRegister = I.defs().begin()->getReg();
271 if (GR->getSPIRVTypeForVReg(ResultRegister)) {
272 LLVM_DEBUG(dbgs() << "Instruction already has a SPIR-V type.\n");
273 if (!MRI.getRegClassOrNull(ResultRegister)) {
274 LLVM_DEBUG(dbgs() << "Updating the register class.\n");
275 setRegClassType(ResultRegister, GR->getSPIRVTypeForVReg(ResultRegister),
276 GR, &MRI, *GR->CurMF, true);
277 }
278 return false;
279 }
280
281 return true;
282}
283
288 for (MachineBasicBlock &MBB : MF) {
289 for (MachineInstr &I : MBB) {
290 if (requiresSpirvType(I, GR, MRI)) {
291 Worklist.push_back(&I);
292 }
293 }
294 }
295
296 if (Worklist.empty()) {
297 LLVM_DEBUG(dbgs() << "Initial worklist is empty.\n");
298 return;
299 }
300
301 LLVM_DEBUG(dbgs() << "Initial worklist:\n";
302 for (auto *I : Worklist) { I->dump(); });
303
304 bool Changed;
305 do {
306 Changed = false;
308
309 for (MachineInstr *I : Worklist) {
310 MachineIRBuilder MIB(*I);
311 if (deduceAndAssignSpirvType(I, MF, GR, MIB)) {
312 Changed = true;
313 } else {
314 NextWorklist.push_back(I);
315 }
316 }
317 Worklist = std::move(NextWorklist);
318 LLVM_DEBUG(dbgs() << "Worklist size: " << Worklist.size() << "\n");
319 } while (Changed);
320
321 if (Worklist.empty())
322 return;
323
324 for (auto *I : Worklist) {
325 MachineIRBuilder MIB(*I);
326 for (unsigned Idx = 0; Idx < I->getNumDefs(); ++Idx) {
327 Register ResVReg = I->getOperand(Idx).getReg();
328 if (GR->getSPIRVTypeForVReg(ResVReg))
329 continue;
330 const LLT &ResLLT = MRI.getType(ResVReg);
331 SPIRVType *ResType = nullptr;
332 if (ResLLT.isVector()) {
334 ResLLT.getElementType().getSizeInBits(), MIB);
335 ResType = GR->getOrCreateSPIRVVectorType(
336 CompType, ResLLT.getNumElements(), MIB, false);
337 } else {
338 ResType = GR->getOrCreateSPIRVIntegerType(ResLLT.getSizeInBits(), MIB);
339 }
340 LLVM_DEBUG(dbgs() << "Could not determine type for " << ResVReg
341 << ", defaulting to " << *ResType << "\n");
342
343 setRegClassType(ResVReg, ResType, GR, &MRI, MF, true);
344 }
345 }
346}
347
349 for (MachineInstr &UseInstr : MRI.use_nodbg_instructions(Reg)) {
350 if (UseInstr.getOpcode() == SPIRV::ASSIGN_TYPE) {
351 return true;
352 }
353 }
354 return false;
355}
356
357static void generateAssignType(MachineInstr &MI, Register ResultRegister,
358 SPIRVType *ResultType, SPIRVGlobalRegistry *GR,
360 LLVM_DEBUG(dbgs() << " Adding ASSIGN_TYPE for ResultRegister: "
361 << printReg(ResultRegister, MRI.getTargetRegisterInfo())
362 << " with type: " << *ResultType);
363 MachineIRBuilder MIB(MI);
364 updateRegType(ResultRegister, nullptr, ResultType, GR, MIB, MRI);
365
366 // Tablegen definition assumes SPIRV::ASSIGN_TYPE pseudo-instruction is
367 // present after each auto-folded instruction to take a type reference
368 // from.
369 Register NewReg =
370 MRI.createGenericVirtualRegister(MRI.getType(ResultRegister));
371 const auto *RegClass = GR->getRegClass(ResultType);
372 MRI.setRegClass(NewReg, RegClass);
373 MRI.setRegClass(ResultRegister, RegClass);
374
375 GR->assignSPIRVTypeToVReg(ResultType, ResultRegister, MIB.getMF());
376 // This is to make it convenient for Legalizer to get the SPIRVType
377 // when processing the actual MI (i.e. not pseudo one).
378 GR->assignSPIRVTypeToVReg(ResultType, NewReg, MIB.getMF());
379 // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to
380 // keep the flags after instruction selection.
381 const uint32_t Flags = MI.getFlags();
382 MIB.buildInstr(SPIRV::ASSIGN_TYPE)
383 .addDef(ResultRegister)
384 .addUse(NewReg)
385 .addUse(GR->getSPIRVTypeID(ResultType))
386 .setMIFlags(Flags);
387 for (unsigned I = 0, E = MI.getNumDefs(); I != E; ++I) {
388 MachineOperand &MO = MI.getOperand(I);
389 if (MO.getReg() == ResultRegister) {
390 MO.setReg(NewReg);
391 break;
392 }
393 }
394}
395
398 LLVM_DEBUG(dbgs() << "Entering ensureAssignTypeForTypeFolding for function "
399 << MF.getName() << "\n");
401 for (MachineBasicBlock &MBB : MF) {
402 for (MachineInstr &MI : MBB) {
403 if (!isTypeFoldingSupported(MI.getOpcode()))
404 continue;
405
406 LLVM_DEBUG(dbgs() << "Processing instruction: " << MI);
407
408 Register ResultRegister = MI.defs().begin()->getReg();
409 if (hasAssignType(ResultRegister, MRI)) {
410 LLVM_DEBUG(dbgs() << " Instruction already has ASSIGN_TYPE\n");
411 continue;
412 }
413
414 SPIRVType *ResultType = GR->getSPIRVTypeForVReg(ResultRegister);
415 assert(ResultType);
416 generateAssignType(MI, ResultRegister, ResultType, GR, MRI);
417 }
418 }
419}
420
421// Do a preorder traversal of the CFG starting from the BB |Start|.
422// point. Calls |op| on each basic block encountered during the traversal.
424 std::function<void(MachineBasicBlock *)> op) {
425 std::stack<MachineBasicBlock *> ToVisit;
427
428 ToVisit.push(&Start);
429 Seen.insert(ToVisit.top());
430 while (ToVisit.size() != 0) {
431 MachineBasicBlock *MBB = ToVisit.top();
432 ToVisit.pop();
433
434 op(MBB);
435
436 for (auto Succ : MBB->successors()) {
437 if (Seen.contains(Succ))
438 continue;
439 ToVisit.push(Succ);
440 Seen.insert(Succ);
441 }
442 }
443}
444
445// Do a preorder traversal of the CFG starting from the given function's entry
446// point. Calls |op| on each basic block encountered during the traversal.
447void visit(MachineFunction &MF, std::function<void(MachineBasicBlock *)> op) {
448 visit(MF, *MF.begin(), std::move(op));
449}
450
451bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) {
452 // Initialize the type registry.
453 const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
454 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
455 GR->setCurrentFunc(MF);
458 return true;
459}
460
461INITIALIZE_PASS(SPIRVPostLegalizer, DEBUG_TYPE, "SPIRV post legalizer", false,
462 false)
463
464char SPIRVPostLegalizer::ID = 0;
465
466FunctionPass *llvm::createSPIRVPostLegalizerPass() {
467 return new SPIRVPostLegalizer();
468}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define DEBUG_TYPE
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
#define op(i)
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
MachineInstr unsigned OpIdx
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static bool deduceAndAssignSpirvType(MachineInstr *I, MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static SPIRVType * deduceIntTypeFromResult(Register ResVReg, MachineIRBuilder &MIB, SPIRVGlobalRegistry *GR)
void visit(MachineFunction &MF, MachineBasicBlock &Start, std::function< void(MachineBasicBlock *)> op)
static void registerSpirvTypeForNewInstructions(MachineFunction &MF, SPIRVGlobalRegistry *GR)
static bool hasAssignType(Register Reg, MachineRegisterInfo &MRI)
static SPIRVType * deduceResultTypeFromOperands(MachineInstr *I, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static SPIRVType * deduceTypeFromOperandRange(MachineInstr *I, MachineIRBuilder &MIB, SPIRVGlobalRegistry *GR, unsigned StartOp, unsigned EndOp)
static SPIRVType * deduceTypeFromUses(Register Reg, MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static SPIRVType * deduceTypeFromResultRegister(MachineInstr *Use, Register UseRegister, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static void generateAssignType(MachineInstr &MI, Register ResultRegister, SPIRVType *ResultType, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI)
static void ensureAssignTypeForTypeFolding(MachineFunction &MF, SPIRVGlobalRegistry *GR)
static bool deduceAndAssignTypeForGUnmerge(MachineInstr *I, MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static bool requiresSpirvType(MachineInstr &I, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI)
static SPIRVType * deduceTypeFromSingleOperand(MachineInstr *I, MachineIRBuilder &MIB, SPIRVGlobalRegistry *GR, unsigned OpIdx)
#define LLVM_DEBUG(...)
Definition Debug.h:114
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Helper class to build MachineInstr.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
LLVM_ABI 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,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
SPIRVType * getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, const MachineFunction &MF)
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
SPIRVType * getScalarOrVectorComponentType(Register VReg) const
const TargetRegisterClass * getRegClass(SPIRVType *SpvType) const
SPIRVType * getOrCreateSPIRVVectorType(SPIRVType *BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
SPIRVType * getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
const SPIRVInstrInfo * getInstrInfo() const override
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
bool isTypeFoldingSupported(unsigned Opcode)
void updateRegType(Register Reg, Type *Ty, SPIRVType *SpirvTy, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Helper external function for assigning SPIRVType to a register, ensuring the register class and type ...
void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR, SPIRVType *KnownResType)
FunctionPass * createSPIRVPostLegalizerPass()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
void setRegClassType(Register Reg, SPIRVType *SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF, bool Force)
const MachineInstr SPIRVType
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI 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.