LLVM 18.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.find(MI) != RegsAlreadyAddedToDT.end())
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) {
126 for (MachineBasicBlock &MBB : MF) {
127 for (MachineInstr &MI : MBB) {
128 if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast))
129 continue;
130 assert(MI.getOperand(2).isReg());
131 MIB.setInsertPt(*MI.getParent(), MI);
132 MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());
133 ToErase.push_back(&MI);
134 }
135 }
136 for (MachineInstr *MI : ToErase)
137 MI->eraseFromParent();
138}
139
140// Translating GV, IRTranslator sometimes generates following IR:
141// %1 = G_GLOBAL_VALUE
142// %2 = COPY %1
143// %3 = G_ADDRSPACE_CAST %2
144// New registers have no SPIRVType and no register class info.
145//
146// Set SPIRVType for GV, propagate it from GV to other instructions,
147// also set register classes.
150 MachineIRBuilder &MIB) {
151 SPIRVType *SpirvTy = nullptr;
152 assert(MI && "Machine instr is expected");
153 if (MI->getOperand(0).isReg()) {
154 Register Reg = MI->getOperand(0).getReg();
155 SpirvTy = GR->getSPIRVTypeForVReg(Reg);
156 if (!SpirvTy) {
157 switch (MI->getOpcode()) {
158 case TargetOpcode::G_CONSTANT: {
159 MIB.setInsertPt(*MI->getParent(), MI);
160 Type *Ty = MI->getOperand(1).getCImm()->getType();
161 SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);
162 break;
163 }
164 case TargetOpcode::G_GLOBAL_VALUE: {
165 MIB.setInsertPt(*MI->getParent(), MI);
166 Type *Ty = MI->getOperand(1).getGlobal()->getType();
167 SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);
168 break;
169 }
170 case TargetOpcode::G_TRUNC:
171 case TargetOpcode::G_ADDRSPACE_CAST:
172 case TargetOpcode::G_PTR_ADD:
173 case TargetOpcode::COPY: {
174 MachineOperand &Op = MI->getOperand(1);
175 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
176 if (Def)
177 SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB);
178 break;
179 }
180 default:
181 break;
182 }
183 if (SpirvTy)
184 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
185 if (!MRI.getRegClassOrNull(Reg))
186 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
187 }
188 }
189 return SpirvTy;
190}
191
192// Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as
193// a dst of the definition, assign SPIRVType to both registers. If SpirvTy is
194// provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty.
195// It's used also in SPIRVBuiltins.cpp.
196// TODO: maybe move to SPIRVUtils.
197namespace llvm {
201 MachineInstr *Def = MRI.getVRegDef(Reg);
202 assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected.");
203 MIB.setInsertPt(*Def->getParent(),
204 (Def->getNextNode() ? Def->getNextNode()->getIterator()
205 : Def->getParent()->end()));
206 Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg));
207 if (auto *RC = MRI.getRegClassOrNull(Reg)) {
208 MRI.setRegClass(NewReg, RC);
209 } else {
210 MRI.setRegClass(NewReg, &SPIRV::IDRegClass);
211 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
212 }
213 SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB);
214 GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
215 // This is to make it convenient for Legalizer to get the SPIRVType
216 // when processing the actual MI (i.e. not pseudo one).
217 GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF());
218 // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep
219 // the flags after instruction selection.
220 const uint32_t Flags = Def->getFlags();
221 MIB.buildInstr(SPIRV::ASSIGN_TYPE)
222 .addDef(Reg)
223 .addUse(NewReg)
224 .addUse(GR->getSPIRVTypeID(SpirvTy))
225 .setMIFlags(Flags);
226 Def->getOperand(0).setReg(NewReg);
227 return NewReg;
228}
229} // namespace llvm
230
232 MachineIRBuilder MIB) {
235
236 for (MachineBasicBlock *MBB : post_order(&MF)) {
237 if (MBB->empty())
238 continue;
239
240 bool ReachedBegin = false;
241 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
242 !ReachedBegin;) {
243 MachineInstr &MI = *MII;
244
245 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
246 Register Reg = MI.getOperand(1).getReg();
247 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
249 getMDOperandAsType(MI.getOperand(2).getMetadata(), 0), MIB);
250 SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
252 addressSpaceToStorageClass(MI.getOperand(3).getImm()));
253 MachineInstr *Def = MRI.getVRegDef(Reg);
254 assert(Def && "Expecting an instruction that defines the register");
255 insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,
256 MF.getRegInfo());
257 ToErase.push_back(&MI);
258 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
259 Register Reg = MI.getOperand(1).getReg();
260 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
261 MachineInstr *Def = MRI.getVRegDef(Reg);
262 assert(Def && "Expecting an instruction that defines the register");
263 // G_GLOBAL_VALUE already has type info.
264 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
265 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
266 ToErase.push_back(&MI);
267 } else if (MI.getOpcode() == TargetOpcode::G_CONSTANT ||
268 MI.getOpcode() == TargetOpcode::G_FCONSTANT ||
269 MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
270 // %rc = G_CONSTANT ty Val
271 // ===>
272 // %cty = OpType* ty
273 // %rctmp = G_CONSTANT ty Val
274 // %rc = ASSIGN_TYPE %rctmp, %cty
275 Register Reg = MI.getOperand(0).getReg();
276 if (MRI.hasOneUse(Reg)) {
277 MachineInstr &UseMI = *MRI.use_instr_begin(Reg);
278 if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) ||
279 isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name))
280 continue;
281 }
282 Type *Ty = nullptr;
283 if (MI.getOpcode() == TargetOpcode::G_CONSTANT)
284 Ty = MI.getOperand(1).getCImm()->getType();
285 else if (MI.getOpcode() == TargetOpcode::G_FCONSTANT)
286 Ty = MI.getOperand(1).getFPImm()->getType();
287 else {
288 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
289 Type *ElemTy = nullptr;
290 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
291 assert(ElemMI);
292
293 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT)
294 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
295 else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT)
296 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
297 else
298 llvm_unreachable("Unexpected opcode");
299 unsigned NumElts =
300 MI.getNumExplicitOperands() - MI.getNumExplicitDefs();
301 Ty = VectorType::get(ElemTy, NumElts, false);
302 }
303 insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI);
304 } else if (MI.getOpcode() == TargetOpcode::G_TRUNC ||
305 MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
306 MI.getOpcode() == TargetOpcode::COPY ||
307 MI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) {
308 propagateSPIRVType(&MI, GR, MRI, MIB);
309 }
310
311 if (MII == Begin)
312 ReachedBegin = true;
313 else
314 --MII;
315 }
316 }
317 for (MachineInstr *MI : ToErase)
318 MI->eraseFromParent();
319}
320
321static std::pair<Register, unsigned>
323 const SPIRVGlobalRegistry &GR) {
324 LLT NewT = LLT::scalar(32);
325 SPIRVType *SpvType = GR.getSPIRVTypeForVReg(ValReg);
326 assert(SpvType && "VReg is expected to have SPIRV type");
327 bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat;
328 bool IsVectorFloat =
329 SpvType->getOpcode() == SPIRV::OpTypeVector &&
330 GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() ==
331 SPIRV::OpTypeFloat;
332 IsFloat |= IsVectorFloat;
333 auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID;
334 auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass;
335 if (MRI.getType(ValReg).isPointer()) {
336 NewT = LLT::pointer(0, 32);
337 GetIdOp = SPIRV::GET_pID;
338 DstClass = &SPIRV::pIDRegClass;
339 } else if (MRI.getType(ValReg).isVector()) {
340 NewT = LLT::fixed_vector(2, NewT);
341 GetIdOp = IsFloat ? SPIRV::GET_vfID : SPIRV::GET_vID;
342 DstClass = IsFloat ? &SPIRV::vfIDRegClass : &SPIRV::vIDRegClass;
343 }
344 Register IdReg = MRI.createGenericVirtualRegister(NewT);
345 MRI.setRegClass(IdReg, DstClass);
346 return {IdReg, GetIdOp};
347}
348
351 unsigned Opc = MI.getOpcode();
352 assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg()));
353 MachineInstr &AssignTypeInst =
354 *(MRI.use_instr_begin(MI.getOperand(0).getReg()));
355 auto NewReg = createNewIdReg(MI.getOperand(0).getReg(), Opc, MRI, *GR).first;
356 AssignTypeInst.getOperand(1).setReg(NewReg);
357 MI.getOperand(0).setReg(NewReg);
358 MIB.setInsertPt(*MI.getParent(),
359 (MI.getNextNode() ? MI.getNextNode()->getIterator()
360 : MI.getParent()->end()));
361 for (auto &Op : MI.operands()) {
362 if (!Op.isReg() || Op.isDef())
363 continue;
364 auto IdOpInfo = createNewIdReg(Op.getReg(), Opc, MRI, *GR);
365 MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg());
366 Op.setReg(IdOpInfo.first);
367 }
368}
369
370// Defined in SPIRVLegalizerInfo.cpp.
371extern bool isTypeFoldingSupported(unsigned Opcode);
372
375 MachineIRBuilder MIB) {
377 for (MachineBasicBlock &MBB : MF) {
378 for (MachineInstr &MI : MBB) {
379 if (isTypeFoldingSupported(MI.getOpcode()))
380 processInstr(MI, MIB, MRI, GR);
381 }
382 }
383 for (MachineBasicBlock &MBB : MF) {
384 for (MachineInstr &MI : MBB) {
385 // We need to rewrite dst types for ASSIGN_TYPE instrs to be able
386 // to perform tblgen'erated selection and we can't do that on Legalizer
387 // as it operates on gMIR only.
388 if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)
389 continue;
390 Register SrcReg = MI.getOperand(1).getReg();
391 unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode();
392 if (!isTypeFoldingSupported(Opcode))
393 continue;
394 Register DstReg = MI.getOperand(0).getReg();
395 if (MRI.getType(DstReg).isVector())
396 MRI.setRegClass(DstReg, &SPIRV::IDRegClass);
397 // Don't need to reset type of register holding constant and used in
398 // G_ADDRSPACE_CAST, since it braaks legalizer.
399 if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) {
400 MachineInstr &UseMI = *MRI.use_instr_begin(DstReg);
401 if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST)
402 continue;
403 }
404 MRI.setType(DstReg, LLT::scalar(32));
405 }
406 }
407}
408
410 MachineIRBuilder MIB) {
411 // Before IRTranslator pass, calls to spv_switch intrinsic are inserted before
412 // each switch instruction. IRTranslator lowers switches to G_ICMP + G_BRCOND
413 // + G_BR triples. A switch with two cases may be transformed to this MIR
414 // sequence:
415 //
416 // intrinsic(@llvm.spv.switch), %CmpReg, %Const0, %Const1
417 // %Dst0 = G_ICMP intpred(eq), %CmpReg, %Const0
418 // G_BRCOND %Dst0, %bb.2
419 // G_BR %bb.5
420 // bb.5.entry:
421 // %Dst1 = G_ICMP intpred(eq), %CmpReg, %Const1
422 // G_BRCOND %Dst1, %bb.3
423 // G_BR %bb.4
424 // bb.2.sw.bb:
425 // ...
426 // bb.3.sw.bb1:
427 // ...
428 // bb.4.sw.epilog:
429 // ...
430 //
431 // Sometimes (in case of range-compare switches), additional G_SUBs
432 // instructions are inserted before G_ICMPs. Those need to be additionally
433 // processed.
434 //
435 // This function modifies spv_switch call's operands to include destination
436 // MBBs (default and for each constant value).
437 //
438 // At the end, the function removes redundant [G_SUB] + G_ICMP + G_BRCOND +
439 // G_BR sequences.
440
442
443 // Collect spv_switches and G_ICMPs across all MBBs in MF.
444 std::vector<MachineInstr *> RelevantInsts;
445
446 // Collect redundant MIs from [G_SUB] + G_ICMP + G_BRCOND + G_BR sequences.
447 // After updating spv_switches, the instructions can be removed.
448 std::vector<MachineInstr *> PostUpdateArtifacts;
449
450 // Temporary set of compare registers. G_SUBs and G_ICMPs relating to
451 // spv_switch use these registers.
452 DenseSet<Register> CompareRegs;
453 for (MachineBasicBlock &MBB : MF) {
454 for (MachineInstr &MI : MBB) {
455 // Calls to spv_switch intrinsics representing IR switches.
456 if (isSpvIntrinsic(MI, Intrinsic::spv_switch)) {
457 assert(MI.getOperand(1).isReg());
458 CompareRegs.insert(MI.getOperand(1).getReg());
459 RelevantInsts.push_back(&MI);
460 }
461
462 // G_SUBs coming from range-compare switch lowering. G_SUBs are found
463 // after spv_switch but before G_ICMP.
464 if (MI.getOpcode() == TargetOpcode::G_SUB && MI.getOperand(1).isReg() &&
465 CompareRegs.contains(MI.getOperand(1).getReg())) {
466 assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg());
467 Register Dst = MI.getOperand(0).getReg();
468 CompareRegs.insert(Dst);
469 PostUpdateArtifacts.push_back(&MI);
470 }
471
472 // G_ICMPs relating to switches.
473 if (MI.getOpcode() == TargetOpcode::G_ICMP && MI.getOperand(2).isReg() &&
474 CompareRegs.contains(MI.getOperand(2).getReg())) {
475 Register Dst = MI.getOperand(0).getReg();
476 RelevantInsts.push_back(&MI);
477 PostUpdateArtifacts.push_back(&MI);
478 MachineInstr *CBr = MRI.use_begin(Dst)->getParent();
479 assert(CBr->getOpcode() == SPIRV::G_BRCOND);
480 PostUpdateArtifacts.push_back(CBr);
481 MachineInstr *Br = CBr->getNextNode();
482 assert(Br->getOpcode() == SPIRV::G_BR);
483 PostUpdateArtifacts.push_back(Br);
484 }
485 }
486 }
487
488 // Update each spv_switch with destination MBBs.
489 for (auto i = RelevantInsts.begin(); i != RelevantInsts.end(); i++) {
490 if (!isSpvIntrinsic(**i, Intrinsic::spv_switch))
491 continue;
492
493 // Currently considered spv_switch.
494 MachineInstr *Switch = *i;
495 // Set the first successor as default MBB to support empty switches.
496 MachineBasicBlock *DefaultMBB = *Switch->getParent()->succ_begin();
497 // Container for mapping values to MMBs.
499
500 // Walk all G_ICMPs to collect ValuesToMBBs. Start at currently considered
501 // spv_switch (i) and break at any spv_switch with the same compare
502 // register (indicating we are back at the same scope).
503 Register CompareReg = Switch->getOperand(1).getReg();
504 for (auto j = i + 1; j != RelevantInsts.end(); j++) {
505 if (isSpvIntrinsic(**j, Intrinsic::spv_switch) &&
506 (*j)->getOperand(1).getReg() == CompareReg)
507 break;
508
509 if (!((*j)->getOpcode() == TargetOpcode::G_ICMP &&
510 (*j)->getOperand(2).getReg() == CompareReg))
511 continue;
512
513 MachineInstr *ICMP = *j;
514 Register Dst = ICMP->getOperand(0).getReg();
515 MachineOperand &PredOp = ICMP->getOperand(1);
516 const auto CC = static_cast<CmpInst::Predicate>(PredOp.getPredicate());
518 MRI.hasOneUse(Dst) && MRI.hasOneDef(CompareReg));
519 uint64_t Value = getIConstVal(ICMP->getOperand(3).getReg(), &MRI);
520 MachineInstr *CBr = MRI.use_begin(Dst)->getParent();
521 assert(CBr->getOpcode() == SPIRV::G_BRCOND && CBr->getOperand(1).isMBB());
523
524 // Map switch case Value to target MBB.
525 ValuesToMBBs[Value] = MBB;
526
527 // Add target MBB as successor to the switch's MBB.
528 Switch->getParent()->addSuccessor(MBB);
529
530 // The next MI is always G_BR to either the next case or the default.
531 MachineInstr *NextMI = CBr->getNextNode();
532 assert(NextMI->getOpcode() == SPIRV::G_BR &&
533 NextMI->getOperand(0).isMBB());
534 MachineBasicBlock *NextMBB = NextMI->getOperand(0).getMBB();
535 // Default MBB does not begin with G_ICMP using spv_switch compare
536 // register.
537 if (NextMBB->front().getOpcode() != SPIRV::G_ICMP ||
538 (NextMBB->front().getOperand(2).isReg() &&
539 NextMBB->front().getOperand(2).getReg() != CompareReg)) {
540 // Set default MBB and add it as successor to the switch's MBB.
541 DefaultMBB = NextMBB;
542 Switch->getParent()->addSuccessor(DefaultMBB);
543 }
544 }
545
546 // Modify considered spv_switch operands using collected Values and
547 // MBBs.
550 for (unsigned k = 2; k < Switch->getNumExplicitOperands(); k++) {
551 Register CReg = Switch->getOperand(k).getReg();
552 uint64_t Val = getIConstVal(CReg, &MRI);
553 MachineInstr *ConstInstr = getDefInstrMaybeConstant(CReg, &MRI);
554 if (!ValuesToMBBs[Val])
555 continue;
556
557 Values.push_back(ConstInstr->getOperand(1).getCImm());
558 MBBs.push_back(ValuesToMBBs[Val]);
559 }
560
561 for (unsigned k = Switch->getNumExplicitOperands() - 1; k > 1; k--)
562 Switch->removeOperand(k);
563
564 Switch->addOperand(MachineOperand::CreateMBB(DefaultMBB));
565 for (unsigned k = 0; k < Values.size(); k++) {
566 Switch->addOperand(MachineOperand::CreateCImm(Values[k]));
567 Switch->addOperand(MachineOperand::CreateMBB(MBBs[k]));
568 }
569 }
570
571 for (MachineInstr *MI : PostUpdateArtifacts) {
572 MachineBasicBlock *ParentMBB = MI->getParent();
573 MI->eraseFromParent();
574 // If G_ICMP + G_BRCOND + G_BR were the only MIs in MBB, erase this MBB. It
575 // can be safely assumed, there are no breaks or phis directing into this
576 // MBB. However, we need to remove this MBB from the CFG graph. MBBs must be
577 // erased top-down.
578 if (ParentMBB->empty()) {
579 while (!ParentMBB->pred_empty())
580 (*ParentMBB->pred_begin())->removeSuccessor(ParentMBB);
581
582 while (!ParentMBB->succ_empty())
583 ParentMBB->removeSuccessor(ParentMBB->succ_begin());
584
585 ParentMBB->eraseFromParent();
586 }
587 }
588}
589
590bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
591 // Initialize the type registry.
593 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
594 GR->setCurrentFunc(MF);
595 MachineIRBuilder MIB(MF);
596 addConstantsToTrack(MF, GR);
598 insertBitcasts(MF, GR, MIB);
599 generateAssignInstrs(MF, GR, MIB);
600 processSwitches(MF, GR, MIB);
601 processInstrsWithTypeFolding(MF, GR, MIB);
602
603 return true;
604}
605
606INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,
607 false)
608
609char SPIRVPreLegalizer::ID = 0;
610
612 return new SPIRVPreLegalizer();
613}
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())
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:711
@ ICMP_EQ
equal
Definition: InstrTypes.h:732
@ ICMP_ULE
unsigned less or equal
Definition: InstrTypes.h:737
IntegerType * getType() const
getType - Specialize the getType() method to always return an IntegerType, which reduces the amount o...
Definition: Constants.h:176
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:145
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
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
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.
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.
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.
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.
Representation of each machine instruction.
Definition: MachineInstr.h:68
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:543
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:553
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,...
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:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
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:289
#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:225
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace)
Definition: SPIRVUtils.cpp:154
bool isSpvIntrinsic(MachineInstr &MI, Intrinsic::ID IntrinsicID)
Definition: SPIRVUtils.cpp:231
MachineInstr * getDefInstrMaybeConstant(Register &ConstReg, const MachineRegisterInfo *MRI)
Definition: SPIRVUtils.cpp:210
Type * getMDOperandAsType(const MDNode *N, unsigned I)
Definition: SPIRVUtils.cpp:237
void initializeSPIRVPreLegalizerPass(PassRegistry &)