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 ? SPIRV::StorageClass::CodeSectionINTEL
263 : addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST);
264 SPIRVTypeInst AssignedPtrType =
265 GR->getOrCreateSPIRVPointerType(ElemTy, MI, SC);
266
267 // If the ptrcast would be redundant, replace all uses with the source
268 // register.
269 MachineRegisterInfo *MRI = MIB.getMRI();
270 if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) {
271 // Erase Def's assign type instruction if we are going to replace Def.
272 if (MachineInstr *AssignMI = findAssignTypeInstr(Def, MRI))
273 ToErase.push_back(AssignMI);
274 MRI->replaceRegWith(Def, Source);
275 } else {
276 if (!GR->getSPIRVTypeForVReg(Def, &MF))
277 GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
278 MIB.buildBitcast(Def, Source);
279 }
280 }
281 }
282 for (MachineInstr *MI : ToErase)
284}
285
286// Translating GV, IRTranslator sometimes generates following IR:
287// %1 = G_GLOBAL_VALUE
288// %2 = COPY %1
289// %3 = G_ADDRSPACE_CAST %2
290//
291// or
292//
293// %1 = G_ZEXT %2
294// G_MEMCPY ... %2 ...
295//
296// New registers have no SPIRV type and no register class info.
297//
298// Set SPIRV type for GV, propagate it from GV to other instructions,
299// also set register classes.
303 MachineIRBuilder &MIB) {
304 SPIRVTypeInst SpvType = nullptr;
305 assert(MI && "Machine instr is expected");
306 if (MI->getOperand(0).isReg()) {
307 Register Reg = MI->getOperand(0).getReg();
308 SpvType = GR->getSPIRVTypeForVReg(Reg);
309 if (!SpvType) {
310 switch (MI->getOpcode()) {
311 case TargetOpcode::G_FCONSTANT:
312 case TargetOpcode::G_CONSTANT: {
313 MIB.setInsertPt(*MI->getParent(), MI);
314 Type *Ty = MI->getOperand(1).getCImm()->getType();
315 SpvType = GR->getOrCreateSPIRVType(
316 Ty, MIB, SPIRV::AccessQualifier::ReadWrite, true);
317 break;
318 }
319 case TargetOpcode::G_GLOBAL_VALUE: {
320 MIB.setInsertPt(*MI->getParent(), MI);
321 const GlobalValue *Global = MI->getOperand(1).getGlobal();
323 auto *Ty = TypedPointerType::get(ElementTy,
324 Global->getType()->getAddressSpace());
325 SpvType = GR->getOrCreateSPIRVType(
326 Ty, MIB, SPIRV::AccessQualifier::ReadWrite, true);
327 break;
328 }
329 case TargetOpcode::G_ANYEXT:
330 case TargetOpcode::G_SEXT:
331 case TargetOpcode::G_ZEXT: {
332 if (MI->getOperand(1).isReg()) {
333 if (MachineInstr *DefInstr =
334 MRI.getVRegDef(MI->getOperand(1).getReg())) {
335 if (SPIRVTypeInst Def =
336 propagateSPIRVType(DefInstr, GR, MRI, MIB)) {
337 unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);
338 unsigned ExpectedBW =
339 std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);
340 unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);
341 SpvType = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);
342 if (NumElements > 1)
343 SpvType = GR->getOrCreateSPIRVVectorType(SpvType, NumElements,
344 MIB, true);
345 }
346 }
347 }
348 break;
349 }
350 case TargetOpcode::G_PTRTOINT:
351 SpvType = GR->getOrCreateSPIRVIntegerType(
352 MRI.getType(Reg).getScalarSizeInBits(), MIB);
353 break;
354 case TargetOpcode::G_TRUNC:
355 case TargetOpcode::G_ADDRSPACE_CAST:
356 case TargetOpcode::G_PTR_ADD:
357 case TargetOpcode::COPY: {
358 MachineOperand &Op = MI->getOperand(1);
359 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
360 if (Def)
361 SpvType = propagateSPIRVType(Def, GR, MRI, MIB);
362 break;
363 }
364 default:
365 break;
366 }
367 if (SpvType) {
368 // check if the address space needs correction
369 LLT RegType = MRI.getType(Reg);
370 if (SpvType->getOpcode() == SPIRV::OpTypePointer &&
371 RegType.isPointer() &&
373 RegType.getAddressSpace()) {
374 const SPIRVSubtarget &ST =
375 MI->getParent()->getParent()->getSubtarget<SPIRVSubtarget>();
376 auto TSC = addressSpaceToStorageClass(RegType.getAddressSpace(), ST);
377 SpvType = GR->changePointerStorageClass(SpvType, TSC, *MI);
378 }
379 GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
380 }
381 if (!MRI.getRegClassOrNull(Reg))
382 MRI.setRegClass(Reg, SpvType ? GR->getRegClass(SpvType)
383 : &SPIRV::iIDRegClass);
384 }
385 }
386 return SpvType;
387}
388
389// To support current approach and limitations wrt. bit width here we widen a
390// scalar register with a bit width greater than 1 to valid sizes and cap it to
391// 128 width.
392static unsigned widenBitWidthToNextPow2(unsigned BitWidth) {
393 if (BitWidth == 1)
394 return 1; // No need to widen 1-bit values
395 return std::min(std::max<unsigned>(PowerOf2Ceil(BitWidth), 8u), 128u);
396}
397
399 LLT RegType = MRI.getType(Reg);
400 if (!RegType.isScalar())
401 return;
402 unsigned CurrentWidth = RegType.getScalarSizeInBits();
403 unsigned NewWidth = widenBitWidthToNextPow2(CurrentWidth);
404 if (NewWidth != CurrentWidth)
405 MRI.setType(Reg, LLT::scalar(NewWidth));
406}
407
408static void widenCImmType(MachineOperand &MOP) {
409 const ConstantInt *CImmVal = MOP.getCImm();
410 unsigned CurrentWidth = CImmVal->getBitWidth();
411 unsigned NewWidth = widenBitWidthToNextPow2(CurrentWidth);
412 if (NewWidth != CurrentWidth) {
413 // Replace the immediate value with the widened version
414 MOP.setCImm(ConstantInt::get(CImmVal->getType()->getContext(),
415 CImmVal->getValue().zextOrTrunc(NewWidth)));
416 }
417}
418
420 MachineBasicBlock &MBB = *Def->getParent();
422 Def->getNextNode() ? Def->getNextNode()->getIterator() : MBB.end();
423 // Skip all the PHI and debug instructions.
424 while (DefIt != MBB.end() &&
425 (DefIt->isPHI() || DefIt->isDebugOrPseudoInstr()))
426 DefIt = std::next(DefIt);
427 MIB.setInsertPt(MBB, DefIt);
428}
429
430namespace llvm {
433 MachineRegisterInfo &MRI) {
434 assert((Ty || SpvType) && "Either LLVM or SPIRV type is expected.");
435 MachineInstr *Def = MRI.getVRegDef(Reg);
436 setInsertPtAfterDef(MIB, Def);
437 if (!SpvType)
438 SpvType = GR->getOrCreateSPIRVType(Ty, MIB,
439 SPIRV::AccessQualifier::ReadWrite, true);
440 if (!MRI.getRegClassOrNull(Reg))
441 MRI.setRegClass(Reg, GR->getRegClass(SpvType));
442 if (!MRI.getType(Reg).isValid())
443 MRI.setType(Reg, GR->getRegType(SpvType));
444 GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
445}
446
449 SPIRVTypeInst KnownResType) {
450 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
451 for (auto &Op : MI.operands()) {
452 if (!Op.isReg() || Op.isDef())
453 continue;
454 Register OpReg = Op.getReg();
455 SPIRVTypeInst SpvType = GR->getSPIRVTypeForVReg(OpReg);
456 if (!SpvType && KnownResType) {
457 SpvType = KnownResType;
458 GR->assignSPIRVTypeToVReg(KnownResType, OpReg, *MI.getMF());
459 }
460 assert(SpvType);
461 if (!MRI.getRegClassOrNull(OpReg))
462 MRI.setRegClass(OpReg, GR->getRegClass(SpvType));
463 if (!MRI.getType(OpReg).isValid())
464 MRI.setType(OpReg, GR->getRegType(SpvType));
465 }
466}
467} // namespace llvm
468
469static void
472 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
473 // Get access to information about available extensions
474 const SPIRVSubtarget *ST =
475 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
476
479 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
480
481 bool IsExtendedInts =
482 ST->canUseExtension(
483 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers) ||
484 ST->canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
485 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
486
487 if (!IsExtendedInts) {
488 // Without arbitrary precision integer extensions, SPIR-V only supports
489 // integer widths of 8, 16, 32, 64. Non-standard widths (e.g., i24, i40)
490 // must be widened to the next power of two.
491 //
492 // G_TRUNC requires special handling because its semantics depend on the
493 // original destination width. For example:
494 // %dst:s24 = G_TRUNC %src:s64
495 // After widening s24 to s32, we cannot simply do:
496 // %dst:s32 = G_TRUNC %src:s64
497 // because this would keep 32 bits instead of 24. Instead, we insert a
498 // G_AND to mask the value to the original width:
499 // %mask:s64 = G_CONSTANT 0xFFFFFF ; 24-bit mask
500 // %masked:s64 = G_AND %src:s64, %mask
501 // %dst:s32 = G_TRUNC %masked:s64
502 // If src and dst widen to the same size, G_TRUNC is replaced entirely:
503 // %mask:s64 = G_CONSTANT 0xFFFFFFFFFF ; 40-bit mask
504 // %dst:s64 = G_AND %src:s64, %mask
505 SmallVector<MachineInstr *, 8> TruncToRemove;
506 for (MachineBasicBlock &MBB : MF) {
507 for (MachineInstr &MI : MBB) {
508 unsigned MIOp = MI.getOpcode();
509 if (MIOp != TargetOpcode::G_TRUNC)
510 continue;
511 assert(MI.getNumOperands() == 2);
512 assert(MI.getOperand(0).isReg());
513 assert(MI.getOperand(1).isReg());
514
515 Register DstReg = MI.getOperand(0).getReg();
516 Register SrcReg = MI.getOperand(1).getReg();
517
518 LLT DstTy = MRI.getType(DstReg);
519 LLT SrcTy = MRI.getType(SrcReg);
520 assert((DstTy.isScalar() || DstTy.isVector()) &&
521 (SrcTy.isScalar() || SrcTy.isVector()) &&
522 "Expected scalar or vector G_TRUNC types");
523 assert(DstTy.isVector() == SrcTy.isVector() &&
524 "Expected matching scalar/vector G_TRUNC types");
525 assert((!DstTy.isVector() ||
526 DstTy.getElementCount() == SrcTy.getElementCount()) &&
527 "Expected equal vector element counts");
528
529 unsigned OriginalDstWidth = DstTy.getScalarSizeInBits();
530 unsigned OriginalSrcWidth = SrcTy.getScalarSizeInBits();
531
532 unsigned NewDstWidth = widenBitWidthToNextPow2(OriginalDstWidth);
533 unsigned NewSrcWidth = widenBitWidthToNextPow2(OriginalSrcWidth);
534 LLT NewDstTy = DstTy.changeElementSize(NewDstWidth);
535 LLT NewSrcTy = SrcTy.changeElementSize(NewSrcWidth);
536
537 // No Dst width change means no truncation semantics change, but the
538 // source still needs a legal type.
539 if (OriginalDstWidth == NewDstWidth) {
540 MRI.setType(SrcReg, NewSrcTy);
541 continue;
542 }
543
544 MRI.setType(SrcReg, NewSrcTy);
545 MRI.setType(DstReg, NewDstTy);
546
547 MIB.setInsertPt(MBB, MI.getIterator());
548 APInt Mask = APInt::getLowBitsSet(NewSrcWidth, OriginalDstWidth);
549 MachineInstrBuilder MaskReg =
550 DstTy.isVector()
552 NewSrcTy,
554 : MIB.buildConstant(NewSrcTy, Mask);
555 Register MaskedReg = MRI.createGenericVirtualRegister(NewSrcTy);
556 MIB.buildAnd(MaskedReg, SrcReg, MaskReg);
557
558 if (NewSrcWidth == NewDstWidth) {
559 MRI.replaceRegWith(DstReg, MaskedReg);
560 TruncToRemove.push_back(&MI);
561 } else {
562 MI.getOperand(1).setReg(MaskedReg);
563 }
564 }
565 }
566 for (MachineInstr *MI : TruncToRemove)
567 MI->eraseFromParent();
568 }
569
570 for (MachineBasicBlock *MBB : post_order(&MF)) {
571 if (MBB->empty())
572 continue;
573
574 bool ReachedBegin = false;
575 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
576 !ReachedBegin;) {
577 MachineInstr &MI = *MII;
578 unsigned MIOp = MI.getOpcode();
579
580 if (!IsExtendedInts) {
581 // validate bit width of scalar registers and constant immediates
582 for (auto &MOP : MI.operands()) {
583 if (MOP.isReg())
584 widenScalarType(MOP.getReg(), MRI);
585 else if (MOP.isCImm())
586 widenCImmType(MOP);
587 }
588 }
589
590 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
591 Register Reg = MI.getOperand(1).getReg();
592 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
593 Type *ElementTy = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
594 SPIRVTypeInst AssignedPtrType = GR->getOrCreateSPIRVPointerType(
595 ElementTy, MI,
596 addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));
597 // The intrinsic also carries vector-of-pointer values produced by
598 // scalarized vector GEPs; wrap the pointer in OpTypeVector to match
599 // the vreg's LLT.
600 LLT RegTy = MRI.getType(Reg);
601 if (RegTy.isValid() && RegTy.isVector())
602 AssignedPtrType = GR->getOrCreateSPIRVVectorType(
603 AssignedPtrType, RegTy.getNumElements(), MIB, true);
604 MachineInstr *Def = MRI.getVRegDef(Reg);
605 assert(Def && "Expecting an instruction that defines the register");
606 // G_GLOBAL_VALUE already has type info.
607 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
608 updateRegType(Reg, nullptr, AssignedPtrType, GR, MIB,
609 MF.getRegInfo());
610 ToErase.push_back(&MI);
611 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
612 Register Reg = MI.getOperand(1).getReg();
613 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
614 MachineInstr *Def = MRI.getVRegDef(Reg);
615 assert(Def && "Expecting an instruction that defines the register");
616 // G_GLOBAL_VALUE already has type info.
617 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
618 updateRegType(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
619 ToErase.push_back(&MI);
620 } else if (MIOp == TargetOpcode::FAKE_USE && MI.getNumOperands() > 0) {
621 MachineInstr *MdMI = MI.getPrevNode();
622 if (MdMI && isSpvIntrinsic(*MdMI, Intrinsic::spv_value_md)) {
623 // It's an internal service info from before IRTranslator passes.
624 MachineInstr *Def = getVRegDef(MRI, MI.getOperand(0).getReg());
625 for (unsigned I = 1, E = MI.getNumOperands(); I != E && Def; ++I)
626 if (getVRegDef(MRI, MI.getOperand(I).getReg()) != Def)
627 Def = nullptr;
628 if (Def) {
629 const MDNode *MD = MdMI->getOperand(1).getMetadata();
631 cast<MDString>(MD->getOperand(1))->getString();
632 const MDNode *TypeMD = cast<MDNode>(MD->getOperand(0));
633 Type *ValueTy = getMDOperandAsType(TypeMD, 0);
634 GR->addValueAttrs(Def, std::make_pair(ValueTy, ValueName.str()));
635 }
636 ToErase.push_back(MdMI);
637 }
638 ToErase.push_back(&MI);
639 } else if (MIOp == TargetOpcode::G_CONSTANT ||
640 MIOp == TargetOpcode::G_FCONSTANT ||
641 MIOp == TargetOpcode::G_BUILD_VECTOR) {
642 // %rc = G_CONSTANT ty Val
643 // Ensure %rc has a valid SPIR-V type assigned in the Global Registry.
644 Register Reg = MI.getOperand(0).getReg();
645 bool NeedAssignType = !GR->getSPIRVTypeForVReg(Reg);
646 Type *Ty = nullptr;
647 if (MIOp == TargetOpcode::G_CONSTANT) {
648 auto TargetExtIt = TargetExtConstTypes.find(&MI);
649 Ty = TargetExtIt == TargetExtConstTypes.end()
650 ? MI.getOperand(1).getCImm()->getType()
651 : TargetExtIt->second;
652 const ConstantInt *OpCI = MI.getOperand(1).getCImm();
653 // TODO: we may wish to analyze here if OpCI is zero and LLT RegType =
654 // MRI.getType(Reg); RegType.isPointer() is true, so that we observe
655 // at this point not i64/i32 constant but null pointer in the
656 // corresponding address space of RegType.getAddressSpace(). This may
657 // help to successfully validate the case when a OpConstantComposite's
658 // constituent has type that does not match Result Type of
659 // OpConstantComposite (see, for example,
660 // pointers/PtrCast-null-in-OpSpecConstantOp.ll).
661 Register PrimaryReg = GR->find(OpCI, &MF);
662 if (!PrimaryReg.isValid()) {
663 GR->add(OpCI, &MI);
664 } else if (PrimaryReg != Reg &&
665 MRI.getType(Reg) == MRI.getType(PrimaryReg)) {
666 auto *RCReg = MRI.getRegClassOrNull(Reg);
667 auto *RCPrimary = MRI.getRegClassOrNull(PrimaryReg);
668 if (!RCReg || RCPrimary == RCReg) {
669 RegsAlreadyAddedToDT[&MI] = PrimaryReg;
670 ToErase.push_back(&MI);
671 NeedAssignType = false;
672 }
673 }
674 } else if (MIOp == TargetOpcode::G_FCONSTANT) {
675 Ty = MI.getOperand(1).getFPImm()->getType();
676 } else {
677 assert(MIOp == TargetOpcode::G_BUILD_VECTOR);
678 Type *ElemTy = nullptr;
679 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
680 assert(ElemMI);
681
682 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT) {
683 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
684 } else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT) {
685 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
686 } else {
687 if (SPIRVTypeInst ElemSpvType =
688 GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg(), &MF))
689 ElemTy = const_cast<Type *>(GR->getTypeForSPIRVType(ElemSpvType));
690 }
691 if (ElemTy)
692 Ty = VectorType::get(
693 ElemTy, MI.getNumExplicitOperands() - MI.getNumExplicitDefs(),
694 false);
695 else
696 NeedAssignType = false;
697 }
698 if (NeedAssignType)
699 updateRegType(Reg, Ty, nullptr, GR, MIB, MRI);
700 } else if (MIOp == TargetOpcode::G_GLOBAL_VALUE) {
701 propagateSPIRVType(&MI, GR, MRI, MIB);
702 }
703
704 if (MII == Begin)
705 ReachedBegin = true;
706 else
707 --MII;
708 }
709 }
710 for (MachineInstr *MI : ToErase) {
711 auto It = RegsAlreadyAddedToDT.find(MI);
712 if (It != RegsAlreadyAddedToDT.end())
713 MRI.replaceRegWith(MI->getOperand(0).getReg(), It->second);
715 }
716
717 // Address the case when IRTranslator introduces instructions with new
718 // registers without associated SPIRV type.
719 for (MachineBasicBlock &MBB : MF) {
720 for (MachineInstr &MI : MBB) {
721 switch (MI.getOpcode()) {
722 case TargetOpcode::G_TRUNC:
723 case TargetOpcode::G_ANYEXT:
724 case TargetOpcode::G_SEXT:
725 case TargetOpcode::G_ZEXT:
726 case TargetOpcode::G_PTRTOINT:
727 case TargetOpcode::COPY:
728 case TargetOpcode::G_ADDRSPACE_CAST:
729 propagateSPIRVType(&MI, GR, MRI, MIB);
730 break;
731 }
732 }
733 }
734}
735
738 MachineIRBuilder MIB) {
740 for (MachineBasicBlock &MBB : MF)
741 for (MachineInstr &MI : MBB)
742 if (isTypeFoldingSupported(MI.getOpcode()))
743 processInstr(MI, MIB, MRI, GR, nullptr);
744}
745
746static Register
748 SmallVector<unsigned, 4> *Ops = nullptr) {
749 Register DefReg;
750 unsigned StartOp = InlineAsm::MIOp_FirstOperand,
752 for (unsigned Idx = StartOp, MISz = MI->getNumOperands(); Idx != MISz;
753 ++Idx) {
754 const MachineOperand &MO = MI->getOperand(Idx);
755 if (MO.isMetadata())
756 continue;
757 if (Idx == AsmDescOp && MO.isImm()) {
758 // compute the index of the next operand descriptor
759 const InlineAsm::Flag F(MO.getImm());
760 AsmDescOp += 1 + F.getNumOperandRegisters();
761 continue;
762 }
763 if (MO.isReg() && MO.isDef()) {
764 if (!Ops)
765 return MO.getReg();
766 DefReg = MO.getReg();
767 } else if (Ops) {
768 Ops->push_back(Idx);
769 }
770 }
771 return DefReg;
772}
773
774static void
776 const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder,
777 const SmallVector<MachineInstr *> &ToProcess) {
779 Register AsmTargetReg;
780 for (unsigned i = 0, Sz = ToProcess.size(); i + 1 < Sz; i += 2) {
781 MachineInstr *I1 = ToProcess[i], *I2 = ToProcess[i + 1];
782 assert(isSpvIntrinsic(*I1, Intrinsic::spv_inline_asm) && I2->isInlineAsm());
783 MIRBuilder.setInsertPt(*I2->getParent(), *I2);
784
785 if (!AsmTargetReg.isValid()) {
786 // define vendor specific assembly target or dialect
787 AsmTargetReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
788 MRI.setRegClass(AsmTargetReg, &SPIRV::iIDRegClass);
789 auto AsmTargetMIB =
790 MIRBuilder.buildInstr(SPIRV::OpAsmTargetINTEL).addDef(AsmTargetReg);
791 addStringImm(ST.getTargetTripleAsStr(), AsmTargetMIB);
792 GR->add(AsmTargetMIB.getInstr(), AsmTargetMIB);
793 }
794
795 // create types
796 const MDNode *IAMD = I1->getOperand(1).getMetadata();
799 for (const auto &ArgTy : FTy->params())
800 ArgTypes.push_back(GR->getOrCreateSPIRVType(
801 ArgTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true));
802 SPIRVTypeInst RetType =
803 GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder,
804 SPIRV::AccessQualifier::ReadWrite, true);
806 FTy, RetType, ArgTypes, MIRBuilder);
807
808 // define vendor specific assembly instructions string
810 MRI.setRegClass(AsmReg, &SPIRV::iIDRegClass);
811 auto AsmMIB = MIRBuilder.buildInstr(SPIRV::OpAsmINTEL)
812 .addDef(AsmReg)
813 .addUse(GR->getSPIRVTypeID(RetType))
814 .addUse(GR->getSPIRVTypeID(FuncType))
815 .addUse(AsmTargetReg);
816 // inline asm string:
817 addStringImm(I2->getOperand(InlineAsm::MIOp_AsmString).getSymbolName(),
818 AsmMIB);
819 // inline asm constraint string:
820 addStringImm(cast<MDString>(I1->getOperand(2).getMetadata()->getOperand(0))
821 ->getString(),
822 AsmMIB);
823 GR->add(AsmMIB.getInstr(), AsmMIB);
824
825 // calls the inline assembly instruction
826 unsigned ExtraInfo = I2->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
827 if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
828 MIRBuilder.buildInstr(SPIRV::OpDecorate)
829 .addUse(AsmReg)
830 .addImm(static_cast<uint32_t>(SPIRV::Decoration::SideEffectsINTEL));
831
833 if (!DefReg.isValid()) {
835 MRI.setRegClass(DefReg, &SPIRV::iIDRegClass);
836 SPIRVTypeInst VoidType = GR->getOrCreateSPIRVType(
837 Type::getVoidTy(MF.getFunction().getContext()), MIRBuilder,
838 SPIRV::AccessQualifier::ReadWrite, true);
839 GR->assignSPIRVTypeToVReg(VoidType, DefReg, MF);
840 }
841
842 auto AsmCall = MIRBuilder.buildInstr(SPIRV::OpAsmCallINTEL)
843 .addDef(DefReg)
844 .addUse(GR->getSPIRVTypeID(RetType))
845 .addUse(AsmReg);
846 for (unsigned IntrIdx = 3; IntrIdx < I1->getNumOperands(); ++IntrIdx)
847 AsmCall.addUse(I1->getOperand(IntrIdx).getReg());
848
849 // IRTranslator gets a bit confused when lowering inline ASM with outputs
850 // and inserts a spurious COPY & TRUNC as registers are assumed to be i64;
851 // we have to clean that up here to prevent erroneous trunc casts either on
852 // a struct (for multiple outputs) or same width integers to get lowered
853 // into SPIR-V
854 if (MRI.hasOneUse(DefReg)) {
855 MachineInstr &CopyMI = *MRI.use_instr_begin(DefReg);
856 if (CopyMI.getOpcode() == TargetOpcode::COPY) {
857 Register CopyDst = CopyMI.getOperand(0).getReg();
858 if (MRI.hasOneUse(CopyDst)) {
859 MachineInstr &TruncMI = *MRI.use_instr_begin(CopyDst);
860 if (TruncMI.getOpcode() == TargetOpcode::G_TRUNC) {
861 MRI.setType(DefReg, GR->getRegType(RetType));
862 Register TruncReg = TruncMI.defs().begin()->getReg();
863 MRI.replaceRegWith(TruncReg, DefReg);
864 invalidateAndEraseMI(GR, &TruncMI);
865 invalidateAndEraseMI(GR, &CopyMI);
866 }
867 }
868 }
869 }
870 }
871 for (MachineInstr *MI : ToProcess)
873}
874
876 const SPIRVSubtarget &ST,
877 MachineIRBuilder MIRBuilder) {
879 for (MachineBasicBlock &MBB : MF) {
880 for (MachineInstr &MI : MBB) {
881 if (isSpvIntrinsic(MI, Intrinsic::spv_inline_asm) ||
882 MI.getOpcode() == TargetOpcode::INLINEASM)
883 ToProcess.push_back(&MI);
884 }
885 }
886 if (ToProcess.size() == 0)
887 return;
888
889 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly))
890 report_fatal_error("Inline assembly instructions require the "
891 "following SPIR-V extension: SPV_INTEL_inline_assembly",
892 false);
893
894 insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess);
895}
896
898 MachineIRBuilder MIB) {
901 for (MachineBasicBlock &MBB : MF) {
902 for (MachineInstr &MI : MBB) {
903 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration) &&
904 !isSpvIntrinsic(MI, Intrinsic::spv_assign_aliasing_decoration) &&
905 !isSpvIntrinsic(MI, Intrinsic::spv_assign_fpmaxerror_decoration))
906 continue;
907 MIB.setInsertPt(*MI.getParent(), MI.getNextNode());
908 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration)) {
909 buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
910 MI.getOperand(2).getMetadata(), ST);
911 } else if (isSpvIntrinsic(MI,
912 Intrinsic::spv_assign_fpmaxerror_decoration)) {
914 MI.getOperand(2).getMetadata()->getOperand(0));
915 uint32_t OpValue = OpV->getValueAPF().bitcastToAPInt().getZExtValue();
916
917 buildOpDecorate(MI.getOperand(1).getReg(), MIB,
918 SPIRV::Decoration::FPMaxErrorDecorationINTEL,
919 {OpValue});
920 } else {
921 GR->buildMemAliasingOpDecorate(MI.getOperand(1).getReg(), MIB,
922 MI.getOperand(2).getImm(),
923 MI.getOperand(3).getMetadata());
924 }
925
926 ToErase.push_back(&MI);
927 }
928 }
929 for (MachineInstr *MI : ToErase)
931}
932
933// LLVM allows the switches to use registers as cases, while SPIR-V required
934// those to be immediate values. This function replaces such operands with the
935// equivalent immediate constant.
938 MachineIRBuilder MIB) {
940 for (MachineBasicBlock &MBB : MF) {
941 for (MachineInstr &MI : MBB) {
942 if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))
943 continue;
944
946 NewOperands.push_back(MI.getOperand(0)); // Opcode
947 NewOperands.push_back(MI.getOperand(1)); // Condition
948 NewOperands.push_back(MI.getOperand(2)); // Default
949 for (unsigned i = 3; i < MI.getNumOperands(); i += 2) {
950 Register Reg = MI.getOperand(i).getReg();
951 MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI);
952 NewOperands.push_back(
954
955 NewOperands.push_back(MI.getOperand(i + 1));
956 }
957
958 assert(MI.getNumOperands() == NewOperands.size());
959 while (MI.getNumOperands() > 0)
960 MI.removeOperand(0);
961 for (auto &MO : NewOperands)
962 MI.addOperand(MO);
963 }
964 }
965}
966
967// Some instructions are used during CodeGen but should never be emitted.
968// Cleaning up those.
972 for (MachineBasicBlock &MBB : MF) {
973 for (MachineInstr &MI : MBB) {
974 if (isSpvIntrinsic(MI, Intrinsic::spv_track_constant) ||
975 MI.getOpcode() == TargetOpcode::G_BRINDIRECT)
976 ToEraseMI.push_back(&MI);
977 }
978 }
979
980 for (MachineInstr *MI : ToEraseMI)
982}
983
984// Find all usages of G_BLOCK_ADDR in our intrinsics and replace those
985// operands/registers by the actual MBB it references.
987 MachineIRBuilder MIB) {
988 // Gather the reverse-mapping BB -> MBB.
990 for (MachineBasicBlock &MBB : MF)
991 BB2MBB[MBB.getBasicBlock()] = &MBB;
992
993 // Gather instructions requiring patching. For now, only those can use
994 // G_BLOCK_ADDR.
995 SmallVector<MachineInstr *, 8> InstructionsToPatch;
996 for (MachineBasicBlock &MBB : MF) {
997 for (MachineInstr &MI : MBB) {
998 if (isSpvIntrinsic(MI, Intrinsic::spv_switch) ||
999 isSpvIntrinsic(MI, Intrinsic::spv_loop_merge) ||
1000 isSpvIntrinsic(MI, Intrinsic::spv_selection_merge))
1001 InstructionsToPatch.push_back(&MI);
1002 }
1003 }
1004
1005 // For each instruction to fix, we replace all the G_BLOCK_ADDR operands by
1006 // the actual MBB it references. Once those references have been updated, we
1007 // can cleanup remaining G_BLOCK_ADDR references.
1008 SmallPtrSet<MachineBasicBlock *, 8> ClearAddressTaken;
1010 MachineRegisterInfo &MRI = MF.getRegInfo();
1011 for (MachineInstr *MI : InstructionsToPatch) {
1013 for (unsigned i = 0; i < MI->getNumOperands(); ++i) {
1014 // The operand is not a register, keep as-is.
1015 if (!MI->getOperand(i).isReg()) {
1016 NewOps.push_back(MI->getOperand(i));
1017 continue;
1018 }
1019
1020 Register Reg = MI->getOperand(i).getReg();
1021 MachineInstr *BuildMBB = MRI.getVRegDef(Reg);
1022 // The register is not the result of G_BLOCK_ADDR, keep as-is.
1023 if (!BuildMBB || BuildMBB->getOpcode() != TargetOpcode::G_BLOCK_ADDR) {
1024 NewOps.push_back(MI->getOperand(i));
1025 continue;
1026 }
1027
1028 assert(BuildMBB && BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&
1029 BuildMBB->getOperand(1).isBlockAddress() &&
1030 BuildMBB->getOperand(1).getBlockAddress());
1031 BasicBlock *BB =
1032 BuildMBB->getOperand(1).getBlockAddress()->getBasicBlock();
1033 auto It = BB2MBB.find(BB);
1034 if (It == BB2MBB.end())
1035 report_fatal_error("cannot find a machine basic block by a basic block "
1036 "in a switch statement");
1037 MachineBasicBlock *ReferencedBlock = It->second;
1038 NewOps.push_back(MachineOperand::CreateMBB(ReferencedBlock));
1039
1040 ClearAddressTaken.insert(ReferencedBlock);
1041 ToEraseMI.insert(BuildMBB);
1042 }
1043
1044 // Replace the operands.
1045 assert(MI->getNumOperands() == NewOps.size());
1046 while (MI->getNumOperands() > 0)
1047 MI->removeOperand(0);
1048 for (auto &MO : NewOps)
1049 MI->addOperand(MO);
1050
1051 if (MachineInstr *Next = MI->getNextNode()) {
1052 if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {
1053 ToEraseMI.insert(Next);
1054 Next = MI->getNextNode();
1055 }
1056 if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)
1057 ToEraseMI.insert(Next);
1058 }
1059 }
1060
1061 // BlockAddress operands were used to keep information between passes,
1062 // let's undo the "address taken" status to reflect that Succ doesn't
1063 // actually correspond to an IR-level basic block.
1064 for (MachineBasicBlock *Succ : ClearAddressTaken)
1065 Succ->setAddressTakenIRBlock(nullptr);
1066
1067 // If we just delete G_BLOCK_ADDR instructions with BlockAddress operands,
1068 // this leaves their BasicBlock counterparts in a "address taken" status. This
1069 // would make AsmPrinter to generate a series of unneeded labels of a "Address
1070 // of block that was removed by CodeGen" kind. Let's first ensure that we
1071 // don't have a dangling BlockAddress constants by zapping the BlockAddress
1072 // nodes, and only after that proceed with erasing G_BLOCK_ADDR instructions.
1073 Constant *Replacement =
1074 ConstantInt::get(Type::getInt32Ty(MF.getFunction().getContext()), 1);
1075 for (MachineInstr *BlockAddrI : ToEraseMI) {
1076 if (BlockAddrI->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
1077 BlockAddress *BA = const_cast<BlockAddress *>(
1078 BlockAddrI->getOperand(1).getBlockAddress());
1080 ConstantExpr::getIntToPtr(Replacement, BA->getType()));
1081 BA->destroyConstant();
1082 }
1083 invalidateAndEraseMI(GR, BlockAddrI);
1084 }
1085}
1086
1088 if (MBB.empty())
1089 return MBB.getNextNode() != nullptr;
1090
1091 // Branching SPIR-V intrinsics are not detected by this generic method.
1092 // Thus, we can only trust negative result.
1093 if (!MBB.canFallThrough())
1094 return false;
1095
1096 // Otherwise, we must manually check if we have a SPIR-V intrinsic which
1097 // prevent an implicit fallthrough.
1098 for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend();
1099 It != E; ++It) {
1100 if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
1101 return false;
1102 }
1103 return true;
1104}
1105
1107 MachineIRBuilder MIB) {
1108 // It is valid for MachineBasicBlocks to not finish with a branch instruction.
1109 // In such cases, they will simply fallthrough their immediate successor.
1110 for (MachineBasicBlock &MBB : MF) {
1112 continue;
1113
1114 assert(MBB.succ_size() == 1);
1115 MIB.setInsertPt(MBB, MBB.end());
1116 MIB.buildBr(**MBB.successors().begin());
1117 }
1118}
1119
1120bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
1121 // Initialize the type registry.
1122 const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
1123 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1124 GR->setCurrentFunc(MF);
1125 MachineIRBuilder MIB(MF);
1126 // a registry of target extension constants
1127 DenseMap<MachineInstr *, Type *> TargetExtConstTypes;
1128 // to keep record of tracked constants
1129 addConstantsToTrack(MF, GR, ST, TargetExtConstTypes);
1130 foldConstantsIntoIntrinsics(MF, GR, MIB);
1131 insertBitcasts(MF, GR, MIB);
1132 generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes);
1133
1134 processSwitchesConstants(MF, GR, MIB);
1135 processBlockAddr(MF, GR, MIB);
1137
1138 processInstrsWithTypeFolding(MF, GR, MIB);
1140 insertSpirvDecorations(MF, GR, MIB);
1141 insertInlineAsm(MF, GR, ST, MIB);
1142 lowerBitcasts(MF, GR, MIB);
1143
1144 return true;
1145}
1146
1147INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,
1148 false)
1149
1150char SPIRVPreLegalizer::ID = 0;
1151
1152FunctionPass *llvm::createSPIRVPreLegalizerPass() {
1153 return new SPIRVPreLegalizer();
1154}
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:1436
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1563
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:225
iterator end()
Definition DenseMap.h:143
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.
void buildOpName(Register Target, const StringRef &Name, MachineIRBuilder &MIRBuilder)
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...
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:247
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
Type * toTypedPointer(Type *Ty)
Definition SPIRVUtils.h:473
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)
void addStringImm(const StringRef &Str, MCInst &Inst)
MachineInstr * getVRegDef(MachineRegisterInfo &MRI, Register Reg)