LLVM 23.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"
21#include "llvm/IR/Attributes.h"
22#include "llvm/IR/Constants.h"
23#include "llvm/IR/IntrinsicsSPIRV.h"
24
25#define DEBUG_TYPE "spirv-prelegalizer"
26
27using namespace llvm;
28
29namespace {
30class SPIRVPreLegalizer : public MachineFunctionPass {
31public:
32 static char ID;
33 SPIRVPreLegalizer() : MachineFunctionPass(ID) {}
34 bool runOnMachineFunction(MachineFunction &MF) override;
35 void getAnalysisUsage(AnalysisUsage &AU) const override;
36};
37} // namespace
38
39void SPIRVPreLegalizer::getAnalysisUsage(AnalysisUsage &AU) const {
40 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
42}
43
47 MI->eraseFromParent();
48}
49
50static void
52 const SPIRVSubtarget &STI,
53 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
55 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
56 SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites;
57 for (MachineBasicBlock &MBB : MF) {
58 for (MachineInstr &MI : MBB) {
59 if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant))
60 continue;
61 ToErase.push_back(&MI);
62 Register SrcReg = MI.getOperand(2).getReg();
63 auto *Const =
65 MI.getOperand(3).getMetadata()->getOperand(0))
66 ->getValue());
67 if (auto *GV = dyn_cast<GlobalValue>(Const)) {
68 Register Reg = GR->find(GV, &MF);
69 if (!Reg.isValid()) {
70 GR->add(GV, MRI.getVRegDef(SrcReg));
71 GR->addGlobalObject(GV, &MF, SrcReg);
72 } else
73 RegsAlreadyAddedToDT[&MI] = Reg;
74 } else {
75 Register Reg = GR->find(Const, &MF);
76 if (!Reg.isValid()) {
77 if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) {
78 auto *BuildVec = MRI.getVRegDef(SrcReg);
79 assert(BuildVec &&
80 BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
81 GR->add(Const, BuildVec);
82 for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) {
83 // Ensure that OpConstantComposite reuses a constant when it's
84 // already created and available in the same machine function.
85 Constant *ElemConst = ConstVec->getElementAsConstant(i);
86 Register ElemReg = GR->find(ElemConst, &MF);
87 if (!ElemReg.isValid())
88 GR->add(ElemConst,
89 MRI.getVRegDef(BuildVec->getOperand(1 + i).getReg()));
90 else
91 BuildVec->getOperand(1 + i).setReg(ElemReg);
92 }
93 }
94 if (Const->getType()->isTargetExtTy()) {
95 // remember association so that we can restore it when assign types
96 MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);
97 if (SrcMI)
98 GR->add(Const, SrcMI);
99 if (SrcMI && (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT ||
100 SrcMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF))
101 TargetExtConstTypes[SrcMI] = Const->getType();
102 if (Const->isNullValue()) {
103 MachineBasicBlock &DepMBB = MF.front();
104 MachineIRBuilder MIB(DepMBB, DepMBB.getFirstNonPHI());
106 Const->getType(), MIB, SPIRV::AccessQualifier::ReadWrite,
107 true);
108 assert(SrcMI && "Expected source instruction to be valid");
109 SrcMI->setDesc(STI.getInstrInfo()->get(SPIRV::OpConstantNull));
111 GR->getSPIRVTypeID(ExtType), false));
112 }
113 }
114 } else {
115 RegsAlreadyAddedToDT[&MI] = Reg;
116 // This MI is unused and will be removed. If the MI uses
117 // const_composite, it will be unused and should be removed too.
118 assert(MI.getOperand(2).isReg() && "Reg operand is expected");
119 MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg());
120 if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))
121 ToEraseComposites.push_back(SrcMI);
122 }
123 }
124 }
125 }
126 for (MachineInstr *MI : ToErase) {
127 Register Reg = MI->getOperand(2).getReg();
128 auto It = RegsAlreadyAddedToDT.find(MI);
129 if (It != RegsAlreadyAddedToDT.end())
130 Reg = It->second;
131 auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg());
132 if (!MRI.getRegClassOrNull(Reg) && RC)
133 MRI.setRegClass(Reg, RC);
134 MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg);
136 }
137 for (MachineInstr *MI : ToEraseComposites)
139}
140
143 MachineIRBuilder MIB) {
145 for (MachineBasicBlock &MBB : MF) {
146 for (MachineInstr &MI : MBB) {
147 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name))
148 continue;
149 const MDNode *MD = MI.getOperand(2).getMetadata();
150 StringRef ValueName = cast<MDString>(MD->getOperand(0))->getString();
151 if (ValueName.size() > 0) {
152 MIB.setInsertPt(*MI.getParent(), MI);
153 buildOpName(MI.getOperand(1).getReg(), ValueName, MIB);
154 }
155 ToErase.push_back(&MI);
156 }
157 for (MachineInstr *MI : ToErase)
159 ToErase.clear();
160 }
161}
162
164 MachineRegisterInfo *MRI) {
166 IE = MRI->use_instr_end();
167 I != IE; ++I) {
168 MachineInstr *UseMI = &*I;
169 if ((isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_ptr_type) ||
170 isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_type)) &&
171 UseMI->getOperand(1).getReg() == Reg)
172 return UseMI;
173 }
174 return nullptr;
175}
176
178 Register ResVReg, Register OpReg) {
179 SPIRVTypeInst ResType = GR->getSPIRVTypeForVReg(ResVReg);
180 SPIRVTypeInst OpType = GR->getSPIRVTypeForVReg(OpReg);
181 assert(ResType && OpType && "Operand types are expected");
182 if (!GR->isBitcastCompatible(ResType, OpType))
183 report_fatal_error("incompatible result and operand types in a bitcast");
184 MachineRegisterInfo *MRI = MIB.getMRI();
185 if (!MRI->getRegClassOrNull(ResVReg))
186 MRI->setRegClass(ResVReg, GR->getRegClass(ResType));
187 if (ResType == OpType)
188 MIB.buildInstr(TargetOpcode::COPY).addDef(ResVReg).addUse(OpReg);
189 else
190 MIB.buildInstr(SPIRV::OpBitcast)
191 .addDef(ResVReg)
192 .addUse(GR->getSPIRVTypeID(ResType))
193 .addUse(OpReg);
194}
195
196// We lower G_BITCAST to OpBitcast here to avoid a MachineVerifier error.
197// The verifier checks if the source and destination LLTs of a G_BITCAST are
198// different, but this check is too strict for SPIR-V's typed pointers, which
199// may have the same LLT but different SPIRV type (e.g. pointers to different
200// pointee types). By lowering to OpBitcast here, we bypass the verifier's
201// check. See discussion in https://github.com/llvm/llvm-project/pull/110270
202// for more context.
203//
204// We also handle the llvm.spv.bitcast intrinsic here. If the source and
205// destination SPIR-V types are the same, we lower it to a COPY to enable
206// further optimizations like copy propagation.
208 MachineIRBuilder MIB) {
210 for (MachineBasicBlock &MBB : MF) {
211 for (MachineInstr &MI : MBB) {
212 if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
213 Register DstReg = MI.getOperand(0).getReg();
214 Register SrcReg = MI.getOperand(2).getReg();
215 SPIRVTypeInst DstType = GR->getSPIRVTypeForVReg(DstReg);
216 assert(
217 DstType &&
218 "Expected destination SPIR-V type to have been assigned already.");
219 SPIRVTypeInst SrcType = GR->getSPIRVTypeForVReg(SrcReg);
220 assert(SrcType &&
221 "Expected source SPIR-V type to have been assigned already.");
222 if (DstType == SrcType) {
223 MIB.setInsertPt(*MI.getParent(), MI);
224 MIB.buildCopy(DstReg, SrcReg);
225 ToErase.push_back(&MI);
226 continue;
227 }
228 }
229
230 if (MI.getOpcode() != TargetOpcode::G_BITCAST)
231 continue;
232
233 MIB.setInsertPt(*MI.getParent(), MI);
234 buildOpBitcast(GR, MIB, MI.getOperand(0).getReg(),
235 MI.getOperand(1).getReg());
236 ToErase.push_back(&MI);
237 }
238 }
239 for (MachineInstr *MI : ToErase)
241}
242
244 MachineIRBuilder MIB) {
245 // Get access to information about available extensions
246 const SPIRVSubtarget *ST =
247 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
249 for (MachineBasicBlock &MBB : MF) {
250 for (MachineInstr &MI : MBB) {
251 if (!isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
252 continue;
253 assert(MI.getOperand(2).isReg());
254 MIB.setInsertPt(*MI.getParent(), MI);
255 ToErase.push_back(&MI);
256 Register Def = MI.getOperand(0).getReg();
257 Register Source = MI.getOperand(2).getReg();
258 Type *ElemTy = getMDOperandAsType(MI.getOperand(3).getMetadata(), 0);
259 auto SC =
260 isa<FunctionType>(ElemTy)
261 ? SPIRV::StorageClass::CodeSectionINTEL
262 : addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST);
263 SPIRVTypeInst AssignedPtrType =
264 GR->getOrCreateSPIRVPointerType(ElemTy, MI, SC);
265
266 // If the ptrcast would be redundant, replace all uses with the source
267 // register.
268 MachineRegisterInfo *MRI = MIB.getMRI();
269 if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) {
270 // Erase Def's assign type instruction if we are going to replace Def.
271 if (MachineInstr *AssignMI = findAssignTypeInstr(Def, MRI))
272 ToErase.push_back(AssignMI);
273 MRI->replaceRegWith(Def, Source);
274 } else {
275 if (!GR->getSPIRVTypeForVReg(Def, &MF))
276 GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
277 MIB.buildBitcast(Def, Source);
278 }
279 }
280 }
281 for (MachineInstr *MI : ToErase)
283}
284
285// Translating GV, IRTranslator sometimes generates following IR:
286// %1 = G_GLOBAL_VALUE
287// %2 = COPY %1
288// %3 = G_ADDRSPACE_CAST %2
289//
290// or
291//
292// %1 = G_ZEXT %2
293// G_MEMCPY ... %2 ...
294//
295// New registers have no SPIRV type and no register class info.
296//
297// Set SPIRV type for GV, propagate it from GV to other instructions,
298// also set register classes.
302 MachineIRBuilder &MIB) {
303 SPIRVTypeInst SpvType = nullptr;
304 assert(MI && "Machine instr is expected");
305 if (MI->getOperand(0).isReg()) {
306 Register Reg = MI->getOperand(0).getReg();
307 SpvType = GR->getSPIRVTypeForVReg(Reg);
308 if (!SpvType) {
309 switch (MI->getOpcode()) {
310 case TargetOpcode::G_FCONSTANT:
311 case TargetOpcode::G_CONSTANT: {
312 MIB.setInsertPt(*MI->getParent(), MI);
313 Type *Ty = MI->getOperand(1).getCImm()->getType();
314 SpvType = GR->getOrCreateSPIRVType(
315 Ty, MIB, SPIRV::AccessQualifier::ReadWrite, true);
316 break;
317 }
318 case TargetOpcode::G_GLOBAL_VALUE: {
319 MIB.setInsertPt(*MI->getParent(), MI);
320 const GlobalValue *Global = MI->getOperand(1).getGlobal();
322 auto *Ty = TypedPointerType::get(ElementTy,
323 Global->getType()->getAddressSpace());
324 SpvType = GR->getOrCreateSPIRVType(
325 Ty, MIB, SPIRV::AccessQualifier::ReadWrite, true);
326 break;
327 }
328 case TargetOpcode::G_ANYEXT:
329 case TargetOpcode::G_SEXT:
330 case TargetOpcode::G_ZEXT: {
331 if (MI->getOperand(1).isReg()) {
332 if (MachineInstr *DefInstr =
333 MRI.getVRegDef(MI->getOperand(1).getReg())) {
334 if (SPIRVTypeInst Def =
335 propagateSPIRVType(DefInstr, GR, MRI, MIB)) {
336 unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);
337 unsigned ExpectedBW =
338 std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);
339 unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);
340 SpvType = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);
341 if (NumElements > 1)
342 SpvType = GR->getOrCreateSPIRVVectorType(SpvType, NumElements,
343 MIB, true);
344 }
345 }
346 }
347 break;
348 }
349 case TargetOpcode::G_PTRTOINT:
350 SpvType = GR->getOrCreateSPIRVIntegerType(
351 MRI.getType(Reg).getScalarSizeInBits(), MIB);
352 break;
353 case TargetOpcode::G_TRUNC:
354 case TargetOpcode::G_ADDRSPACE_CAST:
355 case TargetOpcode::G_PTR_ADD:
356 case TargetOpcode::COPY: {
357 MachineOperand &Op = MI->getOperand(1);
358 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
359 if (Def)
360 SpvType = propagateSPIRVType(Def, GR, MRI, MIB);
361 break;
362 }
363 default:
364 break;
365 }
366 if (SpvType) {
367 // check if the address space needs correction
368 LLT RegType = MRI.getType(Reg);
369 if (SpvType->getOpcode() == SPIRV::OpTypePointer &&
370 RegType.isPointer() &&
372 RegType.getAddressSpace()) {
373 const SPIRVSubtarget &ST =
374 MI->getParent()->getParent()->getSubtarget<SPIRVSubtarget>();
375 auto TSC = addressSpaceToStorageClass(RegType.getAddressSpace(), ST);
376 SpvType = GR->changePointerStorageClass(SpvType, TSC, *MI);
377 }
378 GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
379 }
380 if (!MRI.getRegClassOrNull(Reg))
381 MRI.setRegClass(Reg, SpvType ? GR->getRegClass(SpvType)
382 : &SPIRV::iIDRegClass);
383 }
384 }
385 return SpvType;
386}
387
388// To support current approach and limitations wrt. bit width here we widen a
389// scalar register with a bit width greater than 1 to valid sizes and cap it to
390// 128 width.
391static unsigned widenBitWidthToNextPow2(unsigned BitWidth) {
392 if (BitWidth == 1)
393 return 1; // No need to widen 1-bit values
394 return std::min(std::max(1u << Log2_32_Ceil(BitWidth), 8u), 128u);
395}
396
398 LLT RegType = MRI.getType(Reg);
399 if (!RegType.isScalar())
400 return;
401 unsigned CurrentWidth = RegType.getScalarSizeInBits();
402 unsigned NewWidth = widenBitWidthToNextPow2(CurrentWidth);
403 if (NewWidth != CurrentWidth)
404 MRI.setType(Reg, LLT::scalar(NewWidth));
405}
406
407static void widenCImmType(MachineOperand &MOP) {
408 const ConstantInt *CImmVal = MOP.getCImm();
409 unsigned CurrentWidth = CImmVal->getBitWidth();
410 unsigned NewWidth = widenBitWidthToNextPow2(CurrentWidth);
411 if (NewWidth != CurrentWidth) {
412 // Replace the immediate value with the widened version
413 MOP.setCImm(ConstantInt::get(CImmVal->getType()->getContext(),
414 CImmVal->getValue().zextOrTrunc(NewWidth)));
415 }
416}
417
419 MachineBasicBlock &MBB = *Def->getParent();
421 Def->getNextNode() ? Def->getNextNode()->getIterator() : MBB.end();
422 // Skip all the PHI and debug instructions.
423 while (DefIt != MBB.end() &&
424 (DefIt->isPHI() || DefIt->isDebugOrPseudoInstr()))
425 DefIt = std::next(DefIt);
426 MIB.setInsertPt(MBB, DefIt);
427}
428
429namespace llvm {
432 MachineRegisterInfo &MRI) {
433 assert((Ty || SpvType) && "Either LLVM or SPIRV type is expected.");
434 MachineInstr *Def = MRI.getVRegDef(Reg);
435 setInsertPtAfterDef(MIB, Def);
436 if (!SpvType)
437 SpvType = GR->getOrCreateSPIRVType(Ty, MIB,
438 SPIRV::AccessQualifier::ReadWrite, true);
439 if (!MRI.getRegClassOrNull(Reg))
440 MRI.setRegClass(Reg, GR->getRegClass(SpvType));
441 if (!MRI.getType(Reg).isValid())
442 MRI.setType(Reg, GR->getRegType(SpvType));
443 GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
444}
445
448 SPIRVTypeInst KnownResType) {
449 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
450 for (auto &Op : MI.operands()) {
451 if (!Op.isReg() || Op.isDef())
452 continue;
453 Register OpReg = Op.getReg();
454 SPIRVTypeInst SpvType = GR->getSPIRVTypeForVReg(OpReg);
455 if (!SpvType && KnownResType) {
456 SpvType = KnownResType;
457 GR->assignSPIRVTypeToVReg(KnownResType, OpReg, *MI.getMF());
458 }
459 assert(SpvType);
460 if (!MRI.getRegClassOrNull(OpReg))
461 MRI.setRegClass(OpReg, GR->getRegClass(SpvType));
462 if (!MRI.getType(OpReg).isValid())
463 MRI.setType(OpReg, GR->getRegType(SpvType));
464 }
465}
466} // namespace llvm
467
468static void
471 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
472 // Get access to information about available extensions
473 const SPIRVSubtarget *ST =
474 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
475
478 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
479
480 bool IsExtendedInts =
481 ST->canUseExtension(
482 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers) ||
483 ST->canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
484 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
485
486 if (!IsExtendedInts) {
487 // Without arbitrary precision integer extensions, SPIR-V only supports
488 // integer widths of 8, 16, 32, 64. Non-standard widths (e.g., i24, i40)
489 // must be widened to the next power of two.
490 //
491 // G_TRUNC requires special handling because its semantics depend on the
492 // original destination width. For example:
493 // %dst:s24 = G_TRUNC %src:s64
494 // After widening s24 to s32, we cannot simply do:
495 // %dst:s32 = G_TRUNC %src:s64
496 // because this would keep 32 bits instead of 24. Instead, we insert a
497 // G_AND to mask the value to the original width:
498 // %mask:s64 = G_CONSTANT 0xFFFFFF ; 24-bit mask
499 // %masked:s64 = G_AND %src:s64, %mask
500 // %dst:s32 = G_TRUNC %masked:s64
501 // If src and dst widen to the same size, G_TRUNC is replaced entirely:
502 // %mask:s64 = G_CONSTANT 0xFFFFFFFFFF ; 40-bit mask
503 // %dst:s64 = G_AND %src:s64, %mask
504 SmallVector<MachineInstr *, 8> TruncToRemove;
505 for (MachineBasicBlock &MBB : MF) {
506 for (MachineInstr &MI : MBB) {
507 unsigned MIOp = MI.getOpcode();
508 if (MIOp != TargetOpcode::G_TRUNC)
509 continue;
510 assert(MI.getNumOperands() == 2);
511 assert(MI.getOperand(0).isReg());
512 assert(MI.getOperand(1).isReg());
513
514 Register DstReg = MI.getOperand(0).getReg();
515 Register SrcReg = MI.getOperand(1).getReg();
516
517 LLT DstTy = MRI.getType(DstReg);
518 LLT SrcTy = MRI.getType(SrcReg);
519 assert((DstTy.isScalar() || DstTy.isVector()) &&
520 (SrcTy.isScalar() || SrcTy.isVector()) &&
521 "Expected scalar or vector G_TRUNC types");
522 assert(DstTy.isVector() == SrcTy.isVector() &&
523 "Expected matching scalar/vector G_TRUNC types");
524 assert((!DstTy.isVector() ||
525 DstTy.getElementCount() == SrcTy.getElementCount()) &&
526 "Expected equal vector element counts");
527
528 unsigned OriginalDstWidth = DstTy.getScalarSizeInBits();
529 unsigned OriginalSrcWidth = SrcTy.getScalarSizeInBits();
530
531 unsigned NewDstWidth = widenBitWidthToNextPow2(OriginalDstWidth);
532 unsigned NewSrcWidth = widenBitWidthToNextPow2(OriginalSrcWidth);
533 LLT NewDstTy = DstTy.changeElementSize(NewDstWidth);
534 LLT NewSrcTy = SrcTy.changeElementSize(NewSrcWidth);
535
536 // No Dst width change means no truncation semantics change, but the
537 // source still needs a legal type.
538 if (OriginalDstWidth == NewDstWidth) {
539 MRI.setType(SrcReg, NewSrcTy);
540 continue;
541 }
542
543 MRI.setType(SrcReg, NewSrcTy);
544 MRI.setType(DstReg, NewDstTy);
545
546 MIB.setInsertPt(MBB, MI.getIterator());
547 APInt Mask = APInt::getLowBitsSet(NewSrcWidth, OriginalDstWidth);
548 MachineInstrBuilder MaskReg =
549 DstTy.isVector()
551 NewSrcTy,
553 : MIB.buildConstant(NewSrcTy, Mask);
554 Register MaskedReg = MRI.createGenericVirtualRegister(NewSrcTy);
555 MIB.buildAnd(MaskedReg, SrcReg, MaskReg);
556
557 if (NewSrcWidth == NewDstWidth) {
558 MRI.replaceRegWith(DstReg, MaskedReg);
559 TruncToRemove.push_back(&MI);
560 } else {
561 MI.getOperand(1).setReg(MaskedReg);
562 }
563 }
564 }
565 for (MachineInstr *MI : TruncToRemove)
566 MI->eraseFromParent();
567 }
568
569 for (MachineBasicBlock *MBB : post_order(&MF)) {
570 if (MBB->empty())
571 continue;
572
573 bool ReachedBegin = false;
574 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
575 !ReachedBegin;) {
576 MachineInstr &MI = *MII;
577 unsigned MIOp = MI.getOpcode();
578
579 if (!IsExtendedInts) {
580 // validate bit width of scalar registers and constant immediates
581 for (auto &MOP : MI.operands()) {
582 if (MOP.isReg())
583 widenScalarType(MOP.getReg(), MRI);
584 else if (MOP.isCImm())
585 widenCImmType(MOP);
586 }
587 }
588
589 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
590 Register Reg = MI.getOperand(1).getReg();
591 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
592 Type *ElementTy = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
593 SPIRVTypeInst AssignedPtrType = GR->getOrCreateSPIRVPointerType(
594 ElementTy, MI,
595 addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));
596 // The intrinsic also carries vector-of-pointer values produced by
597 // scalarized vector GEPs; wrap the pointer in OpTypeVector to match
598 // the vreg's LLT.
599 LLT RegTy = MRI.getType(Reg);
600 if (RegTy.isValid() && RegTy.isVector())
601 AssignedPtrType = GR->getOrCreateSPIRVVectorType(
602 AssignedPtrType, RegTy.getNumElements(), MIB, true);
603 MachineInstr *Def = MRI.getVRegDef(Reg);
604 assert(Def && "Expecting an instruction that defines the register");
605 // G_GLOBAL_VALUE already has type info.
606 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
607 updateRegType(Reg, nullptr, AssignedPtrType, GR, MIB,
608 MF.getRegInfo());
609 ToErase.push_back(&MI);
610 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
611 Register Reg = MI.getOperand(1).getReg();
612 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
613 MachineInstr *Def = MRI.getVRegDef(Reg);
614 assert(Def && "Expecting an instruction that defines the register");
615 // G_GLOBAL_VALUE already has type info.
616 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
617 updateRegType(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
618 ToErase.push_back(&MI);
619 } else if (MIOp == TargetOpcode::FAKE_USE && MI.getNumOperands() > 0) {
620 MachineInstr *MdMI = MI.getPrevNode();
621 if (MdMI && isSpvIntrinsic(*MdMI, Intrinsic::spv_value_md)) {
622 // It's an internal service info from before IRTranslator passes.
623 MachineInstr *Def = getVRegDef(MRI, MI.getOperand(0).getReg());
624 for (unsigned I = 1, E = MI.getNumOperands(); I != E && Def; ++I)
625 if (getVRegDef(MRI, MI.getOperand(I).getReg()) != Def)
626 Def = nullptr;
627 if (Def) {
628 const MDNode *MD = MdMI->getOperand(1).getMetadata();
630 cast<MDString>(MD->getOperand(1))->getString();
631 const MDNode *TypeMD = cast<MDNode>(MD->getOperand(0));
632 Type *ValueTy = getMDOperandAsType(TypeMD, 0);
633 GR->addValueAttrs(Def, std::make_pair(ValueTy, ValueName.str()));
634 }
635 ToErase.push_back(MdMI);
636 }
637 ToErase.push_back(&MI);
638 } else if (MIOp == TargetOpcode::G_CONSTANT ||
639 MIOp == TargetOpcode::G_FCONSTANT ||
640 MIOp == TargetOpcode::G_BUILD_VECTOR) {
641 // %rc = G_CONSTANT ty Val
642 // Ensure %rc has a valid SPIR-V type assigned in the Global Registry.
643 Register Reg = MI.getOperand(0).getReg();
644 bool NeedAssignType = !GR->getSPIRVTypeForVReg(Reg);
645 Type *Ty = nullptr;
646 if (MIOp == TargetOpcode::G_CONSTANT) {
647 auto TargetExtIt = TargetExtConstTypes.find(&MI);
648 Ty = TargetExtIt == TargetExtConstTypes.end()
649 ? MI.getOperand(1).getCImm()->getType()
650 : TargetExtIt->second;
651 const ConstantInt *OpCI = MI.getOperand(1).getCImm();
652 // TODO: we may wish to analyze here if OpCI is zero and LLT RegType =
653 // MRI.getType(Reg); RegType.isPointer() is true, so that we observe
654 // at this point not i64/i32 constant but null pointer in the
655 // corresponding address space of RegType.getAddressSpace(). This may
656 // help to successfully validate the case when a OpConstantComposite's
657 // constituent has type that does not match Result Type of
658 // OpConstantComposite (see, for example,
659 // pointers/PtrCast-null-in-OpSpecConstantOp.ll).
660 Register PrimaryReg = GR->find(OpCI, &MF);
661 if (!PrimaryReg.isValid()) {
662 GR->add(OpCI, &MI);
663 } else if (PrimaryReg != Reg &&
664 MRI.getType(Reg) == MRI.getType(PrimaryReg)) {
665 auto *RCReg = MRI.getRegClassOrNull(Reg);
666 auto *RCPrimary = MRI.getRegClassOrNull(PrimaryReg);
667 if (!RCReg || RCPrimary == RCReg) {
668 RegsAlreadyAddedToDT[&MI] = PrimaryReg;
669 ToErase.push_back(&MI);
670 NeedAssignType = false;
671 }
672 }
673 } else if (MIOp == TargetOpcode::G_FCONSTANT) {
674 Ty = MI.getOperand(1).getFPImm()->getType();
675 } else {
676 assert(MIOp == TargetOpcode::G_BUILD_VECTOR);
677 Type *ElemTy = nullptr;
678 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
679 assert(ElemMI);
680
681 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT) {
682 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
683 } else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT) {
684 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
685 } else {
686 if (SPIRVTypeInst ElemSpvType =
687 GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg(), &MF))
688 ElemTy = const_cast<Type *>(GR->getTypeForSPIRVType(ElemSpvType));
689 }
690 if (ElemTy)
691 Ty = VectorType::get(
692 ElemTy, MI.getNumExplicitOperands() - MI.getNumExplicitDefs(),
693 false);
694 else
695 NeedAssignType = false;
696 }
697 if (NeedAssignType)
698 updateRegType(Reg, Ty, nullptr, GR, MIB, MRI);
699 } else if (MIOp == TargetOpcode::G_GLOBAL_VALUE) {
700 propagateSPIRVType(&MI, GR, MRI, MIB);
701 }
702
703 if (MII == Begin)
704 ReachedBegin = true;
705 else
706 --MII;
707 }
708 }
709 for (MachineInstr *MI : ToErase) {
710 auto It = RegsAlreadyAddedToDT.find(MI);
711 if (It != RegsAlreadyAddedToDT.end())
712 MRI.replaceRegWith(MI->getOperand(0).getReg(), It->second);
714 }
715
716 // Address the case when IRTranslator introduces instructions with new
717 // registers without associated SPIRV type.
718 for (MachineBasicBlock &MBB : MF) {
719 for (MachineInstr &MI : MBB) {
720 switch (MI.getOpcode()) {
721 case TargetOpcode::G_TRUNC:
722 case TargetOpcode::G_ANYEXT:
723 case TargetOpcode::G_SEXT:
724 case TargetOpcode::G_ZEXT:
725 case TargetOpcode::G_PTRTOINT:
726 case TargetOpcode::COPY:
727 case TargetOpcode::G_ADDRSPACE_CAST:
728 propagateSPIRVType(&MI, GR, MRI, MIB);
729 break;
730 }
731 }
732 }
733}
734
737 MachineIRBuilder MIB) {
739 for (MachineBasicBlock &MBB : MF)
740 for (MachineInstr &MI : MBB)
741 if (isTypeFoldingSupported(MI.getOpcode()))
742 processInstr(MI, MIB, MRI, GR, nullptr);
743}
744
745static Register
747 SmallVector<unsigned, 4> *Ops = nullptr) {
748 Register DefReg;
749 unsigned StartOp = InlineAsm::MIOp_FirstOperand,
751 for (unsigned Idx = StartOp, MISz = MI->getNumOperands(); Idx != MISz;
752 ++Idx) {
753 const MachineOperand &MO = MI->getOperand(Idx);
754 if (MO.isMetadata())
755 continue;
756 if (Idx == AsmDescOp && MO.isImm()) {
757 // compute the index of the next operand descriptor
758 const InlineAsm::Flag F(MO.getImm());
759 AsmDescOp += 1 + F.getNumOperandRegisters();
760 continue;
761 }
762 if (MO.isReg() && MO.isDef()) {
763 if (!Ops)
764 return MO.getReg();
765 DefReg = MO.getReg();
766 } else if (Ops) {
767 Ops->push_back(Idx);
768 }
769 }
770 return DefReg;
771}
772
773static void
775 const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder,
776 const SmallVector<MachineInstr *> &ToProcess) {
778 Register AsmTargetReg;
779 for (unsigned i = 0, Sz = ToProcess.size(); i + 1 < Sz; i += 2) {
780 MachineInstr *I1 = ToProcess[i], *I2 = ToProcess[i + 1];
781 assert(isSpvIntrinsic(*I1, Intrinsic::spv_inline_asm) && I2->isInlineAsm());
782 MIRBuilder.setInsertPt(*I2->getParent(), *I2);
783
784 if (!AsmTargetReg.isValid()) {
785 // define vendor specific assembly target or dialect
786 AsmTargetReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
787 MRI.setRegClass(AsmTargetReg, &SPIRV::iIDRegClass);
788 auto AsmTargetMIB =
789 MIRBuilder.buildInstr(SPIRV::OpAsmTargetINTEL).addDef(AsmTargetReg);
790 addStringImm(ST.getTargetTripleAsStr(), AsmTargetMIB);
791 GR->add(AsmTargetMIB.getInstr(), AsmTargetMIB);
792 }
793
794 // create types
795 const MDNode *IAMD = I1->getOperand(1).getMetadata();
798 for (const auto &ArgTy : FTy->params())
799 ArgTypes.push_back(GR->getOrCreateSPIRVType(
800 ArgTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true));
801 SPIRVTypeInst RetType =
802 GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder,
803 SPIRV::AccessQualifier::ReadWrite, true);
805 FTy, RetType, ArgTypes, MIRBuilder);
806
807 // define vendor specific assembly instructions string
809 MRI.setRegClass(AsmReg, &SPIRV::iIDRegClass);
810 auto AsmMIB = MIRBuilder.buildInstr(SPIRV::OpAsmINTEL)
811 .addDef(AsmReg)
812 .addUse(GR->getSPIRVTypeID(RetType))
813 .addUse(GR->getSPIRVTypeID(FuncType))
814 .addUse(AsmTargetReg);
815 // inline asm string:
816 addStringImm(I2->getOperand(InlineAsm::MIOp_AsmString).getSymbolName(),
817 AsmMIB);
818 // inline asm constraint string:
819 addStringImm(cast<MDString>(I1->getOperand(2).getMetadata()->getOperand(0))
820 ->getString(),
821 AsmMIB);
822 GR->add(AsmMIB.getInstr(), AsmMIB);
823
824 // calls the inline assembly instruction
825 unsigned ExtraInfo = I2->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
826 if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
827 MIRBuilder.buildInstr(SPIRV::OpDecorate)
828 .addUse(AsmReg)
829 .addImm(static_cast<uint32_t>(SPIRV::Decoration::SideEffectsINTEL));
830
832 if (!DefReg.isValid()) {
834 MRI.setRegClass(DefReg, &SPIRV::iIDRegClass);
835 SPIRVTypeInst VoidType = GR->getOrCreateSPIRVType(
836 Type::getVoidTy(MF.getFunction().getContext()), MIRBuilder,
837 SPIRV::AccessQualifier::ReadWrite, true);
838 GR->assignSPIRVTypeToVReg(VoidType, DefReg, MF);
839 }
840
841 auto AsmCall = MIRBuilder.buildInstr(SPIRV::OpAsmCallINTEL)
842 .addDef(DefReg)
843 .addUse(GR->getSPIRVTypeID(RetType))
844 .addUse(AsmReg);
845 for (unsigned IntrIdx = 3; IntrIdx < I1->getNumOperands(); ++IntrIdx)
846 AsmCall.addUse(I1->getOperand(IntrIdx).getReg());
847
848 // IRTranslator gets a bit confused when lowering inline ASM with outputs
849 // and inserts a spurious COPY & TRUNC as registers are assumed to be i64;
850 // we have to clean that up here to prevent erroneous trunc casts either on
851 // a struct (for multiple outputs) or same width integers to get lowered
852 // into SPIR-V
853 if (MRI.hasOneUse(DefReg)) {
854 MachineInstr &CopyMI = *MRI.use_instr_begin(DefReg);
855 if (CopyMI.getOpcode() == TargetOpcode::COPY) {
856 Register CopyDst = CopyMI.getOperand(0).getReg();
857 if (MRI.hasOneUse(CopyDst)) {
858 MachineInstr &TruncMI = *MRI.use_instr_begin(CopyDst);
859 if (TruncMI.getOpcode() == TargetOpcode::G_TRUNC) {
860 MRI.setType(DefReg, GR->getRegType(RetType));
861 Register TruncReg = TruncMI.defs().begin()->getReg();
862 MRI.replaceRegWith(TruncReg, DefReg);
863 invalidateAndEraseMI(GR, &TruncMI);
864 invalidateAndEraseMI(GR, &CopyMI);
865 }
866 }
867 }
868 }
869 }
870 for (MachineInstr *MI : ToProcess)
872}
873
875 const SPIRVSubtarget &ST,
876 MachineIRBuilder MIRBuilder) {
878 for (MachineBasicBlock &MBB : MF) {
879 for (MachineInstr &MI : MBB) {
880 if (isSpvIntrinsic(MI, Intrinsic::spv_inline_asm) ||
881 MI.getOpcode() == TargetOpcode::INLINEASM)
882 ToProcess.push_back(&MI);
883 }
884 }
885 if (ToProcess.size() == 0)
886 return;
887
888 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly))
889 report_fatal_error("Inline assembly instructions require the "
890 "following SPIR-V extension: SPV_INTEL_inline_assembly",
891 false);
892
893 insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess);
894}
895
897 union {
898 float F;
899 uint32_t Spir;
900 } FPMaxError;
901 FPMaxError.F = F;
902 return FPMaxError.Spir;
903}
904
906 MachineIRBuilder MIB) {
909 for (MachineBasicBlock &MBB : MF) {
910 for (MachineInstr &MI : MBB) {
911 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration) &&
912 !isSpvIntrinsic(MI, Intrinsic::spv_assign_aliasing_decoration) &&
913 !isSpvIntrinsic(MI, Intrinsic::spv_assign_fpmaxerror_decoration))
914 continue;
915 MIB.setInsertPt(*MI.getParent(), MI.getNextNode());
916 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration)) {
917 buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
918 MI.getOperand(2).getMetadata(), ST);
919 } else if (isSpvIntrinsic(MI,
920 Intrinsic::spv_assign_fpmaxerror_decoration)) {
922 MI.getOperand(2).getMetadata()->getOperand(0));
923 uint32_t OpValue =
925
926 buildOpDecorate(MI.getOperand(1).getReg(), MIB,
927 SPIRV::Decoration::FPMaxErrorDecorationINTEL,
928 {OpValue});
929 } else {
930 GR->buildMemAliasingOpDecorate(MI.getOperand(1).getReg(), MIB,
931 MI.getOperand(2).getImm(),
932 MI.getOperand(3).getMetadata());
933 }
934
935 ToErase.push_back(&MI);
936 }
937 }
938 for (MachineInstr *MI : ToErase)
940}
941
942// LLVM allows the switches to use registers as cases, while SPIR-V required
943// those to be immediate values. This function replaces such operands with the
944// equivalent immediate constant.
947 MachineIRBuilder MIB) {
949 for (MachineBasicBlock &MBB : MF) {
950 for (MachineInstr &MI : MBB) {
951 if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))
952 continue;
953
955 NewOperands.push_back(MI.getOperand(0)); // Opcode
956 NewOperands.push_back(MI.getOperand(1)); // Condition
957 NewOperands.push_back(MI.getOperand(2)); // Default
958 for (unsigned i = 3; i < MI.getNumOperands(); i += 2) {
959 Register Reg = MI.getOperand(i).getReg();
960 MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI);
961 NewOperands.push_back(
963
964 NewOperands.push_back(MI.getOperand(i + 1));
965 }
966
967 assert(MI.getNumOperands() == NewOperands.size());
968 while (MI.getNumOperands() > 0)
969 MI.removeOperand(0);
970 for (auto &MO : NewOperands)
971 MI.addOperand(MO);
972 }
973 }
974}
975
976// Some instructions are used during CodeGen but should never be emitted.
977// Cleaning up those.
981 for (MachineBasicBlock &MBB : MF) {
982 for (MachineInstr &MI : MBB) {
983 if (isSpvIntrinsic(MI, Intrinsic::spv_track_constant) ||
984 MI.getOpcode() == TargetOpcode::G_BRINDIRECT)
985 ToEraseMI.push_back(&MI);
986 }
987 }
988
989 for (MachineInstr *MI : ToEraseMI)
991}
992
993// Find all usages of G_BLOCK_ADDR in our intrinsics and replace those
994// operands/registers by the actual MBB it references.
996 MachineIRBuilder MIB) {
997 // Gather the reverse-mapping BB -> MBB.
999 for (MachineBasicBlock &MBB : MF)
1000 BB2MBB[MBB.getBasicBlock()] = &MBB;
1001
1002 // Gather instructions requiring patching. For now, only those can use
1003 // G_BLOCK_ADDR.
1004 SmallVector<MachineInstr *, 8> InstructionsToPatch;
1005 for (MachineBasicBlock &MBB : MF) {
1006 for (MachineInstr &MI : MBB) {
1007 if (isSpvIntrinsic(MI, Intrinsic::spv_switch) ||
1008 isSpvIntrinsic(MI, Intrinsic::spv_loop_merge) ||
1009 isSpvIntrinsic(MI, Intrinsic::spv_selection_merge))
1010 InstructionsToPatch.push_back(&MI);
1011 }
1012 }
1013
1014 // For each instruction to fix, we replace all the G_BLOCK_ADDR operands by
1015 // the actual MBB it references. Once those references have been updated, we
1016 // can cleanup remaining G_BLOCK_ADDR references.
1017 SmallPtrSet<MachineBasicBlock *, 8> ClearAddressTaken;
1019 MachineRegisterInfo &MRI = MF.getRegInfo();
1020 for (MachineInstr *MI : InstructionsToPatch) {
1022 for (unsigned i = 0; i < MI->getNumOperands(); ++i) {
1023 // The operand is not a register, keep as-is.
1024 if (!MI->getOperand(i).isReg()) {
1025 NewOps.push_back(MI->getOperand(i));
1026 continue;
1027 }
1028
1029 Register Reg = MI->getOperand(i).getReg();
1030 MachineInstr *BuildMBB = MRI.getVRegDef(Reg);
1031 // The register is not the result of G_BLOCK_ADDR, keep as-is.
1032 if (!BuildMBB || BuildMBB->getOpcode() != TargetOpcode::G_BLOCK_ADDR) {
1033 NewOps.push_back(MI->getOperand(i));
1034 continue;
1035 }
1036
1037 assert(BuildMBB && BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&
1038 BuildMBB->getOperand(1).isBlockAddress() &&
1039 BuildMBB->getOperand(1).getBlockAddress());
1040 BasicBlock *BB =
1041 BuildMBB->getOperand(1).getBlockAddress()->getBasicBlock();
1042 auto It = BB2MBB.find(BB);
1043 if (It == BB2MBB.end())
1044 report_fatal_error("cannot find a machine basic block by a basic block "
1045 "in a switch statement");
1046 MachineBasicBlock *ReferencedBlock = It->second;
1047 NewOps.push_back(MachineOperand::CreateMBB(ReferencedBlock));
1048
1049 ClearAddressTaken.insert(ReferencedBlock);
1050 ToEraseMI.insert(BuildMBB);
1051 }
1052
1053 // Replace the operands.
1054 assert(MI->getNumOperands() == NewOps.size());
1055 while (MI->getNumOperands() > 0)
1056 MI->removeOperand(0);
1057 for (auto &MO : NewOps)
1058 MI->addOperand(MO);
1059
1060 if (MachineInstr *Next = MI->getNextNode()) {
1061 if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {
1062 ToEraseMI.insert(Next);
1063 Next = MI->getNextNode();
1064 }
1065 if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)
1066 ToEraseMI.insert(Next);
1067 }
1068 }
1069
1070 // BlockAddress operands were used to keep information between passes,
1071 // let's undo the "address taken" status to reflect that Succ doesn't
1072 // actually correspond to an IR-level basic block.
1073 for (MachineBasicBlock *Succ : ClearAddressTaken)
1074 Succ->setAddressTakenIRBlock(nullptr);
1075
1076 // If we just delete G_BLOCK_ADDR instructions with BlockAddress operands,
1077 // this leaves their BasicBlock counterparts in a "address taken" status. This
1078 // would make AsmPrinter to generate a series of unneeded labels of a "Address
1079 // of block that was removed by CodeGen" kind. Let's first ensure that we
1080 // don't have a dangling BlockAddress constants by zapping the BlockAddress
1081 // nodes, and only after that proceed with erasing G_BLOCK_ADDR instructions.
1082 Constant *Replacement =
1083 ConstantInt::get(Type::getInt32Ty(MF.getFunction().getContext()), 1);
1084 for (MachineInstr *BlockAddrI : ToEraseMI) {
1085 if (BlockAddrI->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
1086 BlockAddress *BA = const_cast<BlockAddress *>(
1087 BlockAddrI->getOperand(1).getBlockAddress());
1089 ConstantExpr::getIntToPtr(Replacement, BA->getType()));
1090 BA->destroyConstant();
1091 }
1092 invalidateAndEraseMI(GR, BlockAddrI);
1093 }
1094}
1095
1097 if (MBB.empty())
1098 return MBB.getNextNode() != nullptr;
1099
1100 // Branching SPIR-V intrinsics are not detected by this generic method.
1101 // Thus, we can only trust negative result.
1102 if (!MBB.canFallThrough())
1103 return false;
1104
1105 // Otherwise, we must manually check if we have a SPIR-V intrinsic which
1106 // prevent an implicit fallthrough.
1107 for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend();
1108 It != E; ++It) {
1109 if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
1110 return false;
1111 }
1112 return true;
1113}
1114
1116 MachineIRBuilder MIB) {
1117 // It is valid for MachineBasicBlocks to not finish with a branch instruction.
1118 // In such cases, they will simply fallthrough their immediate successor.
1119 for (MachineBasicBlock &MBB : MF) {
1121 continue;
1122
1123 assert(MBB.succ_size() == 1);
1124 MIB.setInsertPt(MBB, MBB.end());
1125 MIB.buildBr(**MBB.successors().begin());
1126 }
1127}
1128
1129bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
1130 // Initialize the type registry.
1131 const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
1132 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1133 GR->setCurrentFunc(MF);
1134 MachineIRBuilder MIB(MF);
1135 // a registry of target extension constants
1136 DenseMap<MachineInstr *, Type *> TargetExtConstTypes;
1137 // to keep record of tracked constants
1138 addConstantsToTrack(MF, GR, ST, TargetExtConstTypes);
1139 foldConstantsIntoIntrinsics(MF, GR, MIB);
1140 insertBitcasts(MF, GR, MIB);
1141 generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes);
1142
1143 processSwitchesConstants(MF, GR, MIB);
1144 processBlockAddr(MF, GR, MIB);
1146
1147 processInstrsWithTypeFolding(MF, GR, MIB);
1149 insertSpirvDecorations(MF, GR, MIB);
1150 insertInlineAsm(MF, GR, ST, MIB);
1151 lowerBitcasts(MF, GR, MIB);
1152
1153 return true;
1154}
1155
1156INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,
1157 false)
1158
1159char SPIRVPreLegalizer::ID = 0;
1160
1161FunctionPass *llvm::createSPIRVPreLegalizerPass() {
1162 return new SPIRVPreLegalizer();
1163}
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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")
Provides analysis for continuously CSEing during GISel passes.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Provides analysis for querying information about KnownBits during GISel passes.
#define DEBUG_TYPE
IRTranslator LLVM IR MI
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
static Register collectInlineAsmInstrOperands(MachineInstr *MI, SmallVector< unsigned, 4 > *Ops=nullptr)
static void insertInlineAsm(MachineFunction &MF, SPIRVGlobalRegistry *GR, const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder)
static void cleanupHelperInstructions(MachineFunction &MF, SPIRVGlobalRegistry *GR)
static void insertInlineAsmProcess(MachineFunction &MF, SPIRVGlobalRegistry *GR, const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder, const SmallVector< MachineInstr * > &ToProcess)
static void removeImplicitFallthroughs(MachineFunction &MF, MachineIRBuilder MIB)
static unsigned widenBitWidthToNextPow2(unsigned BitWidth)
static void setInsertPtAfterDef(MachineIRBuilder &MIB, MachineInstr *Def)
static bool isImplicitFallthrough(MachineBasicBlock &MBB)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void processInstrsWithTypeFolding(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void processSwitchesConstants(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void lowerBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static MachineInstr * findAssignTypeInstr(Register Reg, MachineRegisterInfo *MRI)
static void widenCImmType(MachineOperand &MOP)
static void buildOpBitcast(SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, Register ResVReg, Register OpReg)
static void processBlockAddr(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void widenScalarType(Register Reg, MachineRegisterInfo &MRI)
static void foldConstantsIntoIntrinsics(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR, const SPIRVSubtarget &STI, DenseMap< MachineInstr *, Type * > &TargetExtConstTypes)
static uint32_t convertFloatToSPIRVWord(float F)
static SPIRVTypeInst propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI, MachineIRBuilder &MIB)
static void invalidateAndEraseMI(SPIRVGlobalRegistry *GR, MachineInstr *MI)
static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB, DenseMap< MachineInstr *, Type * > &TargetExtConstTypes)
LLVM_ABI float convertToFloat() const
Converts this APFloat to host float value.
Definition APFloat.cpp:5999
Class for arbitrary precision integers.
Definition APInt.h:78
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1076
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:307
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
The address of a basic block.
Definition Constants.h:1082
BasicBlock * getBasicBlock() const
Definition Constants.h:1119
static LLVM_ABI Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
const APFloat & getValueAPF() const
Definition Constants.h:463
This is the shared class of boolean and integer constants.
Definition Constants.h:87
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
Definition Constants.h:162
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition Constants.h:159
This is an important base class in LLVM.
Definition Constant.h:43
LLVM_ABI void destroyConstant()
Called if some element of this constant is no longer valid.
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:225
iterator end()
Definition DenseMap.h:143
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:358
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr ElementCount getElementCount() const
LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
Metadata node.
Definition Metadata.h:1069
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1433
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
MachineInstrBundleIterator< MachineInstr, true > reverse_iterator
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineBasicBlock & front() const
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 buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildBuildVectorConstant(const DstOp &Res, ArrayRef< APInt > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ... where each OpN is built with G_CONSTANT.
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.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
mop_range defs()
Returns all explicit operands that are register definitions.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
const MDNode * getMetadata() const
static MachineOperand CreateCImm(const ConstantInt *CI)
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
bool isMetadata() const
isMetadata - Tests if this is a MO_Metadata operand.
const BlockAddress * getBlockAddress() const
void setCImm(const ConstantInt *CI)
bool isBlockAddress() const
isBlockAddress - Tests if this is a MO_BlockAddress operand.
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
static MachineOperand CreateMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
defusechain_instr_iterator< true, false, false, true > use_instr_iterator
use_instr_iterator/use_instr_begin/use_instr_end - Walk all uses of the specified register,...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
use_instr_iterator use_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
static use_instr_iterator use_instr_end()
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg, const MachineFunction &MF)
SPIRVTypeInst getOrCreateOpTypeFunctionWithArgs(const Type *Ty, SPIRVTypeInst RetType, const SmallVectorImpl< SPIRVTypeInst > &ArgTypes, MachineIRBuilder &MIRBuilder)
const TargetRegisterClass * getRegClass(SPIRVTypeInst SpvType) const
unsigned getScalarOrVectorBitWidth(SPIRVTypeInst Type) const
SPIRVTypeInst getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
unsigned getScalarOrVectorComponentCount(Register VReg) const
const Type * getTypeForSPIRVType(SPIRVTypeInst Ty) const
bool isBitcastCompatible(SPIRVTypeInst Type1, SPIRVTypeInst Type2) const
LLT getRegType(SPIRVTypeInst SpvType) const
void invalidateMachineInstr(MachineInstr *MI)
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC)
Register getSPIRVTypeID(SPIRVTypeInst SpirvType) const
SPIRVTypeInst changePointerStorageClass(SPIRVTypeInst PtrType, SPIRV::StorageClass::StorageClass SC, MachineInstr &I)
void addGlobalObject(const Value *V, const MachineFunction *MF, Register R)
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
Type * getDeducedGlobalValueType(const GlobalValue *Global)
void addValueAttrs(MachineInstr *Key, std::pair< Type *, std::string > Val)
void buildMemAliasingOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, uint32_t Dec, const MDNode *GVarMD)
SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const
bool add(SPIRV::IRHandle Handle, const MachineInstr *MI)
Register find(SPIRV::IRHandle Handle, const MachineFunction *MF)
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.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:309
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:282
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
Definition Type.h:130
static LLVM_ABI 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
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:552
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
IteratorT begin() const
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract(Y &&MD)
Extract a Value from Metadata, if any.
Definition Metadata.h:696
This is an optimization pass for GlobalISel generic memory operations.
void buildOpName(Register Target, const StringRef &Name, MachineIRBuilder &MIRBuilder)
unsigned Log2_32_Ceil(uint32_t Value)
Return the ceil log base 2 of the specified value, 32 if the value is zero.
Definition MathExtras.h:344
StringMapEntry< Value * > ValueName
Definition Value.h:56
bool isTypeFoldingSupported(unsigned Opcode)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
FunctionPass * createSPIRVPreLegalizerPass()
void updateRegType(Register Reg, Type *Ty, SPIRVTypeInst SpirvTy, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Helper external function for assigning a SPIRV type to a register, ensuring the register class and ty...
constexpr unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)
Definition SPIRVUtils.h:250
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, const std::vector< uint32_t > &DecArgs, StringRef StrImm)
Type * toTypedPointer(Type *Ty)
Definition SPIRVUtils.h:476
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
auto post_order(const T &G)
Post-order traversal of a graph.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
@ Global
Append to llvm.global_dtors.
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, const MDNode *GVarMD, const SPIRVSubtarget &ST)
void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR, SPIRVTypeInst KnownResType)
FunctionAddr VTableAddr Next
Definition InstrProf.h:141
DWARFExpression::Operation Op
MachineInstr * getDefInstrMaybeConstant(Register &ConstReg, const MachineRegisterInfo *MRI)
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Type * getMDOperandAsType(const MDNode *N, unsigned I)
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
void addStringImm(const StringRef &Str, MCInst &Inst)
MachineInstr * getVRegDef(MachineRegisterInfo &MRI, Register Reg)