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 Register SrcReg = I->getOperand(I->getNumOperands() - 1).getReg();
58 SPIRVType *ScalarType = nullptr;
59 if (SPIRVType *DefType = GR->getSPIRVTypeForVReg(SrcReg)) {
60 assert(DefType->getOpcode() == SPIRV::OpTypeVector);
61 ScalarType = GR->getSPIRVTypeForVReg(DefType->getOperand(1).getReg());
62 }
63
64 if (!ScalarType) {
65 // If we could not deduce the type from the source, try to deduce it from
66 // the uses of the results.
67 for (unsigned i = 0; i < I->getNumDefs() && !ScalarType; ++i) {
68 for (const auto &Use :
69 MRI.use_nodbg_instructions(I->getOperand(i).getReg())) {
70 if (Use.getOpcode() != TargetOpcode::G_BUILD_VECTOR)
71 continue;
72
73 if (auto *VecType =
74 GR->getSPIRVTypeForVReg(Use.getOperand(0).getReg())) {
75 ScalarType = GR->getScalarOrVectorComponentType(VecType);
76 break;
77 }
78 }
79 }
80 }
81
82 if (!ScalarType)
83 return false;
84
85 for (unsigned i = 0; i < I->getNumDefs(); ++i) {
86 Register DefReg = I->getOperand(i).getReg();
87 if (GR->getSPIRVTypeForVReg(DefReg))
88 continue;
89
90 LLT DefLLT = MRI.getType(DefReg);
91 SPIRVType *ResType =
92 DefLLT.isVector()
94 ScalarType, DefLLT.getNumElements(), *I,
96 : ScalarType;
97 setRegClassType(DefReg, ResType, GR, &MRI, MF);
98 }
99 return true;
100}
101
103 MachineIRBuilder &MIB,
105 unsigned OpIdx) {
106 Register OpReg = I->getOperand(OpIdx).getReg();
107 if (SPIRVType *OpType = GR->getSPIRVTypeForVReg(OpReg)) {
108 if (SPIRVType *CompType = GR->getScalarOrVectorComponentType(OpType)) {
109 Register ResVReg = I->getOperand(0).getReg();
110 const LLT &ResLLT = MIB.getMRI()->getType(ResVReg);
111 if (ResLLT.isVector())
112 return GR->getOrCreateSPIRVVectorType(CompType, ResLLT.getNumElements(),
113 MIB, false);
114 return CompType;
115 }
116 }
117 return nullptr;
118}
119
121 MachineIRBuilder &MIB,
123 unsigned StartOp, unsigned EndOp) {
124 SPIRVType *ResType = nullptr;
125 for (unsigned i = StartOp; i < EndOp; ++i) {
126 if (SPIRVType *Type = deduceTypeFromSingleOperand(I, MIB, GR, i)) {
127#ifdef EXPENSIVE_CHECKS
128 assert(!ResType || Type == ResType && "Conflicting type from operands.");
129 ResType = Type;
130#else
131 return Type;
132#endif
133 }
134 }
135 return ResType;
136}
137
139 Register UseRegister,
141 MachineIRBuilder &MIB) {
142 for (const MachineOperand &MO : Use->defs()) {
143 if (!MO.isReg())
144 continue;
145 if (SPIRVType *OpType = GR->getSPIRVTypeForVReg(MO.getReg())) {
146 if (SPIRVType *CompType = GR->getScalarOrVectorComponentType(OpType)) {
147 const LLT &ResLLT = MIB.getMRI()->getType(UseRegister);
148 if (ResLLT.isVector())
150 CompType, ResLLT.getNumElements(), MIB, false);
151 return CompType;
152 }
153 }
154 }
155 return nullptr;
156}
157
160 MachineIRBuilder &MIB) {
162 for (MachineInstr &Use : MRI.use_nodbg_instructions(Reg)) {
163 SPIRVType *ResType = nullptr;
164 LLVM_DEBUG(dbgs() << "Looking at use " << Use);
165 switch (Use.getOpcode()) {
166 case TargetOpcode::G_BUILD_VECTOR:
167 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
168 case TargetOpcode::G_UNMERGE_VALUES:
169 case TargetOpcode::G_ADD:
170 case TargetOpcode::G_SUB:
171 case TargetOpcode::G_MUL:
172 case TargetOpcode::G_SDIV:
173 case TargetOpcode::G_UDIV:
174 case TargetOpcode::G_SREM:
175 case TargetOpcode::G_UREM:
176 case TargetOpcode::G_FADD:
177 case TargetOpcode::G_FSUB:
178 case TargetOpcode::G_FMUL:
179 case TargetOpcode::G_FDIV:
180 case TargetOpcode::G_FREM:
181 case TargetOpcode::G_FMA:
182 case TargetOpcode::G_STRICT_FMA:
183 ResType = deduceTypeFromResultRegister(&Use, Reg, GR, MIB);
184 break;
185 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
186 case TargetOpcode::G_INTRINSIC: {
187 auto IntrinsicID = cast<GIntrinsic>(Use).getIntrinsicID();
188 if (IntrinsicID == Intrinsic::spv_insertelt) {
189 if (Reg == Use.getOperand(2).getReg())
190 ResType = deduceTypeFromResultRegister(&Use, Reg, GR, MIB);
191 } else if (IntrinsicID == Intrinsic::spv_extractelt) {
192 if (Reg == Use.getOperand(2).getReg())
193 ResType = deduceTypeFromResultRegister(&Use, Reg, GR, MIB);
194 }
195 break;
196 }
197 }
198 if (ResType) {
199 LLVM_DEBUG(dbgs() << "Deduced type from use " << *ResType);
200 return ResType;
201 }
202 }
203 return nullptr;
204}
205
208 MachineIRBuilder &MIB) {
209 Register ResVReg = I->getOperand(0).getReg();
210 switch (I->getOpcode()) {
211 case TargetOpcode::G_CONSTANT:
212 case TargetOpcode::G_ANYEXT:
213 return deduceIntTypeFromResult(ResVReg, MIB, GR);
214 case TargetOpcode::G_BUILD_VECTOR:
215 return deduceTypeFromOperandRange(I, MIB, GR, 1, I->getNumOperands());
216 case TargetOpcode::G_SHUFFLE_VECTOR:
217 return deduceTypeFromOperandRange(I, MIB, GR, 1, 3);
218 default:
219 if (I->getNumDefs() == 1 && I->getNumOperands() > 1 &&
220 I->getOperand(1).isReg())
221 return deduceTypeFromSingleOperand(I, MIB, GR, 1);
222 return nullptr;
223 }
224}
225
228 MachineIRBuilder &MIB) {
229 LLVM_DEBUG(dbgs() << "\nProcessing instruction: " << *I);
231 Register ResVReg = I->getOperand(0).getReg();
232
233 // G_UNMERGE_VALUES is handled separately because it has multiple definitions,
234 // unlike the other instructions which have a single result register. The main
235 // deduction logic is designed for the single-definition case.
236 if (I->getOpcode() == TargetOpcode::G_UNMERGE_VALUES)
237 return deduceAndAssignTypeForGUnmerge(I, MF, GR);
238
239 LLVM_DEBUG(dbgs() << "Inferring type from operands\n");
240 SPIRVType *ResType = deduceResultTypeFromOperands(I, GR, MIB);
241 if (!ResType) {
242 LLVM_DEBUG(dbgs() << "Inferring type from uses\n");
243 ResType = deduceTypeFromUses(ResVReg, MF, GR, MIB);
244 }
245
246 if (!ResType)
247 return false;
248
249 LLVM_DEBUG(dbgs() << "Assigned type to " << *I << ": " << *ResType);
250 GR->assignSPIRVTypeToVReg(ResType, ResVReg, MF);
251
252 if (!MRI.getRegClassOrNull(ResVReg)) {
253 LLVM_DEBUG(dbgs() << "Updating the register class.\n");
254 setRegClassType(ResVReg, ResType, GR, &MRI, *GR->CurMF, true);
255 }
256 return true;
257}
258
261 LLVM_DEBUG(dbgs() << "Checking if instruction requires a SPIR-V type: "
262 << I;);
263 if (I.getNumDefs() == 0) {
264 LLVM_DEBUG(dbgs() << "Instruction does not have a definition.\n");
265 return false;
266 }
267
268 if (!I.isPreISelOpcode()) {
269 LLVM_DEBUG(dbgs() << "Instruction is not a generic instruction.\n");
270 return false;
271 }
272
273 Register ResultRegister = I.defs().begin()->getReg();
274 if (GR->getSPIRVTypeForVReg(ResultRegister)) {
275 LLVM_DEBUG(dbgs() << "Instruction already has a SPIR-V type.\n");
276 if (!MRI.getRegClassOrNull(ResultRegister)) {
277 LLVM_DEBUG(dbgs() << "Updating the register class.\n");
278 setRegClassType(ResultRegister, GR->getSPIRVTypeForVReg(ResultRegister),
279 GR, &MRI, *GR->CurMF, true);
280 }
281 return false;
282 }
283
284 return true;
285}
286
291 for (MachineBasicBlock &MBB : MF) {
292 for (MachineInstr &I : MBB) {
293 if (requiresSpirvType(I, GR, MRI)) {
294 Worklist.push_back(&I);
295 }
296 }
297 }
298
299 if (Worklist.empty()) {
300 LLVM_DEBUG(dbgs() << "Initial worklist is empty.\n");
301 return;
302 }
303
304 LLVM_DEBUG(dbgs() << "Initial worklist:\n";
305 for (auto *I : Worklist) { I->dump(); });
306
307 bool Changed;
308 do {
309 Changed = false;
311
312 for (MachineInstr *I : Worklist) {
313 MachineIRBuilder MIB(*I);
314 if (deduceAndAssignSpirvType(I, MF, GR, MIB)) {
315 Changed = true;
316 } else {
317 NextWorklist.push_back(I);
318 }
319 }
320 Worklist = std::move(NextWorklist);
321 LLVM_DEBUG(dbgs() << "Worklist size: " << Worklist.size() << "\n");
322 } while (Changed);
323
324 if (Worklist.empty())
325 return;
326
327 for (auto *I : Worklist) {
328 MachineIRBuilder MIB(*I);
329 for (unsigned Idx = 0; Idx < I->getNumDefs(); ++Idx) {
330 Register ResVReg = I->getOperand(Idx).getReg();
331 if (GR->getSPIRVTypeForVReg(ResVReg))
332 continue;
333 const LLT &ResLLT = MRI.getType(ResVReg);
334 SPIRVType *ResType = nullptr;
335 if (ResLLT.isVector()) {
337 ResLLT.getElementType().getSizeInBits(), MIB);
338 ResType = GR->getOrCreateSPIRVVectorType(
339 CompType, ResLLT.getNumElements(), MIB, false);
340 } else {
341 ResType = GR->getOrCreateSPIRVIntegerType(ResLLT.getSizeInBits(), MIB);
342 }
343 LLVM_DEBUG(dbgs() << "Could not determine type for " << ResVReg
344 << ", defaulting to " << *ResType << "\n");
345
346 setRegClassType(ResVReg, ResType, GR, &MRI, MF, true);
347 }
348 }
349}
350
352 for (MachineInstr &UseInstr : MRI.use_nodbg_instructions(Reg)) {
353 if (UseInstr.getOpcode() == SPIRV::ASSIGN_TYPE) {
354 return true;
355 }
356 }
357 return false;
358}
359
360static void generateAssignType(MachineInstr &MI, Register ResultRegister,
361 SPIRVType *ResultType, SPIRVGlobalRegistry *GR,
363 LLVM_DEBUG(dbgs() << " Adding ASSIGN_TYPE for ResultRegister: "
364 << printReg(ResultRegister, MRI.getTargetRegisterInfo())
365 << " with type: " << *ResultType);
366 MachineIRBuilder MIB(MI);
367 updateRegType(ResultRegister, nullptr, ResultType, GR, MIB, MRI);
368
369 // Tablegen definition assumes SPIRV::ASSIGN_TYPE pseudo-instruction is
370 // present after each auto-folded instruction to take a type reference
371 // from.
372 Register NewReg =
373 MRI.createGenericVirtualRegister(MRI.getType(ResultRegister));
374 const auto *RegClass = GR->getRegClass(ResultType);
375 MRI.setRegClass(NewReg, RegClass);
376 MRI.setRegClass(ResultRegister, RegClass);
377
378 GR->assignSPIRVTypeToVReg(ResultType, ResultRegister, MIB.getMF());
379 // This is to make it convenient for Legalizer to get the SPIRVType
380 // when processing the actual MI (i.e. not pseudo one).
381 GR->assignSPIRVTypeToVReg(ResultType, NewReg, MIB.getMF());
382 // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to
383 // keep the flags after instruction selection.
384 const uint32_t Flags = MI.getFlags();
385 MIB.buildInstr(SPIRV::ASSIGN_TYPE)
386 .addDef(ResultRegister)
387 .addUse(NewReg)
388 .addUse(GR->getSPIRVTypeID(ResultType))
389 .setMIFlags(Flags);
390 for (unsigned I = 0, E = MI.getNumDefs(); I != E; ++I) {
391 MachineOperand &MO = MI.getOperand(I);
392 if (MO.getReg() == ResultRegister) {
393 MO.setReg(NewReg);
394 break;
395 }
396 }
397}
398
401 LLVM_DEBUG(dbgs() << "Entering ensureAssignTypeForTypeFolding for function "
402 << MF.getName() << "\n");
404 for (MachineBasicBlock &MBB : MF) {
405 for (MachineInstr &MI : MBB) {
406 if (!isTypeFoldingSupported(MI.getOpcode()))
407 continue;
408
409 LLVM_DEBUG(dbgs() << "Processing instruction: " << MI);
410
411 Register ResultRegister = MI.defs().begin()->getReg();
412 if (hasAssignType(ResultRegister, MRI)) {
413 LLVM_DEBUG(dbgs() << " Instruction already has ASSIGN_TYPE\n");
414 continue;
415 }
416
417 SPIRVType *ResultType = GR->getSPIRVTypeForVReg(ResultRegister);
418 assert(ResultType);
419 generateAssignType(MI, ResultRegister, ResultType, GR, MRI);
420 }
421 }
422}
423
424// Do a preorder traversal of the CFG starting from the BB |Start|.
425// point. Calls |op| on each basic block encountered during the traversal.
427 std::function<void(MachineBasicBlock *)> op) {
428 std::stack<MachineBasicBlock *> ToVisit;
430
431 ToVisit.push(&Start);
432 Seen.insert(ToVisit.top());
433 while (ToVisit.size() != 0) {
434 MachineBasicBlock *MBB = ToVisit.top();
435 ToVisit.pop();
436
437 op(MBB);
438
439 for (auto Succ : MBB->successors()) {
440 if (Seen.contains(Succ))
441 continue;
442 ToVisit.push(Succ);
443 Seen.insert(Succ);
444 }
445 }
446}
447
448// Do a preorder traversal of the CFG starting from the given function's entry
449// point. Calls |op| on each basic block encountered during the traversal.
450void visit(MachineFunction &MF, std::function<void(MachineBasicBlock *)> op) {
451 visit(MF, *MF.begin(), std::move(op));
452}
453
454bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) {
455 // Initialize the type registry.
456 const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
457 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
458 GR->setCurrentFunc(MF);
461 return true;
462}
463
464INITIALIZE_PASS(SPIRVPostLegalizer, DEBUG_TYPE, "SPIRV post legalizer", false,
465 false)
466
467char SPIRVPostLegalizer::ID = 0;
468
469FunctionPass *llvm::createSPIRVPostLegalizerPass() {
470 return new SPIRVPostLegalizer();
471}
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 bool deduceAndAssignTypeForGUnmerge(MachineInstr *I, MachineFunction &MF, SPIRVGlobalRegistry *GR)
static void ensureAssignTypeForTypeFolding(MachineFunction &MF, SPIRVGlobalRegistry *GR)
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.