LLVM 19.0.0git
SPIRVPreLegalizer.cpp
Go to the documentation of this file.
1//===-- SPIRVPreLegalizer.cpp - prepare IR for 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 prepares IR for legalization: it assigns SPIR-V types to registers
10// and removes intrinsics which holded these types during IR translation.
11// Also it processes constants and registers them in GR to avoid duplication.
12//
13//===----------------------------------------------------------------------===//
14
15#include "SPIRV.h"
16#include "SPIRVSubtarget.h"
17#include "SPIRVUtils.h"
20#include "llvm/IR/Attributes.h"
21#include "llvm/IR/Constants.h"
23#include "llvm/IR/IntrinsicsSPIRV.h"
25
26#define DEBUG_TYPE "spirv-prelegalizer"
27
28using namespace llvm;
29
30namespace {
31class SPIRVPreLegalizer : public MachineFunctionPass {
32public:
33 static char ID;
34 SPIRVPreLegalizer() : MachineFunctionPass(ID) {
36 }
37 bool runOnMachineFunction(MachineFunction &MF) override;
38};
39} // namespace
40
41static void
43 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
45 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
46 SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites;
47 for (MachineBasicBlock &MBB : MF) {
48 for (MachineInstr &MI : MBB) {
49 if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant))
50 continue;
51 ToErase.push_back(&MI);
52 Register SrcReg = MI.getOperand(2).getReg();
53 auto *Const =
54 cast<Constant>(cast<ConstantAsMetadata>(
55 MI.getOperand(3).getMetadata()->getOperand(0))
56 ->getValue());
57 if (auto *GV = dyn_cast<GlobalValue>(Const)) {
58 Register Reg = GR->find(GV, &MF);
59 if (!Reg.isValid())
60 GR->add(GV, &MF, SrcReg);
61 else
62 RegsAlreadyAddedToDT[&MI] = Reg;
63 } else {
64 Register Reg = GR->find(Const, &MF);
65 if (!Reg.isValid()) {
66 if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) {
67 auto *BuildVec = MRI.getVRegDef(SrcReg);
68 assert(BuildVec &&
69 BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
70 for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) {
71 // Ensure that OpConstantComposite reuses a constant when it's
72 // already created and available in the same machine function.
73 Constant *ElemConst = ConstVec->getElementAsConstant(i);
74 Register ElemReg = GR->find(ElemConst, &MF);
75 if (!ElemReg.isValid())
76 GR->add(ElemConst, &MF, BuildVec->getOperand(1 + i).getReg());
77 else
78 BuildVec->getOperand(1 + i).setReg(ElemReg);
79 }
80 }
81 GR->add(Const, &MF, SrcReg);
82 if (Const->getType()->isTargetExtTy()) {
83 // remember association so that we can restore it when assign types
84 MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);
85 if (SrcMI && SrcMI->getOpcode() == TargetOpcode::G_CONSTANT)
86 TargetExtConstTypes[SrcMI] = Const->getType();
87 }
88 } else {
89 RegsAlreadyAddedToDT[&MI] = Reg;
90 // This MI is unused and will be removed. If the MI uses
91 // const_composite, it will be unused and should be removed too.
92 assert(MI.getOperand(2).isReg() && "Reg operand is expected");
93 MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg());
94 if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))
95 ToEraseComposites.push_back(SrcMI);
96 }
97 }
98 }
99 }
100 for (MachineInstr *MI : ToErase) {
101 Register Reg = MI->getOperand(2).getReg();
102 if (RegsAlreadyAddedToDT.contains(MI))
103 Reg = RegsAlreadyAddedToDT[MI];
104 auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg());
105 if (!MRI.getRegClassOrNull(Reg) && RC)
106 MRI.setRegClass(Reg, RC);
107 MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg);
108 MI->eraseFromParent();
109 }
110 for (MachineInstr *MI : ToEraseComposites)
111 MI->eraseFromParent();
112}
113
117 const unsigned AssignNameOperandShift = 2;
118 for (MachineBasicBlock &MBB : MF) {
119 for (MachineInstr &MI : MBB) {
120 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name))
121 continue;
122 unsigned NumOp = MI.getNumExplicitDefs() + AssignNameOperandShift;
123 while (MI.getOperand(NumOp).isReg()) {
124 MachineOperand &MOp = MI.getOperand(NumOp);
125 MachineInstr *ConstMI = MRI.getVRegDef(MOp.getReg());
126 assert(ConstMI->getOpcode() == TargetOpcode::G_CONSTANT);
127 MI.removeOperand(NumOp);
128 MI.addOperand(MachineOperand::CreateImm(
129 ConstMI->getOperand(1).getCImm()->getZExtValue()));
130 if (MRI.use_empty(ConstMI->getOperand(0).getReg()))
131 ToErase.push_back(ConstMI);
132 }
133 }
134 }
135 for (MachineInstr *MI : ToErase)
136 MI->eraseFromParent();
137}
138
140 MachineIRBuilder MIB) {
141 // Get access to information about available extensions
142 const SPIRVSubtarget *ST =
143 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
145 for (MachineBasicBlock &MBB : MF) {
146 for (MachineInstr &MI : MBB) {
147 if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast) &&
148 !isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
149 continue;
150 assert(MI.getOperand(2).isReg());
151 MIB.setInsertPt(*MI.getParent(), MI);
152 ToErase.push_back(&MI);
153 if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
154 MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());
155 continue;
156 }
157 Register Def = MI.getOperand(0).getReg();
158 Register Source = MI.getOperand(2).getReg();
160 getMDOperandAsType(MI.getOperand(3).getMetadata(), 0), MIB);
161 SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
163 addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST));
164
165 // If the bitcast would be redundant, replace all uses with the source
166 // register.
167 if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) {
168 MIB.getMRI()->replaceRegWith(Def, Source);
169 } else {
170 GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
171 MIB.buildBitcast(Def, Source);
172 }
173 }
174 }
175 for (MachineInstr *MI : ToErase)
176 MI->eraseFromParent();
177}
178
179// Translating GV, IRTranslator sometimes generates following IR:
180// %1 = G_GLOBAL_VALUE
181// %2 = COPY %1
182// %3 = G_ADDRSPACE_CAST %2
183//
184// or
185//
186// %1 = G_ZEXT %2
187// G_MEMCPY ... %2 ...
188//
189// New registers have no SPIRVType and no register class info.
190//
191// Set SPIRVType for GV, propagate it from GV to other instructions,
192// also set register classes.
195 MachineIRBuilder &MIB) {
196 SPIRVType *SpirvTy = nullptr;
197 assert(MI && "Machine instr is expected");
198 if (MI->getOperand(0).isReg()) {
199 Register Reg = MI->getOperand(0).getReg();
200 SpirvTy = GR->getSPIRVTypeForVReg(Reg);
201 if (!SpirvTy) {
202 switch (MI->getOpcode()) {
203 case TargetOpcode::G_CONSTANT: {
204 MIB.setInsertPt(*MI->getParent(), MI);
205 Type *Ty = MI->getOperand(1).getCImm()->getType();
206 SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);
207 break;
208 }
209 case TargetOpcode::G_GLOBAL_VALUE: {
210 MIB.setInsertPt(*MI->getParent(), MI);
211 const GlobalValue *Global = MI->getOperand(1).getGlobal();
212 Type *ElementTy = GR->getDeducedGlobalValueType(Global);
213 auto *Ty = TypedPointerType::get(ElementTy,
214 Global->getType()->getAddressSpace());
215 SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);
216 break;
217 }
218 case TargetOpcode::G_ANYEXT:
219 case TargetOpcode::G_SEXT:
220 case TargetOpcode::G_ZEXT: {
221 if (MI->getOperand(1).isReg()) {
222 if (MachineInstr *DefInstr =
223 MRI.getVRegDef(MI->getOperand(1).getReg())) {
224 if (SPIRVType *Def = propagateSPIRVType(DefInstr, GR, MRI, MIB)) {
225 unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);
226 unsigned ExpectedBW =
227 std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);
228 unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);
229 SpirvTy = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);
230 if (NumElements > 1)
231 SpirvTy =
232 GR->getOrCreateSPIRVVectorType(SpirvTy, NumElements, MIB);
233 }
234 }
235 }
236 break;
237 }
238 case TargetOpcode::G_PTRTOINT:
239 SpirvTy = GR->getOrCreateSPIRVIntegerType(
240 MRI.getType(Reg).getScalarSizeInBits(), MIB);
241 break;
242 case TargetOpcode::G_TRUNC:
243 case TargetOpcode::G_ADDRSPACE_CAST:
244 case TargetOpcode::G_PTR_ADD:
245 case TargetOpcode::COPY: {
246 MachineOperand &Op = MI->getOperand(1);
247 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
248 if (Def)
249 SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB);
250 break;
251 }
252 default:
253 break;
254 }
255 if (SpirvTy)
256 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
257 if (!MRI.getRegClassOrNull(Reg))
258 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
259 }
260 }
261 return SpirvTy;
262}
263
264static std::pair<Register, unsigned>
266 const SPIRVGlobalRegistry &GR) {
267 if (!SpvType)
268 SpvType = GR.getSPIRVTypeForVReg(SrcReg);
269 assert(SpvType && "VReg is expected to have SPIRV type");
270 LLT SrcLLT = MRI.getType(SrcReg);
271 LLT NewT = LLT::scalar(32);
272 bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat;
273 bool IsVectorFloat =
274 SpvType->getOpcode() == SPIRV::OpTypeVector &&
275 GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() ==
276 SPIRV::OpTypeFloat;
277 IsFloat |= IsVectorFloat;
278 auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID;
279 auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass;
280 if (SrcLLT.isPointer()) {
281 unsigned PtrSz = GR.getPointerSize();
282 NewT = LLT::pointer(0, PtrSz);
283 bool IsVec = SrcLLT.isVector();
284 if (IsVec)
285 NewT = LLT::fixed_vector(2, NewT);
286 if (PtrSz == 64) {
287 if (IsVec) {
288 GetIdOp = SPIRV::GET_vpID64;
289 DstClass = &SPIRV::vpID64RegClass;
290 } else {
291 GetIdOp = SPIRV::GET_pID64;
292 DstClass = &SPIRV::pID64RegClass;
293 }
294 } else {
295 if (IsVec) {
296 GetIdOp = SPIRV::GET_vpID32;
297 DstClass = &SPIRV::vpID32RegClass;
298 } else {
299 GetIdOp = SPIRV::GET_pID32;
300 DstClass = &SPIRV::pID32RegClass;
301 }
302 }
303 } else if (SrcLLT.isVector()) {
304 NewT = LLT::fixed_vector(2, NewT);
305 if (IsFloat) {
306 GetIdOp = SPIRV::GET_vfID;
307 DstClass = &SPIRV::vfIDRegClass;
308 } else {
309 GetIdOp = SPIRV::GET_vID;
310 DstClass = &SPIRV::vIDRegClass;
311 }
312 }
313 Register IdReg = MRI.createGenericVirtualRegister(NewT);
314 MRI.setRegClass(IdReg, DstClass);
315 return {IdReg, GetIdOp};
316}
317
318// Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as
319// a dst of the definition, assign SPIRVType to both registers. If SpirvTy is
320// provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty.
321// It's used also in SPIRVBuiltins.cpp.
322// TODO: maybe move to SPIRVUtils.
323namespace llvm {
327 MachineInstr *Def = MRI.getVRegDef(Reg);
328 assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected.");
329 MIB.setInsertPt(*Def->getParent(),
330 (Def->getNextNode() ? Def->getNextNode()->getIterator()
331 : Def->getParent()->end()));
332 SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB);
333 Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg));
334 if (auto *RC = MRI.getRegClassOrNull(Reg)) {
335 MRI.setRegClass(NewReg, RC);
336 } else {
337 MRI.setRegClass(NewReg, &SPIRV::IDRegClass);
338 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
339 }
340 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
341 // This is to make it convenient for Legalizer to get the SPIRVType
342 // when processing the actual MI (i.e. not pseudo one).
343 GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF());
344 // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep
345 // the flags after instruction selection.
346 const uint32_t Flags = Def->getFlags();
347 MIB.buildInstr(SPIRV::ASSIGN_TYPE)
348 .addDef(Reg)
349 .addUse(NewReg)
350 .addUse(GR->getSPIRVTypeID(SpirvTy))
351 .setMIFlags(Flags);
352 Def->getOperand(0).setReg(NewReg);
353 return NewReg;
354}
355
358 assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg()));
359 MachineInstr &AssignTypeInst =
360 *(MRI.use_instr_begin(MI.getOperand(0).getReg()));
361 auto NewReg =
362 createNewIdReg(nullptr, MI.getOperand(0).getReg(), MRI, *GR).first;
363 AssignTypeInst.getOperand(1).setReg(NewReg);
364 MI.getOperand(0).setReg(NewReg);
365 MIB.setInsertPt(*MI.getParent(),
366 (MI.getNextNode() ? MI.getNextNode()->getIterator()
367 : MI.getParent()->end()));
368 for (auto &Op : MI.operands()) {
369 if (!Op.isReg() || Op.isDef())
370 continue;
371 auto IdOpInfo = createNewIdReg(nullptr, Op.getReg(), MRI, *GR);
372 MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg());
373 Op.setReg(IdOpInfo.first);
374 }
375}
376} // namespace llvm
377
378static void
381 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
382 // Get access to information about available extensions
383 const SPIRVSubtarget *ST =
384 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
385
388
389 for (MachineBasicBlock *MBB : post_order(&MF)) {
390 if (MBB->empty())
391 continue;
392
393 bool ReachedBegin = false;
394 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
395 !ReachedBegin;) {
396 MachineInstr &MI = *MII;
397
398 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
399 Register Reg = MI.getOperand(1).getReg();
400 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
402 getMDOperandAsType(MI.getOperand(2).getMetadata(), 0), MIB);
403 SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
405 addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));
406 MachineInstr *Def = MRI.getVRegDef(Reg);
407 assert(Def && "Expecting an instruction that defines the register");
408 // G_GLOBAL_VALUE already has type info.
409 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
410 insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,
411 MF.getRegInfo());
412 ToErase.push_back(&MI);
413 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
414 Register Reg = MI.getOperand(1).getReg();
415 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
416 MachineInstr *Def = MRI.getVRegDef(Reg);
417 assert(Def && "Expecting an instruction that defines the register");
418 // G_GLOBAL_VALUE already has type info.
419 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
420 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
421 ToErase.push_back(&MI);
422 } else if (MI.getOpcode() == TargetOpcode::G_CONSTANT ||
423 MI.getOpcode() == TargetOpcode::G_FCONSTANT ||
424 MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
425 // %rc = G_CONSTANT ty Val
426 // ===>
427 // %cty = OpType* ty
428 // %rctmp = G_CONSTANT ty Val
429 // %rc = ASSIGN_TYPE %rctmp, %cty
430 Register Reg = MI.getOperand(0).getReg();
431 if (MRI.hasOneUse(Reg)) {
432 MachineInstr &UseMI = *MRI.use_instr_begin(Reg);
433 if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) ||
434 isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name))
435 continue;
436 }
437 Type *Ty = nullptr;
438 if (MI.getOpcode() == TargetOpcode::G_CONSTANT) {
439 auto TargetExtIt = TargetExtConstTypes.find(&MI);
440 Ty = TargetExtIt == TargetExtConstTypes.end()
441 ? MI.getOperand(1).getCImm()->getType()
442 : TargetExtIt->second;
443 } else if (MI.getOpcode() == TargetOpcode::G_FCONSTANT) {
444 Ty = MI.getOperand(1).getFPImm()->getType();
445 } else {
446 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
447 Type *ElemTy = nullptr;
448 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
449 assert(ElemMI);
450
451 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT)
452 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
453 else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT)
454 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
455 else
456 llvm_unreachable("Unexpected opcode");
457 unsigned NumElts =
458 MI.getNumExplicitOperands() - MI.getNumExplicitDefs();
459 Ty = VectorType::get(ElemTy, NumElts, false);
460 }
461 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI);
462 } else if (MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
463 propagateSPIRVType(&MI, GR, MRI, MIB);
464 }
465
466 if (MII == Begin)
467 ReachedBegin = true;
468 else
469 --MII;
470 }
471 }
472 for (MachineInstr *MI : ToErase)
473 MI->eraseFromParent();
474
475 // Address the case when IRTranslator introduces instructions with new
476 // registers without SPIRVType associated.
477 for (MachineBasicBlock &MBB : MF) {
478 for (MachineInstr &MI : MBB) {
479 switch (MI.getOpcode()) {
480 case TargetOpcode::G_TRUNC:
481 case TargetOpcode::G_ANYEXT:
482 case TargetOpcode::G_SEXT:
483 case TargetOpcode::G_ZEXT:
484 case TargetOpcode::G_PTRTOINT:
485 case TargetOpcode::COPY:
486 case TargetOpcode::G_ADDRSPACE_CAST:
487 propagateSPIRVType(&MI, GR, MRI, MIB);
488 break;
489 }
490 }
491 }
492}
493
494// Defined in SPIRVLegalizerInfo.cpp.
495extern bool isTypeFoldingSupported(unsigned Opcode);
496
499 MachineIRBuilder MIB) {
501 for (MachineBasicBlock &MBB : MF) {
502 for (MachineInstr &MI : MBB) {
503 if (isTypeFoldingSupported(MI.getOpcode()))
504 processInstr(MI, MIB, MRI, GR);
505 }
506 }
507
508 for (MachineBasicBlock &MBB : MF) {
509 for (MachineInstr &MI : MBB) {
510 // We need to rewrite dst types for ASSIGN_TYPE instrs to be able
511 // to perform tblgen'erated selection and we can't do that on Legalizer
512 // as it operates on gMIR only.
513 if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)
514 continue;
515 Register SrcReg = MI.getOperand(1).getReg();
516 unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode();
517 if (!isTypeFoldingSupported(Opcode))
518 continue;
519 Register DstReg = MI.getOperand(0).getReg();
520 bool IsDstPtr = MRI.getType(DstReg).isPointer();
521 bool isDstVec = MRI.getType(DstReg).isVector();
522 if (IsDstPtr || isDstVec)
523 MRI.setRegClass(DstReg, &SPIRV::IDRegClass);
524 // Don't need to reset type of register holding constant and used in
525 // G_ADDRSPACE_CAST, since it breaks legalizer.
526 if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) {
527 MachineInstr &UseMI = *MRI.use_instr_begin(DstReg);
528 if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST)
529 continue;
530 }
531 MRI.setType(DstReg, IsDstPtr ? LLT::pointer(0, GR->getPointerSize())
532 : LLT::scalar(32));
533 }
534 }
535}
536
537static void
539 const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder,
540 const SmallVector<MachineInstr *> &ToProcess) {
542 Register AsmTargetReg;
543 for (unsigned i = 0, Sz = ToProcess.size(); i + 1 < Sz; i += 2) {
544 MachineInstr *I1 = ToProcess[i], *I2 = ToProcess[i + 1];
545 assert(isSpvIntrinsic(*I1, Intrinsic::spv_inline_asm) && I2->isInlineAsm());
546 MIRBuilder.setInsertPt(*I1->getParent(), *I1);
547
548 if (!AsmTargetReg.isValid()) {
549 // define vendor specific assembly target or dialect
550 AsmTargetReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
551 MRI.setRegClass(AsmTargetReg, &SPIRV::IDRegClass);
552 auto AsmTargetMIB =
553 MIRBuilder.buildInstr(SPIRV::OpAsmTargetINTEL).addDef(AsmTargetReg);
554 addStringImm(ST.getTargetTripleAsStr(), AsmTargetMIB);
555 GR->add(AsmTargetMIB.getInstr(), &MF, AsmTargetReg);
556 }
557
558 // create types
559 const MDNode *IAMD = I1->getOperand(1).getMetadata();
560 FunctionType *FTy = cast<FunctionType>(getMDOperandAsType(IAMD, 0));
562 for (const auto &ArgTy : FTy->params())
563 ArgTypes.push_back(GR->getOrCreateSPIRVType(ArgTy, MIRBuilder));
564 SPIRVType *RetType =
565 GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder);
567 FTy, RetType, ArgTypes, MIRBuilder);
568
569 // define vendor specific assembly instructions string
570 Register AsmReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
571 MRI.setRegClass(AsmReg, &SPIRV::IDRegClass);
572 auto AsmMIB = MIRBuilder.buildInstr(SPIRV::OpAsmINTEL)
573 .addDef(AsmReg)
574 .addUse(GR->getSPIRVTypeID(RetType))
575 .addUse(GR->getSPIRVTypeID(FuncType))
576 .addUse(AsmTargetReg);
577 // inline asm string:
578 addStringImm(I2->getOperand(InlineAsm::MIOp_AsmString).getSymbolName(),
579 AsmMIB);
580 // inline asm constraint string:
581 addStringImm(cast<MDString>(I1->getOperand(2).getMetadata()->getOperand(0))
582 ->getString(),
583 AsmMIB);
584 GR->add(AsmMIB.getInstr(), &MF, AsmReg);
585
586 // calls the inline assembly instruction
587 unsigned ExtraInfo = I2->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
588 if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
589 MIRBuilder.buildInstr(SPIRV::OpDecorate)
590 .addUse(AsmReg)
591 .addImm(static_cast<uint32_t>(SPIRV::Decoration::SideEffectsINTEL));
592 Register DefReg;
594 unsigned StartOp = InlineAsm::MIOp_FirstOperand,
596 unsigned I2Sz = I2->getNumOperands();
597 for (unsigned Idx = StartOp; Idx != I2Sz; ++Idx) {
598 const MachineOperand &MO = I2->getOperand(Idx);
599 if (MO.isMetadata())
600 continue;
601 if (Idx == AsmDescOp && MO.isImm()) {
602 // compute the index of the next operand descriptor
603 const InlineAsm::Flag F(MO.getImm());
604 AsmDescOp += 1 + F.getNumOperandRegisters();
605 } else {
606 if (MO.isReg() && MO.isDef())
607 DefReg = MO.getReg();
608 else
609 Ops.push_back(Idx);
610 }
611 }
612 if (!DefReg.isValid()) {
613 DefReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
614 MRI.setRegClass(DefReg, &SPIRV::IDRegClass);
615 SPIRVType *VoidType = GR->getOrCreateSPIRVType(
616 Type::getVoidTy(MF.getFunction().getContext()), MIRBuilder);
617 GR->assignSPIRVTypeToVReg(VoidType, DefReg, MF);
618 }
619 auto AsmCall = MIRBuilder.buildInstr(SPIRV::OpAsmCallINTEL)
620 .addDef(DefReg)
621 .addUse(GR->getSPIRVTypeID(RetType))
622 .addUse(AsmReg);
623 unsigned IntrIdx = 2;
624 for (unsigned Idx : Ops) {
625 ++IntrIdx;
626 const MachineOperand &MO = I2->getOperand(Idx);
627 if (MO.isReg())
628 AsmCall.addUse(MO.getReg());
629 else
630 AsmCall.addUse(I1->getOperand(IntrIdx).getReg());
631 }
632 }
633 for (MachineInstr *MI : ToProcess)
634 MI->eraseFromParent();
635}
636
638 const SPIRVSubtarget &ST,
639 MachineIRBuilder MIRBuilder) {
641 for (MachineBasicBlock &MBB : MF) {
642 for (MachineInstr &MI : MBB) {
643 if (isSpvIntrinsic(MI, Intrinsic::spv_inline_asm) ||
644 MI.getOpcode() == TargetOpcode::INLINEASM)
645 ToProcess.push_back(&MI);
646 }
647 }
648 if (ToProcess.size() == 0)
649 return;
650
651 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly))
652 report_fatal_error("Inline assembly instructions require the "
653 "following SPIR-V extension: SPV_INTEL_inline_assembly",
654 false);
655
656 insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess);
657}
658
661 for (MachineBasicBlock &MBB : MF) {
662 for (MachineInstr &MI : MBB) {
663 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration))
664 continue;
665 MIB.setInsertPt(*MI.getParent(), MI);
666 buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
667 MI.getOperand(2).getMetadata());
668 ToErase.push_back(&MI);
669 }
670 }
671 for (MachineInstr *MI : ToErase)
672 MI->eraseFromParent();
673}
674
675// Find basic blocks of the switch and replace registers in spv_switch() by its
676// MBB equivalent.
678 MachineIRBuilder MIB) {
681 Switches;
682 for (MachineBasicBlock &MBB : MF) {
684 BB2MBB[MBB.getBasicBlock()] = &MBB;
685 for (MachineInstr &MI : MBB) {
686 if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))
687 continue;
688 // Calls to spv_switch intrinsics representing IR switches.
690 for (unsigned i = 2; i < MI.getNumOperands(); ++i) {
691 Register Reg = MI.getOperand(i).getReg();
692 if (i % 2 == 1) {
693 MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI);
694 NewOps.push_back(ConstInstr);
695 } else {
696 MachineInstr *BuildMBB = MRI.getVRegDef(Reg);
697 assert(BuildMBB &&
698 BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&
699 BuildMBB->getOperand(1).isBlockAddress() &&
700 BuildMBB->getOperand(1).getBlockAddress());
701 NewOps.push_back(BuildMBB);
702 }
703 }
704 Switches.push_back(std::make_pair(&MI, NewOps));
705 }
706 }
707
709 for (auto &SwIt : Switches) {
710 MachineInstr &MI = *SwIt.first;
711 SmallVector<MachineInstr *, 8> &Ins = SwIt.second;
713 for (unsigned i = 0; i < Ins.size(); ++i) {
714 if (Ins[i]->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
715 BasicBlock *CaseBB =
716 Ins[i]->getOperand(1).getBlockAddress()->getBasicBlock();
717 auto It = BB2MBB.find(CaseBB);
718 if (It == BB2MBB.end())
719 report_fatal_error("cannot find a machine basic block by a basic "
720 "block in a switch statement");
721 NewOps.push_back(MachineOperand::CreateMBB(It->second));
722 MI.getParent()->addSuccessor(It->second);
723 ToEraseMI.insert(Ins[i]);
724 } else {
725 NewOps.push_back(
726 MachineOperand::CreateCImm(Ins[i]->getOperand(1).getCImm()));
727 }
728 }
729 for (unsigned i = MI.getNumOperands() - 1; i > 1; --i)
730 MI.removeOperand(i);
731 for (auto &MO : NewOps)
732 MI.addOperand(MO);
733 if (MachineInstr *Next = MI.getNextNode()) {
734 if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {
735 ToEraseMI.insert(Next);
736 Next = MI.getNextNode();
737 }
738 if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)
739 ToEraseMI.insert(Next);
740 }
741 }
742
743 // If we just delete G_BLOCK_ADDR instructions with BlockAddress operands,
744 // this leaves their BasicBlock counterparts in a "address taken" status. This
745 // would make AsmPrinter to generate a series of unneeded labels of a "Address
746 // of block that was removed by CodeGen" kind. Let's first ensure that we
747 // don't have a dangling BlockAddress constants by zapping the BlockAddress
748 // nodes, and only after that proceed with erasing G_BLOCK_ADDR instructions.
749 Constant *Replacement =
750 ConstantInt::get(Type::getInt32Ty(MF.getFunction().getContext()), 1);
751 for (MachineInstr *BlockAddrI : ToEraseMI) {
752 if (BlockAddrI->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
753 BlockAddress *BA = const_cast<BlockAddress *>(
754 BlockAddrI->getOperand(1).getBlockAddress());
756 ConstantExpr::getIntToPtr(Replacement, BA->getType()));
757 BA->destroyConstant();
758 }
759 BlockAddrI->eraseFromParent();
760 }
761}
762
764 if (MBB.empty())
765 return true;
766
767 // Branching SPIR-V intrinsics are not detected by this generic method.
768 // Thus, we can only trust negative result.
769 if (!MBB.canFallThrough())
770 return false;
771
772 // Otherwise, we must manually check if we have a SPIR-V intrinsic which
773 // prevent an implicit fallthrough.
775 It != E; ++It) {
776 if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
777 return false;
778 }
779 return true;
780}
781
783 MachineIRBuilder MIB) {
784 // It is valid for MachineBasicBlocks to not finish with a branch instruction.
785 // In such cases, they will simply fallthrough their immediate successor.
786 for (MachineBasicBlock &MBB : MF) {
788 continue;
789
790 assert(std::distance(MBB.successors().begin(), MBB.successors().end()) ==
791 1);
792 MIB.setInsertPt(MBB, MBB.end());
793 MIB.buildBr(**MBB.successors().begin());
794 }
795}
796
797bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
798 // Initialize the type registry.
800 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
801 GR->setCurrentFunc(MF);
802 MachineIRBuilder MIB(MF);
803 // a registry of target extension constants
804 DenseMap<MachineInstr *, Type *> TargetExtConstTypes;
805 addConstantsToTrack(MF, GR, TargetExtConstTypes);
807 insertBitcasts(MF, GR, MIB);
808 generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes);
809 processSwitches(MF, GR, MIB);
810 processInstrsWithTypeFolding(MF, GR, MIB);
812 insertSpirvDecorations(MF, MIB);
813 insertInlineAsm(MF, GR, ST, MIB);
814
815 return true;
816}
817
818INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,
819 false)
820
821char SPIRVPreLegalizer::ID = 0;
822
824 return new SPIRVPreLegalizer();
825}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineBasicBlock & MBB
This file contains the simple types necessary to represent the attributes associated with functions a...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition: MD5.cpp:55
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static void insertInlineAsm(MachineFunction &MF, SPIRVGlobalRegistry *GR, const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder)
static void insertInlineAsmProcess(MachineFunction &MF, SPIRVGlobalRegistry *GR, const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder, const SmallVector< MachineInstr * > &ToProcess)
static void removeImplicitFallthroughs(MachineFunction &MF, MachineIRBuilder MIB)
static bool isImplicitFallthrough(MachineBasicBlock &MBB)
bool isTypeFoldingSupported(unsigned Opcode)
static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void processInstrsWithTypeFolding(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static SPIRVType * propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI, MachineIRBuilder &MIB)
static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
#define DEBUG_TYPE
static void insertSpirvDecorations(MachineFunction &MF, MachineIRBuilder MIB)
static std::pair< Register, unsigned > createNewIdReg(SPIRVType *SpvType, Register SrcReg, MachineRegisterInfo &MRI, const SPIRVGlobalRegistry &GR)
static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB, DenseMap< MachineInstr *, Type * > &TargetExtConstTypes)
static void addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR, DenseMap< MachineInstr *, Type * > &TargetExtConstTypes)
static void foldConstantsIntoIntrinsics(MachineFunction &MF)
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
Definition: VPlanSLP.cpp:191
LLVM Basic Block Representation.
Definition: BasicBlock.h:60
The address of a basic block.
Definition: Constants.h:890
static Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
Definition: Constants.cpp:2126
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition: Constants.h:155
This is an important base class in LLVM.
Definition: Constant.h:41
void destroyConstant()
Called if some element of this constant is no longer valid.
Definition: Constants.cpp:472
This class represents an Operation in the Expression.
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:155
iterator end()
Definition: DenseMap.h:84
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition: DenseMap.h:145
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:356
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelType.h:42
constexpr bool isVector() const
Definition: LowLevelType.h:148
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
Definition: LowLevelType.h:57
constexpr bool isPointer() const
Definition: LowLevelType.h:149
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
Definition: LowLevelType.h:100
Metadata node.
Definition: Metadata.h:1067
reverse_iterator rend()
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
bool canFallThrough()
Return true if the block can implicitly transfer control to the block after it by falling off the end...
iterator_range< succ_iterator > successors()
reverse_iterator rbegin()
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
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.
Function & getFunction()
Return the LLVM function that this machine code represents.
Helper class to build MachineInstr.
MachineInstrBuilder buildBr(MachineBasicBlock &Dest)
Build and insert G_BR Dest.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
MachineRegisterInfo * getMRI()
Getter for MRI.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
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.
MachineBasicBlock iterator that automatically skips over MIs that are inside bundles (i....
Representation of each machine instruction.
Definition: MachineInstr.h:69
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:564
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:574
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
static MachineOperand CreateCImm(const ConstantInt *CI)
void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
bool isMetadata() const
isMetadata - Tests if this is a MO_Metadata operand.
const BlockAddress * getBlockAddress() const
static MachineOperand CreateImm(int64_t Val)
bool isBlockAddress() const
isBlockAddress - Tests if this is a MO_BlockAddress operand.
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
static MachineOperand CreateMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
constexpr bool isValid() const
Definition: Register.h:116
SPIRVType * getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
void add(const Constant *C, MachineFunction *MF, Register R)
unsigned getScalarOrVectorComponentCount(Register VReg) const
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
SPIRVType * getOrCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, SPIRV::AccessQualifier::AccessQualifier AQ=SPIRV::AccessQualifier::ReadWrite, bool EmitIR=true)
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, MachineFunction &MF)
SPIRVType * getOrCreateOpTypeFunctionWithArgs(const Type *Ty, SPIRVType *RetType, const SmallVectorImpl< SPIRVType * > &ArgTypes, MachineIRBuilder &MIRBuilder)
Register find(const MachineInstr *MI, MachineFunction *MF)
SPIRVType * getOrCreateSPIRVPointerType(SPIRVType *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SClass=SPIRV::StorageClass::Function)
SPIRVType * getOrCreateSPIRVVectorType(SPIRVType *BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder)
SPIRVType * getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
Type * getDeducedGlobalValueType(const GlobalValue *Global)
unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const
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.
Definition: SmallPtrSet.h:342
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:427
size_t size() const
Definition: SmallVector.h:91
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static Type * getVoidTy(LLVMContext &C)
static IntegerType * getInt32Ty(LLVMContext &C)
static TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:534
#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
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
FunctionPass * createSPIRVPreLegalizerPass()
Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Helper external function for inserting ASSIGN_TYPE instuction between Reg and its definition,...
iterator_range< po_iterator< T > > post_order(const T &G)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:159
@ Global
Append to llvm.global_dtors.
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
Definition: SPIRVUtils.cpp:190
void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR)
MachineInstr * getDefInstrMaybeConstant(Register &ConstReg, const MachineRegisterInfo *MRI)
Definition: SPIRVUtils.cpp:254
Type * getMDOperandAsType(const MDNode *N, unsigned I)
Definition: SPIRVUtils.cpp:281
void initializeSPIRVPreLegalizerPass(PassRegistry &)
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
Definition: SPIRVUtils.cpp:275
void addStringImm(const StringRef &Str, MCInst &Inst)
Definition: SPIRVUtils.cpp:51
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, const MDNode *GVarMD)
Definition: SPIRVUtils.cpp:136