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 GR->add(ConstVec->getElementAsConstant(i), &MF,
69 BuildVec->getOperand(1 + i).getReg());
70 }
71 GR->add(Const, &MF, MI.getOperand(2).getReg());
72 } else {
73 RegsAlreadyAddedToDT[&MI] = Reg;
74 // This MI is unused and will be removed. If the MI uses
75 // const_composite, it will be unused and should be removed too.
76 assert(MI.getOperand(2).isReg() && "Reg operand is expected");
77 MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg());
78 if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))
79 ToEraseComposites.push_back(SrcMI);
80 }
81 }
82 }
83 }
84 for (MachineInstr *MI : ToErase) {
85 Register Reg = MI->getOperand(2).getReg();
86 if (RegsAlreadyAddedToDT.contains(MI))
87 Reg = RegsAlreadyAddedToDT[MI];
88 auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg());
89 if (!MRI.getRegClassOrNull(Reg) && RC)
90 MRI.setRegClass(Reg, RC);
91 MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg);
92 MI->eraseFromParent();
93 }
94 for (MachineInstr *MI : ToEraseComposites)
95 MI->eraseFromParent();
96}
97
101 const unsigned AssignNameOperandShift = 2;
102 for (MachineBasicBlock &MBB : MF) {
103 for (MachineInstr &MI : MBB) {
104 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name))
105 continue;
106 unsigned NumOp = MI.getNumExplicitDefs() + AssignNameOperandShift;
107 while (MI.getOperand(NumOp).isReg()) {
108 MachineOperand &MOp = MI.getOperand(NumOp);
109 MachineInstr *ConstMI = MRI.getVRegDef(MOp.getReg());
110 assert(ConstMI->getOpcode() == TargetOpcode::G_CONSTANT);
111 MI.removeOperand(NumOp);
112 MI.addOperand(MachineOperand::CreateImm(
113 ConstMI->getOperand(1).getCImm()->getZExtValue()));
114 if (MRI.use_empty(ConstMI->getOperand(0).getReg()))
115 ToErase.push_back(ConstMI);
116 }
117 }
118 }
119 for (MachineInstr *MI : ToErase)
120 MI->eraseFromParent();
121}
122
124 MachineIRBuilder MIB) {
125 // Get access to information about available extensions
126 const SPIRVSubtarget *ST =
127 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
129 for (MachineBasicBlock &MBB : MF) {
130 for (MachineInstr &MI : MBB) {
131 if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast) &&
132 !isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
133 continue;
134 assert(MI.getOperand(2).isReg());
135 MIB.setInsertPt(*MI.getParent(), MI);
136 ToErase.push_back(&MI);
137 if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
138 MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());
139 continue;
140 }
141 Register Def = MI.getOperand(0).getReg();
142 Register Source = MI.getOperand(2).getReg();
144 getMDOperandAsType(MI.getOperand(3).getMetadata(), 0), MIB);
145 SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
147 addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST));
148
149 // If the bitcast would be redundant, replace all uses with the source
150 // register.
151 if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) {
152 MIB.getMRI()->replaceRegWith(Def, Source);
153 } else {
154 GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
155 MIB.buildBitcast(Def, Source);
156 }
157 }
158 }
159 for (MachineInstr *MI : ToErase)
160 MI->eraseFromParent();
161}
162
163// Translating GV, IRTranslator sometimes generates following IR:
164// %1 = G_GLOBAL_VALUE
165// %2 = COPY %1
166// %3 = G_ADDRSPACE_CAST %2
167// New registers have no SPIRVType and no register class info.
168//
169// Set SPIRVType for GV, propagate it from GV to other instructions,
170// also set register classes.
173 MachineIRBuilder &MIB) {
174 SPIRVType *SpirvTy = nullptr;
175 assert(MI && "Machine instr is expected");
176 if (MI->getOperand(0).isReg()) {
177 Register Reg = MI->getOperand(0).getReg();
178 SpirvTy = GR->getSPIRVTypeForVReg(Reg);
179 if (!SpirvTy) {
180 switch (MI->getOpcode()) {
181 case TargetOpcode::G_CONSTANT: {
182 MIB.setInsertPt(*MI->getParent(), MI);
183 Type *Ty = MI->getOperand(1).getCImm()->getType();
184 SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);
185 break;
186 }
187 case TargetOpcode::G_GLOBAL_VALUE: {
188 MIB.setInsertPt(*MI->getParent(), MI);
189 Type *Ty = MI->getOperand(1).getGlobal()->getType();
190 SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);
191 break;
192 }
193 case TargetOpcode::G_TRUNC:
194 case TargetOpcode::G_ADDRSPACE_CAST:
195 case TargetOpcode::G_PTR_ADD:
196 case TargetOpcode::COPY: {
197 MachineOperand &Op = MI->getOperand(1);
198 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
199 if (Def)
200 SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB);
201 break;
202 }
203 default:
204 break;
205 }
206 if (SpirvTy)
207 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
208 if (!MRI.getRegClassOrNull(Reg))
209 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
210 }
211 }
212 return SpirvTy;
213}
214
215// Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as
216// a dst of the definition, assign SPIRVType to both registers. If SpirvTy is
217// provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty.
218// It's used also in SPIRVBuiltins.cpp.
219// TODO: maybe move to SPIRVUtils.
220namespace llvm {
224 MachineInstr *Def = MRI.getVRegDef(Reg);
225 assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected.");
226 MIB.setInsertPt(*Def->getParent(),
227 (Def->getNextNode() ? Def->getNextNode()->getIterator()
228 : Def->getParent()->end()));
229 Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg));
230 if (auto *RC = MRI.getRegClassOrNull(Reg)) {
231 MRI.setRegClass(NewReg, RC);
232 } else {
233 MRI.setRegClass(NewReg, &SPIRV::IDRegClass);
234 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
235 }
236 SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB);
237 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
238 // This is to make it convenient for Legalizer to get the SPIRVType
239 // when processing the actual MI (i.e. not pseudo one).
240 GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF());
241 // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep
242 // the flags after instruction selection.
243 const uint32_t Flags = Def->getFlags();
244 MIB.buildInstr(SPIRV::ASSIGN_TYPE)
245 .addDef(Reg)
246 .addUse(NewReg)
247 .addUse(GR->getSPIRVTypeID(SpirvTy))
248 .setMIFlags(Flags);
249 Def->getOperand(0).setReg(NewReg);
250 return NewReg;
251}
252} // namespace llvm
253
255 MachineIRBuilder MIB) {
256 // Get access to information about available extensions
257 const SPIRVSubtarget *ST =
258 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
259
262
263 for (MachineBasicBlock *MBB : post_order(&MF)) {
264 if (MBB->empty())
265 continue;
266
267 bool ReachedBegin = false;
268 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
269 !ReachedBegin;) {
270 MachineInstr &MI = *MII;
271
272 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
273 Register Reg = MI.getOperand(1).getReg();
274 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
276 getMDOperandAsType(MI.getOperand(2).getMetadata(), 0), MIB);
277 SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
279 addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));
280 MachineInstr *Def = MRI.getVRegDef(Reg);
281 assert(Def && "Expecting an instruction that defines the register");
282 insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,
283 MF.getRegInfo());
284 ToErase.push_back(&MI);
285 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
286 Register Reg = MI.getOperand(1).getReg();
287 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
288 MachineInstr *Def = MRI.getVRegDef(Reg);
289 assert(Def && "Expecting an instruction that defines the register");
290 // G_GLOBAL_VALUE already has type info.
291 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
292 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
293 ToErase.push_back(&MI);
294 } else if (MI.getOpcode() == TargetOpcode::G_CONSTANT ||
295 MI.getOpcode() == TargetOpcode::G_FCONSTANT ||
296 MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
297 // %rc = G_CONSTANT ty Val
298 // ===>
299 // %cty = OpType* ty
300 // %rctmp = G_CONSTANT ty Val
301 // %rc = ASSIGN_TYPE %rctmp, %cty
302 Register Reg = MI.getOperand(0).getReg();
303 if (MRI.hasOneUse(Reg)) {
304 MachineInstr &UseMI = *MRI.use_instr_begin(Reg);
305 if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) ||
306 isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name))
307 continue;
308 }
309 Type *Ty = nullptr;
310 if (MI.getOpcode() == TargetOpcode::G_CONSTANT)
311 Ty = MI.getOperand(1).getCImm()->getType();
312 else if (MI.getOpcode() == TargetOpcode::G_FCONSTANT)
313 Ty = MI.getOperand(1).getFPImm()->getType();
314 else {
315 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
316 Type *ElemTy = nullptr;
317 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
318 assert(ElemMI);
319
320 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT)
321 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
322 else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT)
323 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
324 else
325 llvm_unreachable("Unexpected opcode");
326 unsigned NumElts =
327 MI.getNumExplicitOperands() - MI.getNumExplicitDefs();
328 Ty = VectorType::get(ElemTy, NumElts, false);
329 }
330 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI);
331 } else if (MI.getOpcode() == TargetOpcode::G_TRUNC ||
332 MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
333 MI.getOpcode() == TargetOpcode::COPY ||
334 MI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) {
335 propagateSPIRVType(&MI, GR, MRI, MIB);
336 }
337
338 if (MII == Begin)
339 ReachedBegin = true;
340 else
341 --MII;
342 }
343 }
344 for (MachineInstr *MI : ToErase)
345 MI->eraseFromParent();
346}
347
348static std::pair<Register, unsigned>
350 const SPIRVGlobalRegistry &GR) {
351 LLT NewT = LLT::scalar(32);
352 SPIRVType *SpvType = GR.getSPIRVTypeForVReg(ValReg);
353 assert(SpvType && "VReg is expected to have SPIRV type");
354 bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat;
355 bool IsVectorFloat =
356 SpvType->getOpcode() == SPIRV::OpTypeVector &&
357 GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() ==
358 SPIRV::OpTypeFloat;
359 IsFloat |= IsVectorFloat;
360 auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID;
361 auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass;
362 if (MRI.getType(ValReg).isPointer()) {
363 NewT = LLT::pointer(0, 32);
364 GetIdOp = SPIRV::GET_pID;
365 DstClass = &SPIRV::pIDRegClass;
366 } else if (MRI.getType(ValReg).isVector()) {
367 NewT = LLT::fixed_vector(2, NewT);
368 GetIdOp = IsFloat ? SPIRV::GET_vfID : SPIRV::GET_vID;
369 DstClass = IsFloat ? &SPIRV::vfIDRegClass : &SPIRV::vIDRegClass;
370 }
371 Register IdReg = MRI.createGenericVirtualRegister(NewT);
372 MRI.setRegClass(IdReg, DstClass);
373 return {IdReg, GetIdOp};
374}
375
378 unsigned Opc = MI.getOpcode();
379 assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg()));
380 MachineInstr &AssignTypeInst =
381 *(MRI.use_instr_begin(MI.getOperand(0).getReg()));
382 auto NewReg = createNewIdReg(MI.getOperand(0).getReg(), Opc, MRI, *GR).first;
383 AssignTypeInst.getOperand(1).setReg(NewReg);
384 MI.getOperand(0).setReg(NewReg);
385 MIB.setInsertPt(*MI.getParent(),
386 (MI.getNextNode() ? MI.getNextNode()->getIterator()
387 : MI.getParent()->end()));
388 for (auto &Op : MI.operands()) {
389 if (!Op.isReg() || Op.isDef())
390 continue;
391 auto IdOpInfo = createNewIdReg(Op.getReg(), Opc, MRI, *GR);
392 MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg());
393 Op.setReg(IdOpInfo.first);
394 }
395}
396
397// Defined in SPIRVLegalizerInfo.cpp.
398extern bool isTypeFoldingSupported(unsigned Opcode);
399
402 MachineIRBuilder MIB) {
404 for (MachineBasicBlock &MBB : MF) {
405 for (MachineInstr &MI : MBB) {
406 if (isTypeFoldingSupported(MI.getOpcode()))
407 processInstr(MI, MIB, MRI, GR);
408 }
409 }
410 for (MachineBasicBlock &MBB : MF) {
411 for (MachineInstr &MI : MBB) {
412 // We need to rewrite dst types for ASSIGN_TYPE instrs to be able
413 // to perform tblgen'erated selection and we can't do that on Legalizer
414 // as it operates on gMIR only.
415 if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)
416 continue;
417 Register SrcReg = MI.getOperand(1).getReg();
418 unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode();
419 if (!isTypeFoldingSupported(Opcode))
420 continue;
421 Register DstReg = MI.getOperand(0).getReg();
422 if (MRI.getType(DstReg).isVector())
423 MRI.setRegClass(DstReg, &SPIRV::IDRegClass);
424 // Don't need to reset type of register holding constant and used in
425 // G_ADDRSPACE_CAST, since it braaks legalizer.
426 if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) {
427 MachineInstr &UseMI = *MRI.use_instr_begin(DstReg);
428 if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST)
429 continue;
430 }
431 MRI.setType(DstReg, LLT::scalar(32));
432 }
433 }
434}
435
437 MachineIRBuilder MIB) {
438 // Before IRTranslator pass, calls to spv_switch intrinsic are inserted before
439 // each switch instruction. IRTranslator lowers switches to G_ICMP + G_BRCOND
440 // + G_BR triples. A switch with two cases may be transformed to this MIR
441 // sequence:
442 //
443 // intrinsic(@llvm.spv.switch), %CmpReg, %Const0, %Const1
444 // %Dst0 = G_ICMP intpred(eq), %CmpReg, %Const0
445 // G_BRCOND %Dst0, %bb.2
446 // G_BR %bb.5
447 // bb.5.entry:
448 // %Dst1 = G_ICMP intpred(eq), %CmpReg, %Const1
449 // G_BRCOND %Dst1, %bb.3
450 // G_BR %bb.4
451 // bb.2.sw.bb:
452 // ...
453 // bb.3.sw.bb1:
454 // ...
455 // bb.4.sw.epilog:
456 // ...
457 //
458 // Sometimes (in case of range-compare switches), additional G_SUBs
459 // instructions are inserted before G_ICMPs. Those need to be additionally
460 // processed.
461 //
462 // This function modifies spv_switch call's operands to include destination
463 // MBBs (default and for each constant value).
464 //
465 // At the end, the function removes redundant [G_SUB] + G_ICMP + G_BRCOND +
466 // G_BR sequences.
467
469
470 // Collect spv_switches and G_ICMPs across all MBBs in MF.
471 std::vector<MachineInstr *> RelevantInsts;
472
473 // Collect redundant MIs from [G_SUB] + G_ICMP + G_BRCOND + G_BR sequences.
474 // After updating spv_switches, the instructions can be removed.
475 std::vector<MachineInstr *> PostUpdateArtifacts;
476
477 // Temporary set of compare registers. G_SUBs and G_ICMPs relating to
478 // spv_switch use these registers.
479 DenseSet<Register> CompareRegs;
480 for (MachineBasicBlock &MBB : MF) {
481 for (MachineInstr &MI : MBB) {
482 // Calls to spv_switch intrinsics representing IR switches.
483 if (isSpvIntrinsic(MI, Intrinsic::spv_switch)) {
484 assert(MI.getOperand(1).isReg());
485 CompareRegs.insert(MI.getOperand(1).getReg());
486 RelevantInsts.push_back(&MI);
487 }
488
489 // G_SUBs coming from range-compare switch lowering. G_SUBs are found
490 // after spv_switch but before G_ICMP.
491 if (MI.getOpcode() == TargetOpcode::G_SUB && MI.getOperand(1).isReg() &&
492 CompareRegs.contains(MI.getOperand(1).getReg())) {
493 assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg());
494 Register Dst = MI.getOperand(0).getReg();
495 CompareRegs.insert(Dst);
496 PostUpdateArtifacts.push_back(&MI);
497 }
498
499 // G_ICMPs relating to switches.
500 if (MI.getOpcode() == TargetOpcode::G_ICMP && MI.getOperand(2).isReg() &&
501 CompareRegs.contains(MI.getOperand(2).getReg())) {
502 Register Dst = MI.getOperand(0).getReg();
503 RelevantInsts.push_back(&MI);
504 PostUpdateArtifacts.push_back(&MI);
505 MachineInstr *CBr = MRI.use_begin(Dst)->getParent();
506 assert(CBr->getOpcode() == SPIRV::G_BRCOND);
507 PostUpdateArtifacts.push_back(CBr);
508 MachineInstr *Br = CBr->getNextNode();
509 assert(Br->getOpcode() == SPIRV::G_BR);
510 PostUpdateArtifacts.push_back(Br);
511 }
512 }
513 }
514
515 // Update each spv_switch with destination MBBs.
516 for (auto i = RelevantInsts.begin(); i != RelevantInsts.end(); i++) {
517 if (!isSpvIntrinsic(**i, Intrinsic::spv_switch))
518 continue;
519
520 // Currently considered spv_switch.
521 MachineInstr *Switch = *i;
522 // Set the first successor as default MBB to support empty switches.
523 MachineBasicBlock *DefaultMBB = *Switch->getParent()->succ_begin();
524 // Container for mapping values to MMBs.
526
527 // Walk all G_ICMPs to collect ValuesToMBBs. Start at currently considered
528 // spv_switch (i) and break at any spv_switch with the same compare
529 // register (indicating we are back at the same scope).
530 Register CompareReg = Switch->getOperand(1).getReg();
531 for (auto j = i + 1; j != RelevantInsts.end(); j++) {
532 if (isSpvIntrinsic(**j, Intrinsic::spv_switch) &&
533 (*j)->getOperand(1).getReg() == CompareReg)
534 break;
535
536 if (!((*j)->getOpcode() == TargetOpcode::G_ICMP &&
537 (*j)->getOperand(2).getReg() == CompareReg))
538 continue;
539
540 MachineInstr *ICMP = *j;
541 Register Dst = ICMP->getOperand(0).getReg();
542 MachineOperand &PredOp = ICMP->getOperand(1);
543 const auto CC = static_cast<CmpInst::Predicate>(PredOp.getPredicate());
545 MRI.hasOneUse(Dst) && MRI.hasOneDef(CompareReg));
546 uint64_t Value = getIConstVal(ICMP->getOperand(3).getReg(), &MRI);
547 MachineInstr *CBr = MRI.use_begin(Dst)->getParent();
548 assert(CBr->getOpcode() == SPIRV::G_BRCOND && CBr->getOperand(1).isMBB());
550
551 // Map switch case Value to target MBB.
552 ValuesToMBBs[Value] = MBB;
553
554 // Add target MBB as successor to the switch's MBB.
555 Switch->getParent()->addSuccessor(MBB);
556
557 // The next MI is always G_BR to either the next case or the default.
558 MachineInstr *NextMI = CBr->getNextNode();
559 assert(NextMI->getOpcode() == SPIRV::G_BR &&
560 NextMI->getOperand(0).isMBB());
561 MachineBasicBlock *NextMBB = NextMI->getOperand(0).getMBB();
562 // Default MBB does not begin with G_ICMP using spv_switch compare
563 // register.
564 if (NextMBB->front().getOpcode() != SPIRV::G_ICMP ||
565 (NextMBB->front().getOperand(2).isReg() &&
566 NextMBB->front().getOperand(2).getReg() != CompareReg)) {
567 // Set default MBB and add it as successor to the switch's MBB.
568 DefaultMBB = NextMBB;
569 Switch->getParent()->addSuccessor(DefaultMBB);
570 }
571 }
572
573 // Modify considered spv_switch operands using collected Values and
574 // MBBs.
577 for (unsigned k = 2; k < Switch->getNumExplicitOperands(); k++) {
578 Register CReg = Switch->getOperand(k).getReg();
579 uint64_t Val = getIConstVal(CReg, &MRI);
580 MachineInstr *ConstInstr = getDefInstrMaybeConstant(CReg, &MRI);
581 if (!ValuesToMBBs[Val])
582 continue;
583
584 Values.push_back(ConstInstr->getOperand(1).getCImm());
585 MBBs.push_back(ValuesToMBBs[Val]);
586 }
587
588 for (unsigned k = Switch->getNumExplicitOperands() - 1; k > 1; k--)
589 Switch->removeOperand(k);
590
591 Switch->addOperand(MachineOperand::CreateMBB(DefaultMBB));
592 for (unsigned k = 0; k < Values.size(); k++) {
593 Switch->addOperand(MachineOperand::CreateCImm(Values[k]));
594 Switch->addOperand(MachineOperand::CreateMBB(MBBs[k]));
595 }
596 }
597
598 for (MachineInstr *MI : PostUpdateArtifacts) {
599 MachineBasicBlock *ParentMBB = MI->getParent();
600 MI->eraseFromParent();
601 // If G_ICMP + G_BRCOND + G_BR were the only MIs in MBB, erase this MBB. It
602 // can be safely assumed, there are no breaks or phis directing into this
603 // MBB. However, we need to remove this MBB from the CFG graph. MBBs must be
604 // erased top-down.
605 if (ParentMBB->empty()) {
606 while (!ParentMBB->pred_empty())
607 (*ParentMBB->pred_begin())->removeSuccessor(ParentMBB);
608
609 while (!ParentMBB->succ_empty())
610 ParentMBB->removeSuccessor(ParentMBB->succ_begin());
611
612 ParentMBB->eraseFromParent();
613 }
614 }
615}
616
618 if (MBB.empty())
619 return true;
620
621 // Branching SPIR-V intrinsics are not detected by this generic method.
622 // Thus, we can only trust negative result.
623 if (!MBB.canFallThrough())
624 return false;
625
626 // Otherwise, we must manually check if we have a SPIR-V intrinsic which
627 // prevent an implicit fallthrough.
629 It != E; ++It) {
630 if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
631 return false;
632 }
633 return true;
634}
635
637 MachineIRBuilder MIB) {
638 // It is valid for MachineBasicBlocks to not finish with a branch instruction.
639 // In such cases, they will simply fallthrough their immediate successor.
640 for (MachineBasicBlock &MBB : MF) {
642 continue;
643
644 assert(std::distance(MBB.successors().begin(), MBB.successors().end()) ==
645 1);
646 MIB.setInsertPt(MBB, MBB.end());
647 MIB.buildBr(**MBB.successors().begin());
648 }
649}
650
651bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
652 // Initialize the type registry.
654 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
655 GR->setCurrentFunc(MF);
656 MachineIRBuilder MIB(MF);
657 addConstantsToTrack(MF, GR);
659 insertBitcasts(MF, GR, MIB);
660 generateAssignInstrs(MF, GR, MIB);
661 processSwitches(MF, GR, MIB);
662 processInstrsWithTypeFolding(MF, GR, MIB);
664
665 return true;
666}
667
668INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,
669 false)
670
671char SPIRVPreLegalizer::ID = 0;
672
674 return new SPIRVPreLegalizer();
675}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineBasicBlock & MBB
This file contains the simple types necessary to represent the attributes associated with functions a...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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 processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR)
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 std::pair< Register, unsigned > createNewIdReg(Register ValReg, unsigned Opcode, MachineRegisterInfo &MRI, const SPIRVGlobalRegistry &GR)
static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR)
#define DEBUG_TYPE
static void foldConstantsIntoIntrinsics(MachineFunction &MF)
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition: InstrTypes.h:967
@ ICMP_EQ
equal
Definition: InstrTypes.h:988
@ ICMP_ULE
unsigned less or equal
Definition: InstrTypes.h:993
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:153
This class represents an Operation in the Expression.
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
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
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:49
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:92
reverse_iterator rend()
bool canFallThrough()
Return true if the block can implicitly transfer control to the block after it by falling off the end...
void removeSuccessor(MachineBasicBlock *Succ, bool NormalizeSuccProbs=false)
Remove successor from the successors list of this MachineBasicBlock.
void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
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:544
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:554
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
static MachineOperand CreateCImm(const ConstantInt *CI)
void setReg(Register Reg)
Change the register this operand corresponds to.
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
unsigned getPredicate() const
static MachineOperand CreateMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0)
bool isMBB() const
isMBB - Tests if this is a MO_MachineBasicBlock operand.
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
void add(const Constant *C, MachineFunction *MF, Register R)
SPIRVType * getSPIRVTypeForVReg(Register VReg) const
Register find(const Constant *C, MachineFunction *MF)
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 * getOrCreateSPIRVPointerType(SPIRVType *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SClass=SPIRV::StorageClass::Function)
const SPIRVInstrInfo * getInstrInfo() const override
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
LLVM Value Representation.
Definition: Value.h:74
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition: DenseSet.h:185
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition: ilist_node.h:316
#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)
uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI)
Definition: SPIRVUtils.cpp:241
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
Definition: SPIRVUtils.cpp:162
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