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 const SPIRVSubtarget &STI,
44 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes,
45 SmallSet<Register, 4> &TrackedConstRegs) {
47 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
48 SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites;
49 for (MachineBasicBlock &MBB : MF) {
50 for (MachineInstr &MI : MBB) {
51 if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant))
52 continue;
53 ToErase.push_back(&MI);
54 Register SrcReg = MI.getOperand(2).getReg();
55 auto *Const =
56 cast<Constant>(cast<ConstantAsMetadata>(
57 MI.getOperand(3).getMetadata()->getOperand(0))
58 ->getValue());
59 if (auto *GV = dyn_cast<GlobalValue>(Const)) {
60 Register Reg = GR->find(GV, &MF);
61 if (!Reg.isValid())
62 GR->add(GV, &MF, SrcReg);
63 else
64 RegsAlreadyAddedToDT[&MI] = Reg;
65 } else {
66 Register Reg = GR->find(Const, &MF);
67 if (!Reg.isValid()) {
68 if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) {
69 auto *BuildVec = MRI.getVRegDef(SrcReg);
70 assert(BuildVec &&
71 BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
72 for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) {
73 // Ensure that OpConstantComposite reuses a constant when it's
74 // already created and available in the same machine function.
75 Constant *ElemConst = ConstVec->getElementAsConstant(i);
76 Register ElemReg = GR->find(ElemConst, &MF);
77 if (!ElemReg.isValid())
78 GR->add(ElemConst, &MF, BuildVec->getOperand(1 + i).getReg());
79 else
80 BuildVec->getOperand(1 + i).setReg(ElemReg);
81 }
82 }
83 GR->add(Const, &MF, SrcReg);
84 TrackedConstRegs.insert(SrcReg);
85 if (Const->getType()->isTargetExtTy()) {
86 // remember association so that we can restore it when assign types
87 MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);
88 if (SrcMI && (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT ||
89 SrcMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF))
90 TargetExtConstTypes[SrcMI] = Const->getType();
91 if (Const->isNullValue()) {
92 MachineIRBuilder MIB(MF);
93 SPIRVType *ExtType =
94 GR->getOrCreateSPIRVType(Const->getType(), MIB);
95 SrcMI->setDesc(STI.getInstrInfo()->get(SPIRV::OpConstantNull));
97 GR->getSPIRVTypeID(ExtType), false));
98 }
99 }
100 } else {
101 RegsAlreadyAddedToDT[&MI] = Reg;
102 // This MI is unused and will be removed. If the MI uses
103 // const_composite, it will be unused and should be removed too.
104 assert(MI.getOperand(2).isReg() && "Reg operand is expected");
105 MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg());
106 if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))
107 ToEraseComposites.push_back(SrcMI);
108 }
109 }
110 }
111 }
112 for (MachineInstr *MI : ToErase) {
113 Register Reg = MI->getOperand(2).getReg();
114 if (RegsAlreadyAddedToDT.contains(MI))
115 Reg = RegsAlreadyAddedToDT[MI];
116 auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg());
117 if (!MRI.getRegClassOrNull(Reg) && RC)
118 MRI.setRegClass(Reg, RC);
119 MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg);
120 MI->eraseFromParent();
121 }
122 for (MachineInstr *MI : ToEraseComposites)
123 MI->eraseFromParent();
124}
125
126static void
128 const SmallSet<Register, 4> &TrackedConstRegs) {
131 const unsigned AssignNameOperandShift = 2;
132 for (MachineBasicBlock &MBB : MF) {
133 for (MachineInstr &MI : MBB) {
134 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name))
135 continue;
136 unsigned NumOp = MI.getNumExplicitDefs() + AssignNameOperandShift;
137 while (MI.getOperand(NumOp).isReg()) {
138 MachineOperand &MOp = MI.getOperand(NumOp);
139 MachineInstr *ConstMI = MRI.getVRegDef(MOp.getReg());
140 assert(ConstMI->getOpcode() == TargetOpcode::G_CONSTANT);
141 MI.removeOperand(NumOp);
142 MI.addOperand(MachineOperand::CreateImm(
143 ConstMI->getOperand(1).getCImm()->getZExtValue()));
144 Register DefReg = ConstMI->getOperand(0).getReg();
145 if (MRI.use_empty(DefReg) && !TrackedConstRegs.contains(DefReg))
146 ToErase.push_back(ConstMI);
147 }
148 }
149 }
150 for (MachineInstr *MI : ToErase)
151 MI->eraseFromParent();
152}
153
155 MachineIRBuilder MIB) {
156 // Get access to information about available extensions
157 const SPIRVSubtarget *ST =
158 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
160 for (MachineBasicBlock &MBB : MF) {
161 for (MachineInstr &MI : MBB) {
162 if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast) &&
163 !isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
164 continue;
165 assert(MI.getOperand(2).isReg());
166 MIB.setInsertPt(*MI.getParent(), MI);
167 ToErase.push_back(&MI);
168 if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
169 MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());
170 continue;
171 }
172 Register Def = MI.getOperand(0).getReg();
173 Register Source = MI.getOperand(2).getReg();
174 Type *ElemTy = getMDOperandAsType(MI.getOperand(3).getMetadata(), 0);
175 SPIRVType *BaseTy = GR->getOrCreateSPIRVType(ElemTy, MIB);
176 SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
178 addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST));
179
180 // If the bitcast would be redundant, replace all uses with the source
181 // register.
182 if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) {
183 MIB.getMRI()->replaceRegWith(Def, Source);
184 } else {
185 GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
186 MIB.buildBitcast(Def, Source);
187 }
188 }
189 }
190 for (MachineInstr *MI : ToErase)
191 MI->eraseFromParent();
192}
193
194// Translating GV, IRTranslator sometimes generates following IR:
195// %1 = G_GLOBAL_VALUE
196// %2 = COPY %1
197// %3 = G_ADDRSPACE_CAST %2
198//
199// or
200//
201// %1 = G_ZEXT %2
202// G_MEMCPY ... %2 ...
203//
204// New registers have no SPIRVType and no register class info.
205//
206// Set SPIRVType for GV, propagate it from GV to other instructions,
207// also set register classes.
210 MachineIRBuilder &MIB) {
211 SPIRVType *SpirvTy = nullptr;
212 assert(MI && "Machine instr is expected");
213 if (MI->getOperand(0).isReg()) {
214 Register Reg = MI->getOperand(0).getReg();
215 SpirvTy = GR->getSPIRVTypeForVReg(Reg);
216 if (!SpirvTy) {
217 switch (MI->getOpcode()) {
218 case TargetOpcode::G_CONSTANT: {
219 MIB.setInsertPt(*MI->getParent(), MI);
220 Type *Ty = MI->getOperand(1).getCImm()->getType();
221 SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);
222 break;
223 }
224 case TargetOpcode::G_GLOBAL_VALUE: {
225 MIB.setInsertPt(*MI->getParent(), MI);
226 const GlobalValue *Global = MI->getOperand(1).getGlobal();
227 Type *ElementTy = GR->getDeducedGlobalValueType(Global);
228 auto *Ty = TypedPointerType::get(toTypedPointer(ElementTy),
229 Global->getType()->getAddressSpace());
230 SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);
231 break;
232 }
233 case TargetOpcode::G_ANYEXT:
234 case TargetOpcode::G_SEXT:
235 case TargetOpcode::G_ZEXT: {
236 if (MI->getOperand(1).isReg()) {
237 if (MachineInstr *DefInstr =
238 MRI.getVRegDef(MI->getOperand(1).getReg())) {
239 if (SPIRVType *Def = propagateSPIRVType(DefInstr, GR, MRI, MIB)) {
240 unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);
241 unsigned ExpectedBW =
242 std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);
243 unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);
244 SpirvTy = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);
245 if (NumElements > 1)
246 SpirvTy =
247 GR->getOrCreateSPIRVVectorType(SpirvTy, NumElements, MIB);
248 }
249 }
250 }
251 break;
252 }
253 case TargetOpcode::G_PTRTOINT:
254 SpirvTy = GR->getOrCreateSPIRVIntegerType(
255 MRI.getType(Reg).getScalarSizeInBits(), MIB);
256 break;
257 case TargetOpcode::G_TRUNC:
258 case TargetOpcode::G_ADDRSPACE_CAST:
259 case TargetOpcode::G_PTR_ADD:
260 case TargetOpcode::COPY: {
261 MachineOperand &Op = MI->getOperand(1);
262 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
263 if (Def)
264 SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB);
265 break;
266 }
267 default:
268 break;
269 }
270 if (SpirvTy)
271 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
272 if (!MRI.getRegClassOrNull(Reg))
273 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
274 }
275 }
276 return SpirvTy;
277}
278
279// To support current approach and limitations wrt. bit width here we widen a
280// scalar register with a bit width greater than 1 to valid sizes and cap it to
281// 64 width.
283 LLT RegType = MRI.getType(Reg);
284 if (!RegType.isScalar())
285 return;
286 unsigned Sz = RegType.getScalarSizeInBits();
287 if (Sz == 1)
288 return;
289 unsigned NewSz = std::min(std::max(1u << Log2_32_Ceil(Sz), 8u), 64u);
290 if (NewSz != Sz)
291 MRI.setType(Reg, LLT::scalar(NewSz));
292}
293
294static std::pair<Register, unsigned>
296 const SPIRVGlobalRegistry &GR) {
297 if (!SpvType)
298 SpvType = GR.getSPIRVTypeForVReg(SrcReg);
299 assert(SpvType && "VReg is expected to have SPIRV type");
300 LLT SrcLLT = MRI.getType(SrcReg);
301 LLT NewT = LLT::scalar(32);
302 bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat;
303 bool IsVectorFloat =
304 SpvType->getOpcode() == SPIRV::OpTypeVector &&
305 GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() ==
306 SPIRV::OpTypeFloat;
307 IsFloat |= IsVectorFloat;
308 auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID;
309 auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass;
310 if (SrcLLT.isPointer()) {
311 unsigned PtrSz = GR.getPointerSize();
312 NewT = LLT::pointer(0, PtrSz);
313 bool IsVec = SrcLLT.isVector();
314 if (IsVec)
315 NewT = LLT::fixed_vector(2, NewT);
316 if (PtrSz == 64) {
317 if (IsVec) {
318 GetIdOp = SPIRV::GET_vpID64;
319 DstClass = &SPIRV::vpID64RegClass;
320 } else {
321 GetIdOp = SPIRV::GET_pID64;
322 DstClass = &SPIRV::pID64RegClass;
323 }
324 } else {
325 if (IsVec) {
326 GetIdOp = SPIRV::GET_vpID32;
327 DstClass = &SPIRV::vpID32RegClass;
328 } else {
329 GetIdOp = SPIRV::GET_pID32;
330 DstClass = &SPIRV::pID32RegClass;
331 }
332 }
333 } else if (SrcLLT.isVector()) {
334 NewT = LLT::fixed_vector(2, NewT);
335 if (IsFloat) {
336 GetIdOp = SPIRV::GET_vfID;
337 DstClass = &SPIRV::vfIDRegClass;
338 } else {
339 GetIdOp = SPIRV::GET_vID;
340 DstClass = &SPIRV::vIDRegClass;
341 }
342 }
343 Register IdReg = MRI.createGenericVirtualRegister(NewT);
344 MRI.setRegClass(IdReg, DstClass);
345 return {IdReg, GetIdOp};
346}
347
348// Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as
349// a dst of the definition, assign SPIRVType to both registers. If SpirvTy is
350// provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty.
351// It's used also in SPIRVBuiltins.cpp.
352// TODO: maybe move to SPIRVUtils.
353namespace llvm {
357 MachineInstr *Def = MRI.getVRegDef(Reg);
358 assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected.");
359 MIB.setInsertPt(*Def->getParent(),
360 (Def->getNextNode() ? Def->getNextNode()->getIterator()
361 : Def->getParent()->end()));
362 SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB);
363 Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg));
364 if (auto *RC = MRI.getRegClassOrNull(Reg)) {
365 MRI.setRegClass(NewReg, RC);
366 } else {
367 MRI.setRegClass(NewReg, &SPIRV::IDRegClass);
368 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
369 }
370 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
371 // This is to make it convenient for Legalizer to get the SPIRVType
372 // when processing the actual MI (i.e. not pseudo one).
373 GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF());
374 // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep
375 // the flags after instruction selection.
376 const uint32_t Flags = Def->getFlags();
377 MIB.buildInstr(SPIRV::ASSIGN_TYPE)
378 .addDef(Reg)
379 .addUse(NewReg)
380 .addUse(GR->getSPIRVTypeID(SpirvTy))
381 .setMIFlags(Flags);
382 Def->getOperand(0).setReg(NewReg);
383 return NewReg;
384}
385
388 assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg()));
389 MachineInstr &AssignTypeInst =
390 *(MRI.use_instr_begin(MI.getOperand(0).getReg()));
391 auto NewReg =
392 createNewIdReg(nullptr, MI.getOperand(0).getReg(), MRI, *GR).first;
393 AssignTypeInst.getOperand(1).setReg(NewReg);
394 MI.getOperand(0).setReg(NewReg);
395 MIB.setInsertPt(*MI.getParent(),
396 (MI.getNextNode() ? MI.getNextNode()->getIterator()
397 : MI.getParent()->end()));
398 for (auto &Op : MI.operands()) {
399 if (!Op.isReg() || Op.isDef())
400 continue;
401 auto IdOpInfo = createNewIdReg(nullptr, Op.getReg(), MRI, *GR);
402 MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg());
403 Op.setReg(IdOpInfo.first);
404 }
405}
406} // namespace llvm
407
408static void
411 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
412 // Get access to information about available extensions
413 const SPIRVSubtarget *ST =
414 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
415
418 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
419
420 for (MachineBasicBlock *MBB : post_order(&MF)) {
421 if (MBB->empty())
422 continue;
423
424 bool ReachedBegin = false;
425 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
426 !ReachedBegin;) {
427 MachineInstr &MI = *MII;
428 unsigned MIOp = MI.getOpcode();
429
430 // validate bit width of scalar registers
431 for (const auto &MOP : MI.operands())
432 if (MOP.isReg())
433 widenScalarLLTNextPow2(MOP.getReg(), MRI);
434
435 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
436 Register Reg = MI.getOperand(1).getReg();
437 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
438 Type *ElementTy = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
439 SPIRVType *BaseTy = GR->getOrCreateSPIRVType(ElementTy, MIB);
440 SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
442 addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));
443 MachineInstr *Def = MRI.getVRegDef(Reg);
444 assert(Def && "Expecting an instruction that defines the register");
445 // G_GLOBAL_VALUE already has type info.
446 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE &&
447 Def->getOpcode() != SPIRV::ASSIGN_TYPE)
448 insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,
449 MF.getRegInfo());
450 ToErase.push_back(&MI);
451 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
452 Register Reg = MI.getOperand(1).getReg();
453 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
454 MachineInstr *Def = MRI.getVRegDef(Reg);
455 assert(Def && "Expecting an instruction that defines the register");
456 // G_GLOBAL_VALUE already has type info.
457 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE &&
458 Def->getOpcode() != SPIRV::ASSIGN_TYPE)
459 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
460 ToErase.push_back(&MI);
461 } else if (MIOp == TargetOpcode::G_CONSTANT ||
462 MIOp == TargetOpcode::G_FCONSTANT ||
463 MIOp == TargetOpcode::G_BUILD_VECTOR) {
464 // %rc = G_CONSTANT ty Val
465 // ===>
466 // %cty = OpType* ty
467 // %rctmp = G_CONSTANT ty Val
468 // %rc = ASSIGN_TYPE %rctmp, %cty
469 Register Reg = MI.getOperand(0).getReg();
470 bool NeedAssignType = true;
471 if (MRI.hasOneUse(Reg)) {
472 MachineInstr &UseMI = *MRI.use_instr_begin(Reg);
473 if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) ||
474 isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name))
475 continue;
476 }
477 Type *Ty = nullptr;
478 if (MIOp == TargetOpcode::G_CONSTANT) {
479 auto TargetExtIt = TargetExtConstTypes.find(&MI);
480 Ty = TargetExtIt == TargetExtConstTypes.end()
481 ? MI.getOperand(1).getCImm()->getType()
482 : TargetExtIt->second;
483 const ConstantInt *OpCI = MI.getOperand(1).getCImm();
484 Register PrimaryReg = GR->find(OpCI, &MF);
485 if (!PrimaryReg.isValid()) {
486 GR->add(OpCI, &MF, Reg);
487 } else if (PrimaryReg != Reg &&
488 MRI.getType(Reg) == MRI.getType(PrimaryReg)) {
489 auto *RCReg = MRI.getRegClassOrNull(Reg);
490 auto *RCPrimary = MRI.getRegClassOrNull(PrimaryReg);
491 if (!RCReg || RCPrimary == RCReg) {
492 RegsAlreadyAddedToDT[&MI] = PrimaryReg;
493 ToErase.push_back(&MI);
494 NeedAssignType = false;
495 }
496 }
497 } else if (MIOp == TargetOpcode::G_FCONSTANT) {
498 Ty = MI.getOperand(1).getFPImm()->getType();
499 } else {
500 assert(MIOp == TargetOpcode::G_BUILD_VECTOR);
501 Type *ElemTy = nullptr;
502 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
503 assert(ElemMI);
504
505 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT)
506 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
507 else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT)
508 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
509 else
510 llvm_unreachable("Unexpected opcode");
511 unsigned NumElts =
512 MI.getNumExplicitOperands() - MI.getNumExplicitDefs();
513 Ty = VectorType::get(ElemTy, NumElts, false);
514 }
515 if (NeedAssignType)
516 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI);
517 } else if (MIOp == TargetOpcode::G_GLOBAL_VALUE) {
518 propagateSPIRVType(&MI, GR, MRI, MIB);
519 }
520
521 if (MII == Begin)
522 ReachedBegin = true;
523 else
524 --MII;
525 }
526 }
527 for (MachineInstr *MI : ToErase) {
528 auto It = RegsAlreadyAddedToDT.find(MI);
529 if (RegsAlreadyAddedToDT.contains(MI))
530 MRI.replaceRegWith(MI->getOperand(0).getReg(), It->second);
531 MI->eraseFromParent();
532 }
533
534 // Address the case when IRTranslator introduces instructions with new
535 // registers without SPIRVType associated.
536 for (MachineBasicBlock &MBB : MF) {
537 for (MachineInstr &MI : MBB) {
538 switch (MI.getOpcode()) {
539 case TargetOpcode::G_TRUNC:
540 case TargetOpcode::G_ANYEXT:
541 case TargetOpcode::G_SEXT:
542 case TargetOpcode::G_ZEXT:
543 case TargetOpcode::G_PTRTOINT:
544 case TargetOpcode::COPY:
545 case TargetOpcode::G_ADDRSPACE_CAST:
546 propagateSPIRVType(&MI, GR, MRI, MIB);
547 break;
548 }
549 }
550 }
551}
552
553// Defined in SPIRVLegalizerInfo.cpp.
554extern bool isTypeFoldingSupported(unsigned Opcode);
555
558 MachineIRBuilder MIB) {
560 for (MachineBasicBlock &MBB : MF) {
561 for (MachineInstr &MI : MBB) {
562 if (isTypeFoldingSupported(MI.getOpcode()))
563 processInstr(MI, MIB, MRI, GR);
564 }
565 }
566
567 for (MachineBasicBlock &MBB : MF) {
568 for (MachineInstr &MI : MBB) {
569 // We need to rewrite dst types for ASSIGN_TYPE instrs to be able
570 // to perform tblgen'erated selection and we can't do that on Legalizer
571 // as it operates on gMIR only.
572 if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)
573 continue;
574 Register SrcReg = MI.getOperand(1).getReg();
575 unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode();
576 if (!isTypeFoldingSupported(Opcode))
577 continue;
578 Register DstReg = MI.getOperand(0).getReg();
579 bool IsDstPtr = MRI.getType(DstReg).isPointer();
580 bool isDstVec = MRI.getType(DstReg).isVector();
581 if (IsDstPtr || isDstVec)
582 MRI.setRegClass(DstReg, &SPIRV::IDRegClass);
583 // Don't need to reset type of register holding constant and used in
584 // G_ADDRSPACE_CAST, since it breaks legalizer.
585 if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) {
586 MachineInstr &UseMI = *MRI.use_instr_begin(DstReg);
587 if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST)
588 continue;
589 }
590 MRI.setType(DstReg, IsDstPtr ? LLT::pointer(0, GR->getPointerSize())
591 : LLT::scalar(32));
592 }
593 }
594}
595
596static void
598 const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder,
599 const SmallVector<MachineInstr *> &ToProcess) {
601 Register AsmTargetReg;
602 for (unsigned i = 0, Sz = ToProcess.size(); i + 1 < Sz; i += 2) {
603 MachineInstr *I1 = ToProcess[i], *I2 = ToProcess[i + 1];
604 assert(isSpvIntrinsic(*I1, Intrinsic::spv_inline_asm) && I2->isInlineAsm());
605 MIRBuilder.setInsertPt(*I1->getParent(), *I1);
606
607 if (!AsmTargetReg.isValid()) {
608 // define vendor specific assembly target or dialect
609 AsmTargetReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
610 MRI.setRegClass(AsmTargetReg, &SPIRV::IDRegClass);
611 auto AsmTargetMIB =
612 MIRBuilder.buildInstr(SPIRV::OpAsmTargetINTEL).addDef(AsmTargetReg);
613 addStringImm(ST.getTargetTripleAsStr(), AsmTargetMIB);
614 GR->add(AsmTargetMIB.getInstr(), &MF, AsmTargetReg);
615 }
616
617 // create types
618 const MDNode *IAMD = I1->getOperand(1).getMetadata();
619 FunctionType *FTy = cast<FunctionType>(getMDOperandAsType(IAMD, 0));
621 for (const auto &ArgTy : FTy->params())
622 ArgTypes.push_back(GR->getOrCreateSPIRVType(ArgTy, MIRBuilder));
623 SPIRVType *RetType =
624 GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder);
626 FTy, RetType, ArgTypes, MIRBuilder);
627
628 // define vendor specific assembly instructions string
629 Register AsmReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
630 MRI.setRegClass(AsmReg, &SPIRV::IDRegClass);
631 auto AsmMIB = MIRBuilder.buildInstr(SPIRV::OpAsmINTEL)
632 .addDef(AsmReg)
633 .addUse(GR->getSPIRVTypeID(RetType))
634 .addUse(GR->getSPIRVTypeID(FuncType))
635 .addUse(AsmTargetReg);
636 // inline asm string:
637 addStringImm(I2->getOperand(InlineAsm::MIOp_AsmString).getSymbolName(),
638 AsmMIB);
639 // inline asm constraint string:
640 addStringImm(cast<MDString>(I1->getOperand(2).getMetadata()->getOperand(0))
641 ->getString(),
642 AsmMIB);
643 GR->add(AsmMIB.getInstr(), &MF, AsmReg);
644
645 // calls the inline assembly instruction
646 unsigned ExtraInfo = I2->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
647 if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
648 MIRBuilder.buildInstr(SPIRV::OpDecorate)
649 .addUse(AsmReg)
650 .addImm(static_cast<uint32_t>(SPIRV::Decoration::SideEffectsINTEL));
651 Register DefReg;
653 unsigned StartOp = InlineAsm::MIOp_FirstOperand,
655 unsigned I2Sz = I2->getNumOperands();
656 for (unsigned Idx = StartOp; Idx != I2Sz; ++Idx) {
657 const MachineOperand &MO = I2->getOperand(Idx);
658 if (MO.isMetadata())
659 continue;
660 if (Idx == AsmDescOp && MO.isImm()) {
661 // compute the index of the next operand descriptor
662 const InlineAsm::Flag F(MO.getImm());
663 AsmDescOp += 1 + F.getNumOperandRegisters();
664 } else {
665 if (MO.isReg() && MO.isDef())
666 DefReg = MO.getReg();
667 else
668 Ops.push_back(Idx);
669 }
670 }
671 if (!DefReg.isValid()) {
672 DefReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
673 MRI.setRegClass(DefReg, &SPIRV::IDRegClass);
674 SPIRVType *VoidType = GR->getOrCreateSPIRVType(
675 Type::getVoidTy(MF.getFunction().getContext()), MIRBuilder);
676 GR->assignSPIRVTypeToVReg(VoidType, DefReg, MF);
677 }
678 auto AsmCall = MIRBuilder.buildInstr(SPIRV::OpAsmCallINTEL)
679 .addDef(DefReg)
680 .addUse(GR->getSPIRVTypeID(RetType))
681 .addUse(AsmReg);
682 unsigned IntrIdx = 2;
683 for (unsigned Idx : Ops) {
684 ++IntrIdx;
685 const MachineOperand &MO = I2->getOperand(Idx);
686 if (MO.isReg())
687 AsmCall.addUse(MO.getReg());
688 else
689 AsmCall.addUse(I1->getOperand(IntrIdx).getReg());
690 }
691 }
692 for (MachineInstr *MI : ToProcess)
693 MI->eraseFromParent();
694}
695
697 const SPIRVSubtarget &ST,
698 MachineIRBuilder MIRBuilder) {
700 for (MachineBasicBlock &MBB : MF) {
701 for (MachineInstr &MI : MBB) {
702 if (isSpvIntrinsic(MI, Intrinsic::spv_inline_asm) ||
703 MI.getOpcode() == TargetOpcode::INLINEASM)
704 ToProcess.push_back(&MI);
705 }
706 }
707 if (ToProcess.size() == 0)
708 return;
709
710 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly))
711 report_fatal_error("Inline assembly instructions require the "
712 "following SPIR-V extension: SPV_INTEL_inline_assembly",
713 false);
714
715 insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess);
716}
717
720 for (MachineBasicBlock &MBB : MF) {
721 for (MachineInstr &MI : MBB) {
722 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration))
723 continue;
724 MIB.setInsertPt(*MI.getParent(), MI);
725 buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
726 MI.getOperand(2).getMetadata());
727 ToErase.push_back(&MI);
728 }
729 }
730 for (MachineInstr *MI : ToErase)
731 MI->eraseFromParent();
732}
733
734// Find basic blocks of the switch and replace registers in spv_switch() by its
735// MBB equivalent.
737 MachineIRBuilder MIB) {
740 Switches;
741 for (MachineBasicBlock &MBB : MF) {
743 BB2MBB[MBB.getBasicBlock()] = &MBB;
744 for (MachineInstr &MI : MBB) {
745 if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))
746 continue;
747 // Calls to spv_switch intrinsics representing IR switches.
749 for (unsigned i = 2; i < MI.getNumOperands(); ++i) {
750 Register Reg = MI.getOperand(i).getReg();
751 if (i % 2 == 1) {
752 MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI);
753 NewOps.push_back(ConstInstr);
754 } else {
755 MachineInstr *BuildMBB = MRI.getVRegDef(Reg);
756 assert(BuildMBB &&
757 BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&
758 BuildMBB->getOperand(1).isBlockAddress() &&
759 BuildMBB->getOperand(1).getBlockAddress());
760 NewOps.push_back(BuildMBB);
761 }
762 }
763 Switches.push_back(std::make_pair(&MI, NewOps));
764 }
765 }
766
768 for (auto &SwIt : Switches) {
769 MachineInstr &MI = *SwIt.first;
770 SmallVector<MachineInstr *, 8> &Ins = SwIt.second;
772 for (unsigned i = 0; i < Ins.size(); ++i) {
773 if (Ins[i]->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
774 BasicBlock *CaseBB =
775 Ins[i]->getOperand(1).getBlockAddress()->getBasicBlock();
776 auto It = BB2MBB.find(CaseBB);
777 if (It == BB2MBB.end())
778 report_fatal_error("cannot find a machine basic block by a basic "
779 "block in a switch statement");
780 NewOps.push_back(MachineOperand::CreateMBB(It->second));
781 MI.getParent()->addSuccessor(It->second);
782 ToEraseMI.insert(Ins[i]);
783 } else {
784 NewOps.push_back(
785 MachineOperand::CreateCImm(Ins[i]->getOperand(1).getCImm()));
786 }
787 }
788 for (unsigned i = MI.getNumOperands() - 1; i > 1; --i)
789 MI.removeOperand(i);
790 for (auto &MO : NewOps)
791 MI.addOperand(MO);
792 if (MachineInstr *Next = MI.getNextNode()) {
793 if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {
794 ToEraseMI.insert(Next);
795 Next = MI.getNextNode();
796 }
797 if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)
798 ToEraseMI.insert(Next);
799 }
800 }
801
802 // If we just delete G_BLOCK_ADDR instructions with BlockAddress operands,
803 // this leaves their BasicBlock counterparts in a "address taken" status. This
804 // would make AsmPrinter to generate a series of unneeded labels of a "Address
805 // of block that was removed by CodeGen" kind. Let's first ensure that we
806 // don't have a dangling BlockAddress constants by zapping the BlockAddress
807 // nodes, and only after that proceed with erasing G_BLOCK_ADDR instructions.
808 Constant *Replacement =
809 ConstantInt::get(Type::getInt32Ty(MF.getFunction().getContext()), 1);
810 for (MachineInstr *BlockAddrI : ToEraseMI) {
811 if (BlockAddrI->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
812 BlockAddress *BA = const_cast<BlockAddress *>(
813 BlockAddrI->getOperand(1).getBlockAddress());
815 ConstantExpr::getIntToPtr(Replacement, BA->getType()));
816 BA->destroyConstant();
817 }
818 BlockAddrI->eraseFromParent();
819 }
820}
821
823 if (MBB.empty())
824 return true;
825
826 // Branching SPIR-V intrinsics are not detected by this generic method.
827 // Thus, we can only trust negative result.
828 if (!MBB.canFallThrough())
829 return false;
830
831 // Otherwise, we must manually check if we have a SPIR-V intrinsic which
832 // prevent an implicit fallthrough.
834 It != E; ++It) {
835 if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
836 return false;
837 }
838 return true;
839}
840
842 MachineIRBuilder MIB) {
843 // It is valid for MachineBasicBlocks to not finish with a branch instruction.
844 // In such cases, they will simply fallthrough their immediate successor.
845 for (MachineBasicBlock &MBB : MF) {
847 continue;
848
849 assert(std::distance(MBB.successors().begin(), MBB.successors().end()) ==
850 1);
851 MIB.setInsertPt(MBB, MBB.end());
852 MIB.buildBr(**MBB.successors().begin());
853 }
854}
855
856bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
857 // Initialize the type registry.
859 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
860 GR->setCurrentFunc(MF);
861 MachineIRBuilder MIB(MF);
862 // a registry of target extension constants
863 DenseMap<MachineInstr *, Type *> TargetExtConstTypes;
864 // to keep record of tracked constants
865 SmallSet<Register, 4> TrackedConstRegs;
866 addConstantsToTrack(MF, GR, ST, TargetExtConstTypes, TrackedConstRegs);
867 foldConstantsIntoIntrinsics(MF, TrackedConstRegs);
868 insertBitcasts(MF, GR, MIB);
869 generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes);
870 processSwitches(MF, GR, MIB);
871 processInstrsWithTypeFolding(MF, GR, MIB);
873 insertSpirvDecorations(MF, MIB);
874 insertInlineAsm(MF, GR, ST, MIB);
875
876 return true;
877}
878
879INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,
880 false)
881
882char SPIRVPreLegalizer::ID = 0;
883
885 return new SPIRVPreLegalizer();
886}
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 void widenScalarLLTNextPow2(Register Reg, MachineRegisterInfo &MRI)
static SPIRVType * propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI, MachineIRBuilder &MIB)
static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR, const SPIRVSubtarget &STI, DenseMap< MachineInstr *, Type * > &TargetExtConstTypes, SmallSet< Register, 4 > &TrackedConstRegs)
#define DEBUG_TYPE
static void foldConstantsIntoIntrinsics(MachineFunction &MF, const SmallSet< Register, 4 > &TrackedConstRegs)
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 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:61
The address of a basic block.
Definition: Constants.h:890
static Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
Definition: Constants.cpp:2231
This is the shared class of boolean and integer constants.
Definition: Constants.h:81
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:358
constexpr unsigned getScalarSizeInBits() const
Definition: LowLevelType.h:267
constexpr bool isScalar() const
Definition: LowLevelType.h:146
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:569
void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:579
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 CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
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:344
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:479
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:135
bool contains(const T &V) const
Check if the SmallSet contains the given element.
Definition: SmallSet.h:236
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition: SmallSet.h:179
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
unsigned Log2_32_Ceil(uint32_t Value)
Return the ceil log base 2 of the specified value, 32 if the value is zero.
Definition: MathExtras.h:337
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)
Type * toTypedPointer(Type *Ty)
Definition: SPIRVUtils.h:156
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
@ 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:285
void initializeSPIRVPreLegalizerPass(PassRegistry &)
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
Definition: SPIRVUtils.cpp:279
void addStringImm(const StringRef &Str, MCInst &Inst)
Definition: SPIRVUtils.cpp:51
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, const MDNode *GVarMD)
Definition: SPIRVUtils.cpp:136