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
43 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
44 SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites;
45 for (MachineBasicBlock &MBB : MF) {
46 for (MachineInstr &MI : MBB) {
47 if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant))
48 continue;
49 ToErase.push_back(&MI);
50 auto *Const =
51 cast<Constant>(cast<ConstantAsMetadata>(
52 MI.getOperand(3).getMetadata()->getOperand(0))
53 ->getValue());
54 if (auto *GV = dyn_cast<GlobalValue>(Const)) {
55 Register Reg = GR->find(GV, &MF);
56 if (!Reg.isValid())
57 GR->add(GV, &MF, MI.getOperand(2).getReg());
58 else
59 RegsAlreadyAddedToDT[&MI] = Reg;
60 } else {
61 Register Reg = GR->find(Const, &MF);
62 if (!Reg.isValid()) {
63 if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) {
64 auto *BuildVec = MRI.getVRegDef(MI.getOperand(2).getReg());
65 assert(BuildVec &&
66 BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
67 for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) {
68 // Ensure that OpConstantComposite reuses a constant when it's
69 // already created and available in the same machine function.
70 Constant *ElemConst = ConstVec->getElementAsConstant(i);
71 Register ElemReg = GR->find(ElemConst, &MF);
72 if (!ElemReg.isValid())
73 GR->add(ElemConst, &MF, BuildVec->getOperand(1 + i).getReg());
74 else
75 BuildVec->getOperand(1 + i).setReg(ElemReg);
76 }
77 }
78 GR->add(Const, &MF, MI.getOperand(2).getReg());
79 } else {
80 RegsAlreadyAddedToDT[&MI] = Reg;
81 // This MI is unused and will be removed. If the MI uses
82 // const_composite, it will be unused and should be removed too.
83 assert(MI.getOperand(2).isReg() && "Reg operand is expected");
84 MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg());
85 if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))
86 ToEraseComposites.push_back(SrcMI);
87 }
88 }
89 }
90 }
91 for (MachineInstr *MI : ToErase) {
92 Register Reg = MI->getOperand(2).getReg();
93 if (RegsAlreadyAddedToDT.contains(MI))
94 Reg = RegsAlreadyAddedToDT[MI];
95 auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg());
96 if (!MRI.getRegClassOrNull(Reg) && RC)
97 MRI.setRegClass(Reg, RC);
98 MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg);
99 MI->eraseFromParent();
100 }
101 for (MachineInstr *MI : ToEraseComposites)
102 MI->eraseFromParent();
103}
104
108 const unsigned AssignNameOperandShift = 2;
109 for (MachineBasicBlock &MBB : MF) {
110 for (MachineInstr &MI : MBB) {
111 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name))
112 continue;
113 unsigned NumOp = MI.getNumExplicitDefs() + AssignNameOperandShift;
114 while (MI.getOperand(NumOp).isReg()) {
115 MachineOperand &MOp = MI.getOperand(NumOp);
116 MachineInstr *ConstMI = MRI.getVRegDef(MOp.getReg());
117 assert(ConstMI->getOpcode() == TargetOpcode::G_CONSTANT);
118 MI.removeOperand(NumOp);
119 MI.addOperand(MachineOperand::CreateImm(
120 ConstMI->getOperand(1).getCImm()->getZExtValue()));
121 if (MRI.use_empty(ConstMI->getOperand(0).getReg()))
122 ToErase.push_back(ConstMI);
123 }
124 }
125 }
126 for (MachineInstr *MI : ToErase)
127 MI->eraseFromParent();
128}
129
131 MachineIRBuilder MIB) {
132 // Get access to information about available extensions
133 const SPIRVSubtarget *ST =
134 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
136 for (MachineBasicBlock &MBB : MF) {
137 for (MachineInstr &MI : MBB) {
138 if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast) &&
139 !isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
140 continue;
141 assert(MI.getOperand(2).isReg());
142 MIB.setInsertPt(*MI.getParent(), MI);
143 ToErase.push_back(&MI);
144 if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
145 MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());
146 continue;
147 }
148 Register Def = MI.getOperand(0).getReg();
149 Register Source = MI.getOperand(2).getReg();
151 getMDOperandAsType(MI.getOperand(3).getMetadata(), 0), MIB);
152 SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
154 addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST));
155
156 // If the bitcast would be redundant, replace all uses with the source
157 // register.
158 if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) {
159 MIB.getMRI()->replaceRegWith(Def, Source);
160 } else {
161 GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
162 MIB.buildBitcast(Def, Source);
163 }
164 }
165 }
166 for (MachineInstr *MI : ToErase)
167 MI->eraseFromParent();
168}
169
170// Translating GV, IRTranslator sometimes generates following IR:
171// %1 = G_GLOBAL_VALUE
172// %2 = COPY %1
173// %3 = G_ADDRSPACE_CAST %2
174//
175// or
176//
177// %1 = G_ZEXT %2
178// G_MEMCPY ... %2 ...
179//
180// New registers have no SPIRVType and no register class info.
181//
182// Set SPIRVType for GV, propagate it from GV to other instructions,
183// also set register classes.
186 MachineIRBuilder &MIB) {
187 SPIRVType *SpirvTy = nullptr;
188 assert(MI && "Machine instr is expected");
189 if (MI->getOperand(0).isReg()) {
190 Register Reg = MI->getOperand(0).getReg();
191 SpirvTy = GR->getSPIRVTypeForVReg(Reg);
192 if (!SpirvTy) {
193 switch (MI->getOpcode()) {
194 case TargetOpcode::G_CONSTANT: {
195 MIB.setInsertPt(*MI->getParent(), MI);
196 Type *Ty = MI->getOperand(1).getCImm()->getType();
197 SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);
198 break;
199 }
200 case TargetOpcode::G_GLOBAL_VALUE: {
201 MIB.setInsertPt(*MI->getParent(), MI);
202 const GlobalValue *Global = MI->getOperand(1).getGlobal();
203 Type *ElementTy = GR->getDeducedGlobalValueType(Global);
204 auto *Ty = TypedPointerType::get(ElementTy,
205 Global->getType()->getAddressSpace());
206 SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);
207 break;
208 }
209 case TargetOpcode::G_ZEXT: {
210 if (MI->getOperand(1).isReg()) {
211 if (MachineInstr *DefInstr =
212 MRI.getVRegDef(MI->getOperand(1).getReg())) {
213 if (SPIRVType *Def = propagateSPIRVType(DefInstr, GR, MRI, MIB)) {
214 unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);
215 unsigned ExpectedBW =
216 std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);
217 unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);
218 SpirvTy = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);
219 if (NumElements > 1)
220 SpirvTy =
221 GR->getOrCreateSPIRVVectorType(SpirvTy, NumElements, MIB);
222 }
223 }
224 }
225 break;
226 }
227 case TargetOpcode::G_TRUNC:
228 case TargetOpcode::G_ADDRSPACE_CAST:
229 case TargetOpcode::G_PTR_ADD:
230 case TargetOpcode::COPY: {
231 MachineOperand &Op = MI->getOperand(1);
232 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
233 if (Def)
234 SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB);
235 break;
236 }
237 default:
238 break;
239 }
240 if (SpirvTy)
241 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
242 if (!MRI.getRegClassOrNull(Reg))
243 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
244 }
245 }
246 return SpirvTy;
247}
248
249static std::pair<Register, unsigned>
251 const SPIRVGlobalRegistry &GR) {
252 if (!SpvType)
253 SpvType = GR.getSPIRVTypeForVReg(SrcReg);
254 assert(SpvType && "VReg is expected to have SPIRV type");
255 LLT NewT = LLT::scalar(32);
256 bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat;
257 bool IsVectorFloat =
258 SpvType->getOpcode() == SPIRV::OpTypeVector &&
259 GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() ==
260 SPIRV::OpTypeFloat;
261 IsFloat |= IsVectorFloat;
262 auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID;
263 auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass;
264 if (MRI.getType(SrcReg).isPointer()) {
265 unsigned PtrSz = GR.getPointerSize();
266 NewT = LLT::pointer(0, PtrSz);
267 bool IsVec = MRI.getType(SrcReg).isVector();
268 if (IsVec)
269 NewT = LLT::fixed_vector(2, NewT);
270 if (PtrSz == 64) {
271 if (IsVec) {
272 GetIdOp = SPIRV::GET_vpID64;
273 DstClass = &SPIRV::vpID64RegClass;
274 } else {
275 GetIdOp = SPIRV::GET_pID64;
276 DstClass = &SPIRV::pID64RegClass;
277 }
278 } else {
279 if (IsVec) {
280 GetIdOp = SPIRV::GET_vpID32;
281 DstClass = &SPIRV::vpID32RegClass;
282 } else {
283 GetIdOp = SPIRV::GET_pID32;
284 DstClass = &SPIRV::pID32RegClass;
285 }
286 }
287 } else if (MRI.getType(SrcReg).isVector()) {
288 NewT = LLT::fixed_vector(2, NewT);
289 if (IsFloat) {
290 GetIdOp = SPIRV::GET_vfID;
291 DstClass = &SPIRV::vfIDRegClass;
292 } else {
293 GetIdOp = SPIRV::GET_vID;
294 DstClass = &SPIRV::vIDRegClass;
295 }
296 }
297 Register IdReg = MRI.createGenericVirtualRegister(NewT);
298 MRI.setRegClass(IdReg, DstClass);
299 return {IdReg, GetIdOp};
300}
301
302// Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as
303// a dst of the definition, assign SPIRVType to both registers. If SpirvTy is
304// provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty.
305// It's used also in SPIRVBuiltins.cpp.
306// TODO: maybe move to SPIRVUtils.
307namespace llvm {
311 MachineInstr *Def = MRI.getVRegDef(Reg);
312 assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected.");
313 MIB.setInsertPt(*Def->getParent(),
314 (Def->getNextNode() ? Def->getNextNode()->getIterator()
315 : Def->getParent()->end()));
316 SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB);
317 Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg));
318 if (auto *RC = MRI.getRegClassOrNull(Reg)) {
319 MRI.setRegClass(NewReg, RC);
320 } else {
321 MRI.setRegClass(NewReg, &SPIRV::IDRegClass);
322 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
323 }
324 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
325 // This is to make it convenient for Legalizer to get the SPIRVType
326 // when processing the actual MI (i.e. not pseudo one).
327 GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF());
328 // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep
329 // the flags after instruction selection.
330 const uint32_t Flags = Def->getFlags();
331 MIB.buildInstr(SPIRV::ASSIGN_TYPE)
332 .addDef(Reg)
333 .addUse(NewReg)
334 .addUse(GR->getSPIRVTypeID(SpirvTy))
335 .setMIFlags(Flags);
336 Def->getOperand(0).setReg(NewReg);
337 return NewReg;
338}
339
342 assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg()));
343 MachineInstr &AssignTypeInst =
344 *(MRI.use_instr_begin(MI.getOperand(0).getReg()));
345 auto NewReg =
346 createNewIdReg(nullptr, MI.getOperand(0).getReg(), MRI, *GR).first;
347 AssignTypeInst.getOperand(1).setReg(NewReg);
348 MI.getOperand(0).setReg(NewReg);
349 MIB.setInsertPt(*MI.getParent(),
350 (MI.getNextNode() ? MI.getNextNode()->getIterator()
351 : MI.getParent()->end()));
352 for (auto &Op : MI.operands()) {
353 if (!Op.isReg() || Op.isDef())
354 continue;
355 auto IdOpInfo = createNewIdReg(nullptr, Op.getReg(), MRI, *GR);
356 MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg());
357 Op.setReg(IdOpInfo.first);
358 }
359}
360} // namespace llvm
361
363 MachineIRBuilder MIB) {
364 // Get access to information about available extensions
365 const SPIRVSubtarget *ST =
366 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
367
370
371 for (MachineBasicBlock *MBB : post_order(&MF)) {
372 if (MBB->empty())
373 continue;
374
375 bool ReachedBegin = false;
376 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
377 !ReachedBegin;) {
378 MachineInstr &MI = *MII;
379
380 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
381 Register Reg = MI.getOperand(1).getReg();
382 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
384 getMDOperandAsType(MI.getOperand(2).getMetadata(), 0), MIB);
385 SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
387 addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));
388 MachineInstr *Def = MRI.getVRegDef(Reg);
389 assert(Def && "Expecting an instruction that defines the register");
390 // G_GLOBAL_VALUE already has type info.
391 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
392 insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,
393 MF.getRegInfo());
394 ToErase.push_back(&MI);
395 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
396 Register Reg = MI.getOperand(1).getReg();
397 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
398 MachineInstr *Def = MRI.getVRegDef(Reg);
399 assert(Def && "Expecting an instruction that defines the register");
400 // G_GLOBAL_VALUE already has type info.
401 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
402 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
403 ToErase.push_back(&MI);
404 } else if (MI.getOpcode() == TargetOpcode::G_CONSTANT ||
405 MI.getOpcode() == TargetOpcode::G_FCONSTANT ||
406 MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
407 // %rc = G_CONSTANT ty Val
408 // ===>
409 // %cty = OpType* ty
410 // %rctmp = G_CONSTANT ty Val
411 // %rc = ASSIGN_TYPE %rctmp, %cty
412 Register Reg = MI.getOperand(0).getReg();
413 if (MRI.hasOneUse(Reg)) {
414 MachineInstr &UseMI = *MRI.use_instr_begin(Reg);
415 if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) ||
416 isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name))
417 continue;
418 }
419 Type *Ty = nullptr;
420 if (MI.getOpcode() == TargetOpcode::G_CONSTANT)
421 Ty = MI.getOperand(1).getCImm()->getType();
422 else if (MI.getOpcode() == TargetOpcode::G_FCONSTANT)
423 Ty = MI.getOperand(1).getFPImm()->getType();
424 else {
425 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
426 Type *ElemTy = nullptr;
427 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
428 assert(ElemMI);
429
430 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT)
431 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
432 else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT)
433 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
434 else
435 llvm_unreachable("Unexpected opcode");
436 unsigned NumElts =
437 MI.getNumExplicitOperands() - MI.getNumExplicitDefs();
438 Ty = VectorType::get(ElemTy, NumElts, false);
439 }
440 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI);
441 } else if (MI.getOpcode() == TargetOpcode::G_TRUNC ||
442 MI.getOpcode() == TargetOpcode::G_ZEXT ||
443 MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
444 MI.getOpcode() == TargetOpcode::COPY ||
445 MI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) {
446 propagateSPIRVType(&MI, GR, MRI, MIB);
447 }
448
449 if (MII == Begin)
450 ReachedBegin = true;
451 else
452 --MII;
453 }
454 }
455 for (MachineInstr *MI : ToErase)
456 MI->eraseFromParent();
457}
458
459// Defined in SPIRVLegalizerInfo.cpp.
460extern bool isTypeFoldingSupported(unsigned Opcode);
461
464 MachineIRBuilder MIB) {
466 for (MachineBasicBlock &MBB : MF) {
467 for (MachineInstr &MI : MBB) {
468 if (isTypeFoldingSupported(MI.getOpcode()))
469 processInstr(MI, MIB, MRI, GR);
470 }
471 }
472
473 for (MachineBasicBlock &MBB : MF) {
474 for (MachineInstr &MI : MBB) {
475 // We need to rewrite dst types for ASSIGN_TYPE instrs to be able
476 // to perform tblgen'erated selection and we can't do that on Legalizer
477 // as it operates on gMIR only.
478 if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)
479 continue;
480 Register SrcReg = MI.getOperand(1).getReg();
481 unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode();
482 if (!isTypeFoldingSupported(Opcode))
483 continue;
484 Register DstReg = MI.getOperand(0).getReg();
485 bool IsDstPtr = MRI.getType(DstReg).isPointer();
486 if (IsDstPtr || MRI.getType(DstReg).isVector())
487 MRI.setRegClass(DstReg, &SPIRV::IDRegClass);
488 // Don't need to reset type of register holding constant and used in
489 // G_ADDRSPACE_CAST, since it breaks legalizer.
490 if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) {
491 MachineInstr &UseMI = *MRI.use_instr_begin(DstReg);
492 if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST)
493 continue;
494 }
495 MRI.setType(DstReg, IsDstPtr ? LLT::pointer(0, GR->getPointerSize())
496 : LLT::scalar(32));
497 }
498 }
499}
500
501// Find basic blocks of the switch and replace registers in spv_switch() by its
502// MBB equivalent.
504 MachineIRBuilder MIB) {
507 Switches;
508 for (MachineBasicBlock &MBB : MF) {
510 BB2MBB[MBB.getBasicBlock()] = &MBB;
511 for (MachineInstr &MI : MBB) {
512 if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))
513 continue;
514 // Calls to spv_switch intrinsics representing IR switches.
516 for (unsigned i = 2; i < MI.getNumOperands(); ++i) {
517 Register Reg = MI.getOperand(i).getReg();
518 if (i % 2 == 1) {
519 MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI);
520 NewOps.push_back(ConstInstr);
521 } else {
522 MachineInstr *BuildMBB = MRI.getVRegDef(Reg);
523 assert(BuildMBB &&
524 BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&
525 BuildMBB->getOperand(1).isBlockAddress() &&
526 BuildMBB->getOperand(1).getBlockAddress());
527 NewOps.push_back(BuildMBB);
528 }
529 }
530 Switches.push_back(std::make_pair(&MI, NewOps));
531 }
532 }
533
535 for (auto &SwIt : Switches) {
536 MachineInstr &MI = *SwIt.first;
537 SmallVector<MachineInstr *, 8> &Ins = SwIt.second;
539 for (unsigned i = 0; i < Ins.size(); ++i) {
540 if (Ins[i]->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
541 BasicBlock *CaseBB =
542 Ins[i]->getOperand(1).getBlockAddress()->getBasicBlock();
543 auto It = BB2MBB.find(CaseBB);
544 if (It == BB2MBB.end())
545 report_fatal_error("cannot find a machine basic block by a basic "
546 "block in a switch statement");
547 NewOps.push_back(MachineOperand::CreateMBB(It->second));
548 MI.getParent()->addSuccessor(It->second);
549 ToEraseMI.insert(Ins[i]);
550 } else {
551 NewOps.push_back(
552 MachineOperand::CreateCImm(Ins[i]->getOperand(1).getCImm()));
553 }
554 }
555 for (unsigned i = MI.getNumOperands() - 1; i > 1; --i)
556 MI.removeOperand(i);
557 for (auto &MO : NewOps)
558 MI.addOperand(MO);
559 if (MachineInstr *Next = MI.getNextNode()) {
560 if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {
561 ToEraseMI.insert(Next);
562 Next = MI.getNextNode();
563 }
564 if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)
565 ToEraseMI.insert(Next);
566 }
567 }
568 for (MachineInstr *BlockAddrI : ToEraseMI)
569 BlockAddrI->eraseFromParent();
570}
571
573 if (MBB.empty())
574 return true;
575
576 // Branching SPIR-V intrinsics are not detected by this generic method.
577 // Thus, we can only trust negative result.
578 if (!MBB.canFallThrough())
579 return false;
580
581 // Otherwise, we must manually check if we have a SPIR-V intrinsic which
582 // prevent an implicit fallthrough.
584 It != E; ++It) {
585 if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
586 return false;
587 }
588 return true;
589}
590
592 MachineIRBuilder MIB) {
593 // It is valid for MachineBasicBlocks to not finish with a branch instruction.
594 // In such cases, they will simply fallthrough their immediate successor.
595 for (MachineBasicBlock &MBB : MF) {
597 continue;
598
599 assert(std::distance(MBB.successors().begin(), MBB.successors().end()) ==
600 1);
601 MIB.setInsertPt(MBB, MBB.end());
602 MIB.buildBr(**MBB.successors().begin());
603 }
604}
605
606bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
607 // Initialize the type registry.
609 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
610 GR->setCurrentFunc(MF);
611 MachineIRBuilder MIB(MF);
612 addConstantsToTrack(MF, GR);
614 insertBitcasts(MF, GR, MIB);
615 generateAssignInstrs(MF, GR, MIB);
616 processSwitches(MF, GR, MIB);
617 processInstrsWithTypeFolding(MF, GR, MIB);
619
620 return true;
621}
622
623INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,
624 false)
625
626char SPIRVPreLegalizer::ID = 0;
627
629 return new SPIRVPreLegalizer();
630}
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)
static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR)
#define DEBUG_TYPE
static std::pair< Register, unsigned > createNewIdReg(SPIRVType *SpvType, Register SrcReg, MachineRegisterInfo &MRI, const SPIRVGlobalRegistry &GR)
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
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
Definition: LowLevelType.h:57
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:546
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:556
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