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