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_ZEXT: {
219 if (MI->getOperand(1).isReg()) {
220 if (MachineInstr *DefInstr =
221 MRI.getVRegDef(MI->getOperand(1).getReg())) {
222 if (SPIRVType *Def = propagateSPIRVType(DefInstr, GR, MRI, MIB)) {
223 unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);
224 unsigned ExpectedBW =
225 std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);
226 unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);
227 SpirvTy = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);
228 if (NumElements > 1)
229 SpirvTy =
230 GR->getOrCreateSPIRVVectorType(SpirvTy, NumElements, MIB);
231 }
232 }
233 }
234 break;
235 }
236 case TargetOpcode::G_PTRTOINT:
237 SpirvTy = GR->getOrCreateSPIRVIntegerType(
238 MRI.getType(Reg).getScalarSizeInBits(), MIB);
239 break;
240 case TargetOpcode::G_TRUNC:
241 case TargetOpcode::G_ADDRSPACE_CAST:
242 case TargetOpcode::G_PTR_ADD:
243 case TargetOpcode::COPY: {
244 MachineOperand &Op = MI->getOperand(1);
245 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
246 if (Def)
247 SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB);
248 break;
249 }
250 default:
251 break;
252 }
253 if (SpirvTy)
254 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
255 if (!MRI.getRegClassOrNull(Reg))
256 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
257 }
258 }
259 return SpirvTy;
260}
261
262static std::pair<Register, unsigned>
264 const SPIRVGlobalRegistry &GR) {
265 if (!SpvType)
266 SpvType = GR.getSPIRVTypeForVReg(SrcReg);
267 assert(SpvType && "VReg is expected to have SPIRV type");
268 LLT SrcLLT = MRI.getType(SrcReg);
269 LLT NewT = LLT::scalar(32);
270 bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat;
271 bool IsVectorFloat =
272 SpvType->getOpcode() == SPIRV::OpTypeVector &&
273 GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() ==
274 SPIRV::OpTypeFloat;
275 IsFloat |= IsVectorFloat;
276 auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID;
277 auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass;
278 if (SrcLLT.isPointer()) {
279 unsigned PtrSz = GR.getPointerSize();
280 NewT = LLT::pointer(0, PtrSz);
281 bool IsVec = SrcLLT.isVector();
282 if (IsVec)
283 NewT = LLT::fixed_vector(2, NewT);
284 if (PtrSz == 64) {
285 if (IsVec) {
286 GetIdOp = SPIRV::GET_vpID64;
287 DstClass = &SPIRV::vpID64RegClass;
288 } else {
289 GetIdOp = SPIRV::GET_pID64;
290 DstClass = &SPIRV::pID64RegClass;
291 }
292 } else {
293 if (IsVec) {
294 GetIdOp = SPIRV::GET_vpID32;
295 DstClass = &SPIRV::vpID32RegClass;
296 } else {
297 GetIdOp = SPIRV::GET_pID32;
298 DstClass = &SPIRV::pID32RegClass;
299 }
300 }
301 } else if (SrcLLT.isVector()) {
302 NewT = LLT::fixed_vector(2, NewT);
303 if (IsFloat) {
304 GetIdOp = SPIRV::GET_vfID;
305 DstClass = &SPIRV::vfIDRegClass;
306 } else {
307 GetIdOp = SPIRV::GET_vID;
308 DstClass = &SPIRV::vIDRegClass;
309 }
310 }
311 Register IdReg = MRI.createGenericVirtualRegister(NewT);
312 MRI.setRegClass(IdReg, DstClass);
313 return {IdReg, GetIdOp};
314}
315
316// Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as
317// a dst of the definition, assign SPIRVType to both registers. If SpirvTy is
318// provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty.
319// It's used also in SPIRVBuiltins.cpp.
320// TODO: maybe move to SPIRVUtils.
321namespace llvm {
325 MachineInstr *Def = MRI.getVRegDef(Reg);
326 assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected.");
327 MIB.setInsertPt(*Def->getParent(),
328 (Def->getNextNode() ? Def->getNextNode()->getIterator()
329 : Def->getParent()->end()));
330 SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB);
331 Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg));
332 if (auto *RC = MRI.getRegClassOrNull(Reg)) {
333 MRI.setRegClass(NewReg, RC);
334 } else {
335 MRI.setRegClass(NewReg, &SPIRV::IDRegClass);
336 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
337 }
338 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
339 // This is to make it convenient for Legalizer to get the SPIRVType
340 // when processing the actual MI (i.e. not pseudo one).
341 GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF());
342 // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep
343 // the flags after instruction selection.
344 const uint32_t Flags = Def->getFlags();
345 MIB.buildInstr(SPIRV::ASSIGN_TYPE)
346 .addDef(Reg)
347 .addUse(NewReg)
348 .addUse(GR->getSPIRVTypeID(SpirvTy))
349 .setMIFlags(Flags);
350 Def->getOperand(0).setReg(NewReg);
351 return NewReg;
352}
353
356 assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg()));
357 MachineInstr &AssignTypeInst =
358 *(MRI.use_instr_begin(MI.getOperand(0).getReg()));
359 auto NewReg =
360 createNewIdReg(nullptr, MI.getOperand(0).getReg(), MRI, *GR).first;
361 AssignTypeInst.getOperand(1).setReg(NewReg);
362 MI.getOperand(0).setReg(NewReg);
363 MIB.setInsertPt(*MI.getParent(),
364 (MI.getNextNode() ? MI.getNextNode()->getIterator()
365 : MI.getParent()->end()));
366 for (auto &Op : MI.operands()) {
367 if (!Op.isReg() || Op.isDef())
368 continue;
369 auto IdOpInfo = createNewIdReg(nullptr, Op.getReg(), MRI, *GR);
370 MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg());
371 Op.setReg(IdOpInfo.first);
372 }
373}
374} // namespace llvm
375
376static void
379 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
380 // Get access to information about available extensions
381 const SPIRVSubtarget *ST =
382 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
383
386
387 for (MachineBasicBlock *MBB : post_order(&MF)) {
388 if (MBB->empty())
389 continue;
390
391 bool ReachedBegin = false;
392 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
393 !ReachedBegin;) {
394 MachineInstr &MI = *MII;
395
396 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
397 Register Reg = MI.getOperand(1).getReg();
398 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
400 getMDOperandAsType(MI.getOperand(2).getMetadata(), 0), MIB);
401 SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
403 addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));
404 MachineInstr *Def = MRI.getVRegDef(Reg);
405 assert(Def && "Expecting an instruction that defines the register");
406 // G_GLOBAL_VALUE already has type info.
407 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
408 insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,
409 MF.getRegInfo());
410 ToErase.push_back(&MI);
411 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
412 Register Reg = MI.getOperand(1).getReg();
413 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
414 MachineInstr *Def = MRI.getVRegDef(Reg);
415 assert(Def && "Expecting an instruction that defines the register");
416 // G_GLOBAL_VALUE already has type info.
417 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
418 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
419 ToErase.push_back(&MI);
420 } else if (MI.getOpcode() == TargetOpcode::G_CONSTANT ||
421 MI.getOpcode() == TargetOpcode::G_FCONSTANT ||
422 MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
423 // %rc = G_CONSTANT ty Val
424 // ===>
425 // %cty = OpType* ty
426 // %rctmp = G_CONSTANT ty Val
427 // %rc = ASSIGN_TYPE %rctmp, %cty
428 Register Reg = MI.getOperand(0).getReg();
429 if (MRI.hasOneUse(Reg)) {
430 MachineInstr &UseMI = *MRI.use_instr_begin(Reg);
431 if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) ||
432 isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name))
433 continue;
434 }
435 Type *Ty = nullptr;
436 if (MI.getOpcode() == TargetOpcode::G_CONSTANT) {
437 auto TargetExtIt = TargetExtConstTypes.find(&MI);
438 Ty = TargetExtIt == TargetExtConstTypes.end()
439 ? MI.getOperand(1).getCImm()->getType()
440 : TargetExtIt->second;
441 } else if (MI.getOpcode() == TargetOpcode::G_FCONSTANT) {
442 Ty = MI.getOperand(1).getFPImm()->getType();
443 } else {
444 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
445 Type *ElemTy = nullptr;
446 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
447 assert(ElemMI);
448
449 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT)
450 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
451 else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT)
452 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
453 else
454 llvm_unreachable("Unexpected opcode");
455 unsigned NumElts =
456 MI.getNumExplicitOperands() - MI.getNumExplicitDefs();
457 Ty = VectorType::get(ElemTy, NumElts, false);
458 }
459 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI);
460 } else if (MI.getOpcode() == TargetOpcode::G_TRUNC ||
461 MI.getOpcode() == TargetOpcode::G_ZEXT ||
462 MI.getOpcode() == TargetOpcode::G_PTRTOINT ||
463 MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
464 MI.getOpcode() == TargetOpcode::COPY ||
465 MI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) {
466 propagateSPIRVType(&MI, GR, MRI, MIB);
467 }
468
469 if (MII == Begin)
470 ReachedBegin = true;
471 else
472 --MII;
473 }
474 }
475 for (MachineInstr *MI : ToErase)
476 MI->eraseFromParent();
477}
478
479// Defined in SPIRVLegalizerInfo.cpp.
480extern bool isTypeFoldingSupported(unsigned Opcode);
481
484 MachineIRBuilder MIB) {
486 for (MachineBasicBlock &MBB : MF) {
487 for (MachineInstr &MI : MBB) {
488 if (isTypeFoldingSupported(MI.getOpcode()))
489 processInstr(MI, MIB, MRI, GR);
490 }
491 }
492
493 for (MachineBasicBlock &MBB : MF) {
494 for (MachineInstr &MI : MBB) {
495 // We need to rewrite dst types for ASSIGN_TYPE instrs to be able
496 // to perform tblgen'erated selection and we can't do that on Legalizer
497 // as it operates on gMIR only.
498 if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)
499 continue;
500 Register SrcReg = MI.getOperand(1).getReg();
501 unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode();
502 if (!isTypeFoldingSupported(Opcode))
503 continue;
504 Register DstReg = MI.getOperand(0).getReg();
505 bool IsDstPtr = MRI.getType(DstReg).isPointer();
506 bool isDstVec = MRI.getType(DstReg).isVector();
507 if (IsDstPtr || isDstVec)
508 MRI.setRegClass(DstReg, &SPIRV::IDRegClass);
509 // Don't need to reset type of register holding constant and used in
510 // G_ADDRSPACE_CAST, since it breaks legalizer.
511 if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) {
512 MachineInstr &UseMI = *MRI.use_instr_begin(DstReg);
513 if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST)
514 continue;
515 }
516 MRI.setType(DstReg, IsDstPtr ? LLT::pointer(0, GR->getPointerSize())
517 : LLT::scalar(32));
518 }
519 }
520}
521
522// Find basic blocks of the switch and replace registers in spv_switch() by its
523// MBB equivalent.
525 MachineIRBuilder MIB) {
528 Switches;
529 for (MachineBasicBlock &MBB : MF) {
531 BB2MBB[MBB.getBasicBlock()] = &MBB;
532 for (MachineInstr &MI : MBB) {
533 if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))
534 continue;
535 // Calls to spv_switch intrinsics representing IR switches.
537 for (unsigned i = 2; i < MI.getNumOperands(); ++i) {
538 Register Reg = MI.getOperand(i).getReg();
539 if (i % 2 == 1) {
540 MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI);
541 NewOps.push_back(ConstInstr);
542 } else {
543 MachineInstr *BuildMBB = MRI.getVRegDef(Reg);
544 assert(BuildMBB &&
545 BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&
546 BuildMBB->getOperand(1).isBlockAddress() &&
547 BuildMBB->getOperand(1).getBlockAddress());
548 NewOps.push_back(BuildMBB);
549 }
550 }
551 Switches.push_back(std::make_pair(&MI, NewOps));
552 }
553 }
554
556 for (auto &SwIt : Switches) {
557 MachineInstr &MI = *SwIt.first;
558 SmallVector<MachineInstr *, 8> &Ins = SwIt.second;
560 for (unsigned i = 0; i < Ins.size(); ++i) {
561 if (Ins[i]->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
562 BasicBlock *CaseBB =
563 Ins[i]->getOperand(1).getBlockAddress()->getBasicBlock();
564 auto It = BB2MBB.find(CaseBB);
565 if (It == BB2MBB.end())
566 report_fatal_error("cannot find a machine basic block by a basic "
567 "block in a switch statement");
568 NewOps.push_back(MachineOperand::CreateMBB(It->second));
569 MI.getParent()->addSuccessor(It->second);
570 ToEraseMI.insert(Ins[i]);
571 } else {
572 NewOps.push_back(
573 MachineOperand::CreateCImm(Ins[i]->getOperand(1).getCImm()));
574 }
575 }
576 for (unsigned i = MI.getNumOperands() - 1; i > 1; --i)
577 MI.removeOperand(i);
578 for (auto &MO : NewOps)
579 MI.addOperand(MO);
580 if (MachineInstr *Next = MI.getNextNode()) {
581 if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {
582 ToEraseMI.insert(Next);
583 Next = MI.getNextNode();
584 }
585 if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)
586 ToEraseMI.insert(Next);
587 }
588 }
589 for (MachineInstr *BlockAddrI : ToEraseMI)
590 BlockAddrI->eraseFromParent();
591}
592
594 if (MBB.empty())
595 return true;
596
597 // Branching SPIR-V intrinsics are not detected by this generic method.
598 // Thus, we can only trust negative result.
599 if (!MBB.canFallThrough())
600 return false;
601
602 // Otherwise, we must manually check if we have a SPIR-V intrinsic which
603 // prevent an implicit fallthrough.
605 It != E; ++It) {
606 if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
607 return false;
608 }
609 return true;
610}
611
613 MachineIRBuilder MIB) {
614 // It is valid for MachineBasicBlocks to not finish with a branch instruction.
615 // In such cases, they will simply fallthrough their immediate successor.
616 for (MachineBasicBlock &MBB : MF) {
618 continue;
619
620 assert(std::distance(MBB.successors().begin(), MBB.successors().end()) ==
621 1);
622 MIB.setInsertPt(MBB, MBB.end());
623 MIB.buildBr(**MBB.successors().begin());
624 }
625}
626
627bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
628 // Initialize the type registry.
630 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
631 GR->setCurrentFunc(MF);
632 MachineIRBuilder MIB(MF);
633 // a registry of target extension constants
634 DenseMap<MachineInstr *, Type *> TargetExtConstTypes;
635 addConstantsToTrack(MF, GR, TargetExtConstTypes);
637 insertBitcasts(MF, GR, MIB);
638 generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes);
639 processSwitches(MF, GR, MIB);
640 processInstrsWithTypeFolding(MF, GR, MIB);
642
643 return true;
644}
645
646INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,
647 false)
648
649char SPIRVPreLegalizer::ID = 0;
650
652 return new SPIRVPreLegalizer();
653}
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...
IRTranslator LLVM IR MI
#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 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 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
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:154
This is an important base class in LLVM.
Definition: Constant.h:41
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
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
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.
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 & 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:558
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:568
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
static MachineOperand CreateCImm(const ConstantInt *CI)
void setReg(Register Reg)
Change the register this operand corresponds to.
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)
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
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 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
#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:156
@ Global
Append to llvm.global_dtors.
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
Definition: SPIRVUtils.cpp:162
void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR)
MachineInstr * getDefInstrMaybeConstant(Register &ConstReg, const MachineRegisterInfo *MRI)
Definition: SPIRVUtils.cpp:226
Type * getMDOperandAsType(const MDNode *N, unsigned I)
Definition: SPIRVUtils.cpp:253
void initializeSPIRVPreLegalizerPass(PassRegistry &)
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
Definition: SPIRVUtils.cpp:247