LLVM 24.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/InstrTypes.h"
24#include "llvm/IR/IntrinsicsSPIRV.h"
26
27#define DEBUG_TYPE "spirv-prelegalizer"
28
29using namespace llvm;
30
31namespace {
32class SPIRVPreLegalizer : public MachineFunctionPass {
33public:
34 static char ID;
35 SPIRVPreLegalizer() : MachineFunctionPass(ID) {}
36 bool runOnMachineFunction(MachineFunction &MF) override;
37 void getAnalysisUsage(AnalysisUsage &AU) const override;
38};
39} // namespace
40
41void SPIRVPreLegalizer::getAnalysisUsage(AnalysisUsage &AU) const {
42 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
44}
45
49 MI->eraseFromParent();
50}
51
52static void
54 const SPIRVSubtarget &STI,
55 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
57 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
58 SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites;
59 for (MachineBasicBlock &MBB : MF) {
60 for (MachineInstr &MI : MBB) {
61 if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant))
62 continue;
63 ToErase.push_back(&MI);
64 Register SrcReg = MI.getOperand(2).getReg();
65 auto *Const =
67 MI.getOperand(3).getMetadata()->getOperand(0))
68 ->getValue());
69 if (auto *GV = dyn_cast<GlobalValue>(Const)) {
70 Register Reg = GR->find(GV, &MF);
71 if (!Reg.isValid()) {
72 GR->add(GV, MRI.getVRegDef(SrcReg));
73 GR->addGlobalObject(GV, &MF, SrcReg);
74 } else
75 RegsAlreadyAddedToDT[&MI] = Reg;
76 } else {
77 Register Reg = GR->find(Const, &MF);
78 if (!Reg.isValid()) {
79 if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) {
80 auto *BuildVec = MRI.getVRegDef(SrcReg);
81 assert(BuildVec &&
82 BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
83 GR->add(Const, BuildVec);
84 for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) {
85 // Ensure that OpConstantComposite reuses a constant when it's
86 // already created and available in the same machine function.
87 Constant *ElemConst = ConstVec->getElementAsConstant(i);
88 Register ElemReg = GR->find(ElemConst, &MF);
89 if (!ElemReg.isValid())
90 GR->add(ElemConst,
91 MRI.getVRegDef(BuildVec->getOperand(1 + i).getReg()));
92 else
93 BuildVec->getOperand(1 + i).setReg(ElemReg);
94 }
95 }
96 if (Const->getType()->isTargetExtTy()) {
97 // remember association so that we can restore it when assign types
98 MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);
99 if (SrcMI)
100 GR->add(Const, SrcMI);
101 if (SrcMI && (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT ||
102 SrcMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF))
103 TargetExtConstTypes[SrcMI] = Const->getType();
104 if (Const->isNullValue()) {
105 MachineBasicBlock &DepMBB = MF.front();
106 MachineIRBuilder MIB(DepMBB, DepMBB.getFirstNonPHI());
108 Const->getType(), MIB, SPIRV::AccessQualifier::ReadWrite,
109 true);
110 assert(SrcMI && "Expected source instruction to be valid");
111 SrcMI->setDesc(STI.getInstrInfo()->get(SPIRV::OpConstantNull));
113 GR->getSPIRVTypeID(ExtType), false));
114 }
115 }
116 } else {
117 RegsAlreadyAddedToDT[&MI] = Reg;
118 // This MI is unused and will be removed. If the MI uses
119 // const_composite, it will be unused and should be removed too.
120 assert(MI.getOperand(2).isReg() && "Reg operand is expected");
121 MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg());
122 if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))
123 ToEraseComposites.push_back(SrcMI);
124 }
125 }
126 }
127 }
128 for (MachineInstr *MI : ToErase) {
129 Register Reg = MI->getOperand(2).getReg();
130 auto It = RegsAlreadyAddedToDT.find(MI);
131 if (It != RegsAlreadyAddedToDT.end())
132 Reg = It->second;
133 auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg());
134 if (!MRI.getRegClassOrNull(Reg) && RC)
135 MRI.setRegClass(Reg, RC);
136 MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg);
138 }
139 for (MachineInstr *MI : ToEraseComposites)
141}
142
145 MachineIRBuilder MIB) {
147 for (MachineBasicBlock &MBB : MF) {
148 for (MachineInstr &MI : MBB) {
149 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name))
150 continue;
151 const MDNode *MD = MI.getOperand(2).getMetadata();
152 StringRef ValueName = cast<MDString>(MD->getOperand(0))->getString();
153 if (ValueName.size() > 0) {
154 MIB.setInsertPt(*MI.getParent(), MI);
155 buildOpName(MI.getOperand(1).getReg(), ValueName, MIB);
156 }
157 ToErase.push_back(&MI);
158 }
159 for (MachineInstr *MI : ToErase)
161 ToErase.clear();
162 }
163}
164
166 MachineRegisterInfo *MRI) {
168 IE = MRI->use_instr_end();
169 I != IE; ++I) {
170 MachineInstr *UseMI = &*I;
171 if ((isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_ptr_type) ||
172 isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_type)) &&
173 UseMI->getOperand(1).getReg() == Reg)
174 return UseMI;
175 }
176 return nullptr;
177}
178
180 Register ResVReg, Register OpReg) {
181 SPIRVTypeInst ResType = GR->getSPIRVTypeForVReg(ResVReg);
182 SPIRVTypeInst OpType = GR->getSPIRVTypeForVReg(OpReg);
183 assert(ResType && OpType && "Operand types are expected");
184 if (!GR->isBitcastCompatible(ResType, OpType))
185 report_fatal_error("incompatible result and operand types in a bitcast");
186 MachineRegisterInfo *MRI = MIB.getMRI();
187 if (!MRI->getRegClassOrNull(ResVReg))
188 MRI->setRegClass(ResVReg, GR->getRegClass(ResType));
189 if (ResType == OpType)
190 MIB.buildInstr(TargetOpcode::COPY).addDef(ResVReg).addUse(OpReg);
191 else
192 MIB.buildInstr(SPIRV::OpBitcast)
193 .addDef(ResVReg)
194 .addUse(GR->getSPIRVTypeID(ResType))
195 .addUse(OpReg);
196}
197
198// We lower G_BITCAST to OpBitcast here to avoid a MachineVerifier error.
199// The verifier checks if the source and destination LLTs of a G_BITCAST are
200// different, but this check is too strict for SPIR-V's typed pointers, which
201// may have the same LLT but different SPIRV type (e.g. pointers to different
202// pointee types). By lowering to OpBitcast here, we bypass the verifier's
203// check. See discussion in https://github.com/llvm/llvm-project/pull/110270
204// for more context.
205//
206// We also handle the llvm.spv.bitcast intrinsic here. If the source and
207// destination SPIR-V types are the same, we lower it to a COPY to enable
208// further optimizations like copy propagation.
210 MachineIRBuilder MIB) {
212 for (MachineBasicBlock &MBB : MF) {
213 for (MachineInstr &MI : MBB) {
214 if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
215 Register DstReg = MI.getOperand(0).getReg();
216 Register SrcReg = MI.getOperand(2).getReg();
217 SPIRVTypeInst DstType = GR->getSPIRVTypeForVReg(DstReg);
218 assert(
219 DstType &&
220 "Expected destination SPIR-V type to have been assigned already.");
221 SPIRVTypeInst SrcType = GR->getSPIRVTypeForVReg(SrcReg);
222 assert(SrcType &&
223 "Expected source SPIR-V type to have been assigned already.");
224 if (DstType == SrcType) {
225 MIB.setInsertPt(*MI.getParent(), MI);
226 MIB.buildCopy(DstReg, SrcReg);
227 ToErase.push_back(&MI);
228 continue;
229 }
230 }
231
232 if (MI.getOpcode() != TargetOpcode::G_BITCAST)
233 continue;
234
235 MIB.setInsertPt(*MI.getParent(), MI);
236 buildOpBitcast(GR, MIB, MI.getOperand(0).getReg(),
237 MI.getOperand(1).getReg());
238 ToErase.push_back(&MI);
239 }
240 }
241 for (MachineInstr *MI : ToErase)
243}
244
246 MachineIRBuilder MIB) {
247 // Get access to information about available extensions
248 const SPIRVSubtarget *ST =
249 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
251 for (MachineBasicBlock &MBB : MF) {
252 for (MachineInstr &MI : MBB) {
253 if (!isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
254 continue;
255 assert(MI.getOperand(2).isReg());
256 MIB.setInsertPt(*MI.getParent(), MI);
257 ToErase.push_back(&MI);
258 Register Def = MI.getOperand(0).getReg();
259 Register Source = MI.getOperand(2).getReg();
260 Type *ElemTy = getMDOperandAsType(MI.getOperand(3).getMetadata(), 0);
261 auto SC =
262 isa<FunctionType>(ElemTy) &&
263 ST->canUseExtension(
264 SPIRV::Extension::SPV_INTEL_function_pointers)
265 ? SPIRV::StorageClass::CodeSectionINTEL
266 : addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST);
267 SPIRVTypeInst AssignedPtrType =
268 GR->getOrCreateSPIRVPointerType(ElemTy, MI, SC);
269
270 // If the ptrcast would be redundant, replace all uses with the source
271 // register.
272 MachineRegisterInfo *MRI = MIB.getMRI();
273 if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) {
274 // Erase Def's assign type instruction if we are going to replace Def.
275 if (MachineInstr *AssignMI = findAssignTypeInstr(Def, MRI))
276 ToErase.push_back(AssignMI);
277 MRI->replaceRegWith(Def, Source);
278 } else {
279 if (!GR->getSPIRVTypeForVReg(Def, &MF))
280 GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
281 MIB.buildBitcast(Def, Source);
282 }
283 }
284 }
285 for (MachineInstr *MI : ToErase)
287}
288
289// Translating GV, IRTranslator sometimes generates following IR:
290// %1 = G_GLOBAL_VALUE
291// %2 = COPY %1
292// %3 = G_ADDRSPACE_CAST %2
293//
294// or
295//
296// %1 = G_ZEXT %2
297// G_MEMCPY ... %2 ...
298//
299// New registers have no SPIRV type and no register class info.
300//
301// Set SPIRV type for GV, propagate it from GV to other instructions,
302// also set register classes.
306 MachineIRBuilder &MIB) {
307 SPIRVTypeInst SpvType = nullptr;
308 assert(MI && "Machine instr is expected");
309 if (MI->getOperand(0).isReg()) {
310 Register Reg = MI->getOperand(0).getReg();
311 SpvType = GR->getSPIRVTypeForVReg(Reg);
312 if (!SpvType) {
313 switch (MI->getOpcode()) {
314 case TargetOpcode::G_FCONSTANT:
315 case TargetOpcode::G_CONSTANT: {
316 MIB.setInsertPt(*MI->getParent(), MI);
317 Type *Ty = MI->getOperand(1).getCImm()->getType();
318 SpvType = GR->getOrCreateSPIRVType(
319 Ty, MIB, SPIRV::AccessQualifier::ReadWrite, true);
320 break;
321 }
322 case TargetOpcode::G_GLOBAL_VALUE: {
323 MIB.setInsertPt(*MI->getParent(), MI);
324 const GlobalValue *Global = MI->getOperand(1).getGlobal();
326 unsigned AddrSpace = Global->getType()->getAddressSpace();
327 // Function pointers use CodeSectionINTEL storage class in SPIR-V when
328 // the SPV_INTEL_function_pointers extension is enabled.
329 const SPIRVSubtarget &ST = MIB.getMF().getSubtarget<SPIRVSubtarget>();
330 if (isa<Function>(Global) &&
331 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
332 AddrSpace =
333 storageClassToAddressSpace(SPIRV::StorageClass::CodeSectionINTEL);
334 auto *Ty = TypedPointerType::get(ElementTy, AddrSpace);
335 SpvType = GR->getOrCreateSPIRVType(
336 Ty, MIB, SPIRV::AccessQualifier::ReadWrite, true);
337 break;
338 }
339 case TargetOpcode::G_ANYEXT:
340 case TargetOpcode::G_SEXT:
341 case TargetOpcode::G_ZEXT: {
342 if (MI->getOperand(1).isReg()) {
343 if (MachineInstr *DefInstr =
344 MRI.getVRegDef(MI->getOperand(1).getReg())) {
345 if (SPIRVTypeInst Def =
346 propagateSPIRVType(DefInstr, GR, MRI, MIB)) {
347 unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);
348 unsigned ExpectedBW =
349 std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);
350 unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);
351 SpvType = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);
352 if (NumElements > 1)
353 SpvType = GR->getOrCreateSPIRVVectorType(SpvType, NumElements,
354 MIB, true);
355 }
356 }
357 }
358 break;
359 }
360 case TargetOpcode::G_PTRTOINT:
361 SpvType = GR->getOrCreateSPIRVIntegerType(
362 MRI.getType(Reg).getScalarSizeInBits(), MIB);
363 break;
364 case TargetOpcode::G_TRUNC:
365 case TargetOpcode::G_ADDRSPACE_CAST:
366 case TargetOpcode::G_PTR_ADD:
367 case TargetOpcode::COPY: {
368 MachineOperand &Op = MI->getOperand(1);
369 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
370 if (Def)
371 SpvType = propagateSPIRVType(Def, GR, MRI, MIB);
372 break;
373 }
374 default:
375 break;
376 }
377 if (SpvType) {
378 // check if the address space needs correction
379 LLT RegType = MRI.getType(Reg);
380 if (SpvType->getOpcode() == SPIRV::OpTypePointer &&
381 RegType.isPointer() &&
383 RegType.getAddressSpace()) {
384 // Don't correct CodeSectionINTEL back to Function for function
385 // pointer G_GLOBAL_VALUE - the LLVM register has address space 0
386 // but the SPIR-V type was intentionally set to CodeSectionINTEL.
387 bool SkipCorrection =
388 MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE &&
389 GR->getPointerStorageClass(SpvType) ==
390 SPIRV::StorageClass::CodeSectionINTEL;
391 if (!SkipCorrection) {
392 const SPIRVSubtarget &ST =
393 MI->getParent()->getParent()->getSubtarget<SPIRVSubtarget>();
394 auto TSC =
395 addressSpaceToStorageClass(RegType.getAddressSpace(), ST);
396 SpvType = GR->changePointerStorageClass(SpvType, TSC, *MI);
397 }
398 }
399 GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
400 }
401 if (!MRI.getRegClassOrNull(Reg))
402 MRI.setRegClass(Reg, SpvType ? GR->getRegClass(SpvType)
403 : &SPIRV::iIDRegClass);
404 }
405 }
406 return SpvType;
407}
408
409// To support current approach and limitations wrt. bit width here we widen a
410// scalar register with a bit width greater than 1 to valid sizes and cap it to
411// 128 width.
412static unsigned widenBitWidthToNextPow2(unsigned BitWidth) {
413 if (BitWidth == 1)
414 return 1; // No need to widen 1-bit values
415 return std::min(std::max<unsigned>(PowerOf2Ceil(BitWidth), 8u), 128u);
416}
417
419 LLT RegType = MRI.getType(Reg);
420 if (!RegType.isScalar())
421 return;
422 unsigned CurrentWidth = RegType.getScalarSizeInBits();
423 unsigned NewWidth = widenBitWidthToNextPow2(CurrentWidth);
424 if (NewWidth != CurrentWidth)
425 MRI.setType(Reg, LLT::scalar(NewWidth));
426}
427
428static void widenCImmType(MachineOperand &MOP) {
429 const ConstantInt *CImmVal = MOP.getCImm();
430 unsigned CurrentWidth = CImmVal->getBitWidth();
431 unsigned NewWidth = widenBitWidthToNextPow2(CurrentWidth);
432 if (NewWidth != CurrentWidth) {
433 // Replace the immediate value with the widened version
434 MOP.setCImm(ConstantInt::get(CImmVal->getType()->getContext(),
435 CImmVal->getValue().zextOrTrunc(NewWidth)));
436 }
437}
438
440 MachineBasicBlock &MBB = *Def->getParent();
442 Def->getNextNode() ? Def->getNextNode()->getIterator() : MBB.end();
443 // Skip all the PHI and debug instructions.
444 while (DefIt != MBB.end() &&
445 (DefIt->isPHI() || DefIt->isDebugOrPseudoInstr()))
446 DefIt = std::next(DefIt);
447 MIB.setInsertPt(MBB, DefIt);
448}
449
450namespace llvm {
453 MachineRegisterInfo &MRI) {
454 assert((Ty || SpvType) && "Either LLVM or SPIRV type is expected.");
455 MachineInstr *Def = MRI.getVRegDef(Reg);
456 setInsertPtAfterDef(MIB, Def);
457 if (!SpvType)
458 SpvType = GR->getOrCreateSPIRVType(Ty, MIB,
459 SPIRV::AccessQualifier::ReadWrite, true);
460 if (!MRI.getRegClassOrNull(Reg))
461 MRI.setRegClass(Reg, GR->getRegClass(SpvType));
462 if (!MRI.getType(Reg).isValid())
463 MRI.setType(Reg, GR->getRegType(SpvType));
464 GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
465}
466
469 SPIRVTypeInst KnownResType) {
470 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
471 for (auto &Op : MI.operands()) {
472 if (!Op.isReg() || Op.isDef())
473 continue;
474 Register OpReg = Op.getReg();
475 SPIRVTypeInst SpvType = GR->getSPIRVTypeForVReg(OpReg);
476 if (!SpvType && KnownResType) {
477 SpvType = KnownResType;
478 GR->assignSPIRVTypeToVReg(KnownResType, OpReg, *MI.getMF());
479 }
480 assert(SpvType);
481 if (!MRI.getRegClassOrNull(OpReg))
482 MRI.setRegClass(OpReg, GR->getRegClass(SpvType));
483 if (!MRI.getType(OpReg).isValid())
484 MRI.setType(OpReg, GR->getRegType(SpvType));
485 }
486}
487} // namespace llvm
488
489// Sign-sensitive integer ops: their result depends on the value of the input
490// sign bit at position (width-1). On sub-pow2 widths the general widening
491// loop is a pure LLT relabel, which leaves the sign bit at the *original*
492// position instead of the widened MSB. These ops therefore need an explicit
493// G_SEXT_INREG on each value operand to move the sign bit up.
494//
495// Signed-vs-unsigned G_ICMP is distinguished by its predicate operand.
496//
497// TODO: follow-up PRs will add the remaining sign-sensitive opcodes
498// (e.g. G_SMIN/G_SMAX, G_SADDSAT/G_SSUBSAT, signed overflow ops).
499static bool isSignSensitiveOp(const MachineInstr &MI) {
500 switch (MI.getOpcode()) {
501 case TargetOpcode::G_ASHR:
502 case TargetOpcode::G_SDIV:
503 case TargetOpcode::G_SREM:
504 return true;
505 case TargetOpcode::G_ICMP:
506 return CmpInst::isSigned(
507 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()));
508 default:
509 return false;
510 }
511}
512
514 // Width before widening of each value-operand vreg (one entry per vreg).
516 // Ops whose value operand(s) need replacing, ordered for reproducible vreg
517 // numbering.
519};
520
521// Collect sign-sensitive ops with narrow scalar value operands and their
522// pre-widening widths, before later passes retype those vregs to pow2 LLTs
523// and the original width is no longer recoverable.
526 MachineRegisterInfo &MRI) {
528 auto RecordIfNarrow = [&](Register Reg) {
529 LLT Ty = MRI.getType(Reg);
530 if (!Ty.isScalar())
531 return false;
532 unsigned W = Ty.getScalarSizeInBits();
533 if (widenBitWidthToNextPow2(W) == W)
534 return false;
535 Info.OrigWidth.try_emplace(Reg, W);
536 return true;
537 };
538 for (MachineBasicBlock &MBB : MF) {
539 for (MachineInstr &MI : MBB) {
540 if (!isSignSensitiveOp(MI))
541 continue;
542 // Value operands are the trailing two, past any def or predicate.
543 unsigned N = MI.getNumOperands();
544 const MachineOperand &LHS = MI.getOperand(N - 2);
545 const MachineOperand &RHS = MI.getOperand(N - 1);
546 // Sign-sensitive opcodes carry register operands only.
547 assert(LHS.isReg() && RHS.isReg());
548 bool NeedsRewrite = RecordIfNarrow(LHS.getReg());
549 NeedsRewrite = RecordIfNarrow(RHS.getReg()) || NeedsRewrite;
550 if (NeedsRewrite)
551 Info.Worklist.push_back(&MI);
552 }
553 }
554 return Info;
555}
556
557// For every recorded sign-sensitive op, insert G_SEXT_INREG on each value
558// operand whose original width was narrower than the widened pow2 width and
559// retype the operand's vreg LLT in place to the widened width.
560//
561// Info must have been populated by recordSignSensitiveOperandWidths before
562// other passes retyped the vregs; otherwise the narrow widths needed here
563// are lost.
564//
565// TODO: handle vector operands.
567 MachineIRBuilder &MIB,
569 const SignSensitiveWideningInfo &Info) {
570 // Emit G_SEXT_INREG from Reg's recorded narrow width; retypes Reg to the
571 // widened width and returns the sign-extended vreg.
572 auto SignExtendReg = [&](Register Reg, unsigned OldW,
574 unsigned NewW = widenBitWidthToNextPow2(OldW);
575 LLT NewLLT = LLT::scalar(NewW);
576 SPIRVTypeInst SpvTy = GR->getOrCreateSPIRVIntegerType(NewW, MIB);
577 Register SExted = MRI.createGenericVirtualRegister(NewLLT);
578 GR->assignSPIRVTypeToVReg(SpvTy, SExted, MF);
579 MRI.setRegClass(SExted, GR->getRegClass(SpvTy));
580 MRI.setType(Reg, NewLLT);
581 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
582 MIB.buildSExtInReg(SExted, Reg, OldW);
583 return SExted;
584 };
585
586 // TODO: when the same narrow vreg feeds multiple sign-sensitive ops (e.g.
587 // sdiv %x, %y and srem %x, %y), emit one shared G_SEXT_INREG instead of one
588 // per use.
589 for (MachineInstr *MI : Info.Worklist) {
590 unsigned N = MI->getNumOperands();
591 MachineOperand &LHS = MI->getOperand(N - 2);
592 MachineOperand &RHS = MI->getOperand(N - 1);
593 Register LHSReg = LHS.getReg();
594 Register RHSReg = RHS.getReg();
595 if (auto It = Info.OrigWidth.find(LHSReg); It != Info.OrigWidth.end())
596 LHS.setReg(SignExtendReg(LHSReg, It->second, *MI));
597 // Same vreg on both sides (e.g. G_ICMP slt %x, %x): reuse the sext just
598 // emitted for LHS instead of emitting a second one.
599 if (RHSReg == LHSReg) {
600 RHS.setReg(LHS.getReg());
601 continue;
602 }
603 if (auto It = Info.OrigWidth.find(RHSReg); It != Info.OrigWidth.end())
604 RHS.setReg(SignExtendReg(RHSReg, It->second, *MI));
605 }
606}
607
608static void
611 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
612 // Get access to information about available extensions
613 const SPIRVSubtarget *ST =
614 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
615
618 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
619
620 bool IsExtendedInts =
621 ST->canUseExtension(
622 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers) ||
623 ST->canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
624 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
625
626 if (!IsExtendedInts) {
627 // Without arbitrary precision integer extensions, SPIR-V only supports
628 // integer widths of 8, 16, 32, 64. Non-standard widths (e.g., i24, i40)
629 // must be widened to the next power of two.
630 //
631 // Record the original widths of sign-sensitive operands before either
632 // the G_TRUNC handling or the general widening loop retypes vregs, then
633 // rewrite those ops after G_TRUNC processing using the recorded widths.
634 SignSensitiveWideningInfo SignSensitiveInfo =
636
637 // G_TRUNC requires special handling because its semantics depend on the
638 // original destination width. For example:
639 // %dst:s24 = G_TRUNC %src:s64
640 // After widening s24 to s32, we cannot simply do:
641 // %dst:s32 = G_TRUNC %src:s64
642 // because this would keep 32 bits instead of 24. Instead, we insert a
643 // G_AND to mask the value to the original width:
644 // %mask:s64 = G_CONSTANT 0xFFFFFF ; 24-bit mask
645 // %masked:s64 = G_AND %src:s64, %mask
646 // %dst:s32 = G_TRUNC %masked:s64
647 // If src and dst widen to the same size, G_TRUNC is replaced entirely:
648 // %mask:s64 = G_CONSTANT 0xFFFFFFFFFF ; 40-bit mask
649 // %dst:s64 = G_AND %src:s64, %mask
650 SmallVector<MachineInstr *, 8> TruncToRemove;
651 for (MachineBasicBlock &MBB : MF) {
652 for (MachineInstr &MI : MBB) {
653 unsigned MIOp = MI.getOpcode();
654 if (MIOp != TargetOpcode::G_TRUNC)
655 continue;
656 assert(MI.getNumOperands() == 2);
657 assert(MI.getOperand(0).isReg());
658 assert(MI.getOperand(1).isReg());
659
660 Register DstReg = MI.getOperand(0).getReg();
661 Register SrcReg = MI.getOperand(1).getReg();
662
663 LLT DstTy = MRI.getType(DstReg);
664 LLT SrcTy = MRI.getType(SrcReg);
665 assert((DstTy.isScalar() || DstTy.isVector()) &&
666 (SrcTy.isScalar() || SrcTy.isVector()) &&
667 "Expected scalar or vector G_TRUNC types");
668 assert(DstTy.isVector() == SrcTy.isVector() &&
669 "Expected matching scalar/vector G_TRUNC types");
670 assert((!DstTy.isVector() ||
671 DstTy.getElementCount() == SrcTy.getElementCount()) &&
672 "Expected equal vector element counts");
673
674 unsigned OriginalDstWidth = DstTy.getScalarSizeInBits();
675 unsigned OriginalSrcWidth = SrcTy.getScalarSizeInBits();
676
677 unsigned NewDstWidth = widenBitWidthToNextPow2(OriginalDstWidth);
678 unsigned NewSrcWidth = widenBitWidthToNextPow2(OriginalSrcWidth);
679 LLT NewDstTy = DstTy.changeElementSize(NewDstWidth);
680 LLT NewSrcTy = SrcTy.changeElementSize(NewSrcWidth);
681
682 // No Dst width change means no truncation semantics change, but the
683 // source still needs a legal type.
684 if (OriginalDstWidth == NewDstWidth) {
685 MRI.setType(SrcReg, NewSrcTy);
686 continue;
687 }
688
689 MRI.setType(SrcReg, NewSrcTy);
690 MRI.setType(DstReg, NewDstTy);
691
692 MIB.setInsertPt(MBB, MI.getIterator());
693 APInt Mask = APInt::getLowBitsSet(NewSrcWidth, OriginalDstWidth);
694 MachineInstrBuilder MaskReg =
695 DstTy.isVector()
697 NewSrcTy,
699 : MIB.buildConstant(NewSrcTy, Mask);
700 Register MaskedReg = MRI.createGenericVirtualRegister(NewSrcTy);
701 MIB.buildAnd(MaskedReg, SrcReg, MaskReg);
702
703 if (NewSrcWidth == NewDstWidth) {
704 // Rekey OrigWidth from DstReg to MaskedReg so widenSignSensitiveOps
705 // still sees the narrow original width after replaceRegWith.
706 if (auto It = SignSensitiveInfo.OrigWidth.find(DstReg);
707 It != SignSensitiveInfo.OrigWidth.end()) {
708 unsigned W = It->second;
709 SignSensitiveInfo.OrigWidth.erase(It);
710 SignSensitiveInfo.OrigWidth.try_emplace(MaskedReg, W);
711 }
712 MRI.replaceRegWith(DstReg, MaskedReg);
713 TruncToRemove.push_back(&MI);
714 } else {
715 MI.getOperand(1).setReg(MaskedReg);
716 }
717 }
718 }
719 for (MachineInstr *MI : TruncToRemove)
720 MI->eraseFromParent();
721
722 widenSignSensitiveOps(MF, GR, MIB, MRI, SignSensitiveInfo);
723 }
724
725 for (MachineBasicBlock *MBB : post_order(&MF)) {
726 if (MBB->empty())
727 continue;
728
729 bool ReachedBegin = false;
730 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
731 !ReachedBegin;) {
732 MachineInstr &MI = *MII;
733 unsigned MIOp = MI.getOpcode();
734
735 if (!IsExtendedInts) {
736 // validate bit width of scalar registers and constant immediates
737 for (auto &MOP : MI.operands()) {
738 if (MOP.isReg())
739 widenScalarType(MOP.getReg(), MRI);
740 else if (MOP.isCImm())
741 widenCImmType(MOP);
742 }
743 }
744
745 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
746 Register Reg = MI.getOperand(1).getReg();
747 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
748 Type *ElementTy = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
749 SPIRVTypeInst AssignedPtrType = GR->getOrCreateSPIRVPointerType(
750 ElementTy, MI,
751 addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));
752 // The intrinsic also carries vector-of-pointer values produced by
753 // scalarized vector GEPs; wrap the pointer in OpTypeVector to match
754 // the vreg's LLT.
755 LLT RegTy = MRI.getType(Reg);
756 if (RegTy.isValid() && RegTy.isVector())
757 AssignedPtrType = GR->getOrCreateSPIRVVectorType(
758 AssignedPtrType, RegTy.getNumElements(), MIB, true);
759 MachineInstr *Def = MRI.getVRegDef(Reg);
760 assert(Def && "Expecting an instruction that defines the register");
761 // G_GLOBAL_VALUE already has type info.
762 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
763 updateRegType(Reg, nullptr, AssignedPtrType, GR, MIB,
764 MF.getRegInfo());
765 ToErase.push_back(&MI);
766 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
767 Register Reg = MI.getOperand(1).getReg();
768 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
769 MachineInstr *Def = MRI.getVRegDef(Reg);
770 assert(Def && "Expecting an instruction that defines the register");
771 // G_GLOBAL_VALUE already has type info.
772 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
773 updateRegType(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
774 ToErase.push_back(&MI);
775 } else if (MIOp == TargetOpcode::FAKE_USE && MI.getNumOperands() > 0) {
776 MachineInstr *MdMI = MI.getPrevNode();
777 if (MdMI && isSpvIntrinsic(*MdMI, Intrinsic::spv_value_md)) {
778 // It's an internal service info from before IRTranslator passes.
779 MachineInstr *Def = getVRegDef(MRI, MI.getOperand(0).getReg());
780 for (unsigned I = 1, E = MI.getNumOperands(); I != E && Def; ++I)
781 if (getVRegDef(MRI, MI.getOperand(I).getReg()) != Def)
782 Def = nullptr;
783 if (Def) {
784 const MDNode *MD = MdMI->getOperand(1).getMetadata();
786 cast<MDString>(MD->getOperand(1))->getString();
787 const MDNode *TypeMD = cast<MDNode>(MD->getOperand(0));
788 Type *ValueTy = getMDOperandAsType(TypeMD, 0);
789 GR->addValueAttrs(Def, std::make_pair(ValueTy, ValueName.str()));
790 }
791 ToErase.push_back(MdMI);
792 }
793 ToErase.push_back(&MI);
794 } else if (MIOp == TargetOpcode::G_CONSTANT ||
795 MIOp == TargetOpcode::G_FCONSTANT ||
796 MIOp == TargetOpcode::G_BUILD_VECTOR) {
797 // %rc = G_CONSTANT ty Val
798 // Ensure %rc has a valid SPIR-V type assigned in the Global Registry.
799 Register Reg = MI.getOperand(0).getReg();
800 bool NeedAssignType = !GR->getSPIRVTypeForVReg(Reg);
801 Type *Ty = nullptr;
802 if (MIOp == TargetOpcode::G_CONSTANT) {
803 auto TargetExtIt = TargetExtConstTypes.find(&MI);
804 Ty = TargetExtIt == TargetExtConstTypes.end()
805 ? MI.getOperand(1).getCImm()->getType()
806 : TargetExtIt->second;
807 const ConstantInt *OpCI = MI.getOperand(1).getCImm();
808 // TODO: we may wish to analyze here if OpCI is zero and LLT RegType =
809 // MRI.getType(Reg); RegType.isPointer() is true, so that we observe
810 // at this point not i64/i32 constant but null pointer in the
811 // corresponding address space of RegType.getAddressSpace(). This may
812 // help to successfully validate the case when a OpConstantComposite's
813 // constituent has type that does not match Result Type of
814 // OpConstantComposite (see, for example,
815 // pointers/PtrCast-null-in-OpSpecConstantOp.ll).
816 Register PrimaryReg = GR->find(OpCI, &MF);
817 if (!PrimaryReg.isValid()) {
818 GR->add(OpCI, &MI);
819 } else if (PrimaryReg != Reg &&
820 MRI.getType(Reg) == MRI.getType(PrimaryReg)) {
821 auto *RCReg = MRI.getRegClassOrNull(Reg);
822 auto *RCPrimary = MRI.getRegClassOrNull(PrimaryReg);
823 if (!RCReg || RCPrimary == RCReg) {
824 RegsAlreadyAddedToDT[&MI] = PrimaryReg;
825 ToErase.push_back(&MI);
826 NeedAssignType = false;
827 }
828 }
829 } else if (MIOp == TargetOpcode::G_FCONSTANT) {
830 Ty = MI.getOperand(1).getFPImm()->getType();
831 } else {
832 assert(MIOp == TargetOpcode::G_BUILD_VECTOR);
833 Type *ElemTy = nullptr;
834 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
835 assert(ElemMI);
836
837 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT) {
838 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
839 } else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT) {
840 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
841 } else {
842 if (SPIRVTypeInst ElemSpvType =
843 GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg(), &MF))
844 ElemTy = const_cast<Type *>(GR->getTypeForSPIRVType(ElemSpvType));
845 }
846 if (ElemTy)
847 Ty = VectorType::get(
848 ElemTy, MI.getNumExplicitOperands() - MI.getNumExplicitDefs(),
849 false);
850 else
851 NeedAssignType = false;
852 }
853 if (NeedAssignType)
854 updateRegType(Reg, Ty, nullptr, GR, MIB, MRI);
855 } else if (MIOp == TargetOpcode::G_GLOBAL_VALUE) {
856 propagateSPIRVType(&MI, GR, MRI, MIB);
857 }
858
859 if (MII == Begin)
860 ReachedBegin = true;
861 else
862 --MII;
863 }
864 }
865 for (MachineInstr *MI : ToErase) {
866 auto It = RegsAlreadyAddedToDT.find(MI);
867 if (It != RegsAlreadyAddedToDT.end())
868 MRI.replaceRegWith(MI->getOperand(0).getReg(), It->second);
870 }
871
872 // Address the case when IRTranslator introduces instructions with new
873 // registers without associated SPIRV type.
874 for (MachineBasicBlock &MBB : MF) {
875 for (MachineInstr &MI : MBB) {
876 switch (MI.getOpcode()) {
877 case TargetOpcode::G_TRUNC:
878 case TargetOpcode::G_ANYEXT:
879 case TargetOpcode::G_SEXT:
880 case TargetOpcode::G_ZEXT:
881 case TargetOpcode::G_PTRTOINT:
882 case TargetOpcode::COPY:
883 case TargetOpcode::G_ADDRSPACE_CAST:
884 propagateSPIRVType(&MI, GR, MRI, MIB);
885 break;
886 }
887 }
888 }
889}
890
893 MachineIRBuilder MIB) {
895 for (MachineBasicBlock &MBB : MF)
896 for (MachineInstr &MI : MBB)
897 if (isTypeFoldingSupported(MI.getOpcode()))
898 processInstr(MI, MIB, MRI, GR, nullptr);
899}
900
901static Register
903 SmallVector<unsigned, 4> *Ops = nullptr) {
904 Register DefReg;
905 unsigned StartOp = InlineAsm::MIOp_FirstOperand,
907 for (unsigned Idx = StartOp, MISz = MI->getNumOperands(); Idx != MISz;
908 ++Idx) {
909 const MachineOperand &MO = MI->getOperand(Idx);
910 if (MO.isMetadata())
911 continue;
912 if (Idx == AsmDescOp && MO.isImm()) {
913 // compute the index of the next operand descriptor
914 const InlineAsm::Flag F(MO.getImm());
915 AsmDescOp += 1 + F.getNumOperandRegisters();
916 continue;
917 }
918 if (MO.isReg() && MO.isDef()) {
919 if (!Ops)
920 return MO.getReg();
921 DefReg = MO.getReg();
922 } else if (Ops) {
923 Ops->push_back(Idx);
924 }
925 }
926 return DefReg;
927}
928
929static void
931 const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder,
932 const SmallVector<MachineInstr *> &ToProcess) {
934 Register AsmTargetReg;
935 for (unsigned i = 0, Sz = ToProcess.size(); i + 1 < Sz; i += 2) {
936 MachineInstr *I1 = ToProcess[i], *I2 = ToProcess[i + 1];
937 assert(isSpvIntrinsic(*I1, Intrinsic::spv_inline_asm) && I2->isInlineAsm());
938 MIRBuilder.setInsertPt(*I2->getParent(), *I2);
939
940 if (!AsmTargetReg.isValid()) {
941 // define vendor specific assembly target or dialect
942 AsmTargetReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
943 MRI.setRegClass(AsmTargetReg, &SPIRV::iIDRegClass);
944 auto AsmTargetMIB =
945 MIRBuilder.buildInstr(SPIRV::OpAsmTargetINTEL).addDef(AsmTargetReg);
946 addStringImm(ST.getTargetTripleAsStr(), AsmTargetMIB);
947 GR->add(AsmTargetMIB.getInstr(), AsmTargetMIB);
948 }
949
950 // create types
951 const MDNode *IAMD = I1->getOperand(1).getMetadata();
954 for (const auto &ArgTy : FTy->params())
955 ArgTypes.push_back(GR->getOrCreateSPIRVType(
956 ArgTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true));
957 SPIRVTypeInst RetType =
958 GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder,
959 SPIRV::AccessQualifier::ReadWrite, true);
961 FTy, RetType, ArgTypes, MIRBuilder);
962
963 // define vendor specific assembly instructions string
965 MRI.setRegClass(AsmReg, &SPIRV::iIDRegClass);
966 auto AsmMIB = MIRBuilder.buildInstr(SPIRV::OpAsmINTEL)
967 .addDef(AsmReg)
968 .addUse(GR->getSPIRVTypeID(RetType))
969 .addUse(GR->getSPIRVTypeID(FuncType))
970 .addUse(AsmTargetReg);
971 // inline asm string:
972 addStringImm(I2->getOperand(InlineAsm::MIOp_AsmString).getSymbolName(),
973 AsmMIB);
974 // inline asm constraint string:
975 addStringImm(cast<MDString>(I1->getOperand(2).getMetadata()->getOperand(0))
976 ->getString(),
977 AsmMIB);
978 GR->add(AsmMIB.getInstr(), AsmMIB);
979
980 // calls the inline assembly instruction
981 unsigned ExtraInfo = I2->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
982 if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
983 MIRBuilder.buildInstr(SPIRV::OpDecorate)
984 .addUse(AsmReg)
985 .addImm(static_cast<uint32_t>(SPIRV::Decoration::SideEffectsINTEL));
986
988 if (!DefReg.isValid()) {
990 MRI.setRegClass(DefReg, &SPIRV::iIDRegClass);
991 SPIRVTypeInst VoidType = GR->getOrCreateSPIRVType(
992 Type::getVoidTy(MF.getFunction().getContext()), MIRBuilder,
993 SPIRV::AccessQualifier::ReadWrite, true);
994 GR->assignSPIRVTypeToVReg(VoidType, DefReg, MF);
995 }
996
997 auto AsmCall = MIRBuilder.buildInstr(SPIRV::OpAsmCallINTEL)
998 .addDef(DefReg)
999 .addUse(GR->getSPIRVTypeID(RetType))
1000 .addUse(AsmReg);
1001 for (unsigned IntrIdx = 3; IntrIdx < I1->getNumOperands(); ++IntrIdx)
1002 AsmCall.addUse(I1->getOperand(IntrIdx).getReg());
1003
1004 // IRTranslator gets a bit confused when lowering inline ASM with outputs
1005 // and inserts a spurious COPY & TRUNC as registers are assumed to be i64;
1006 // we have to clean that up here to prevent erroneous trunc casts either on
1007 // a struct (for multiple outputs) or same width integers to get lowered
1008 // into SPIR-V
1009 if (MRI.hasOneUse(DefReg)) {
1010 MachineInstr &CopyMI = *MRI.use_instr_begin(DefReg);
1011 if (CopyMI.getOpcode() == TargetOpcode::COPY) {
1012 Register CopyDst = CopyMI.getOperand(0).getReg();
1013 if (MRI.hasOneUse(CopyDst)) {
1014 MachineInstr &TruncMI = *MRI.use_instr_begin(CopyDst);
1015 if (TruncMI.getOpcode() == TargetOpcode::G_TRUNC) {
1016 MRI.setType(DefReg, GR->getRegType(RetType));
1017 Register TruncReg = TruncMI.defs().begin()->getReg();
1018 MRI.replaceRegWith(TruncReg, DefReg);
1019 invalidateAndEraseMI(GR, &TruncMI);
1020 invalidateAndEraseMI(GR, &CopyMI);
1021 }
1022 }
1023 }
1024 }
1025 }
1026 for (MachineInstr *MI : ToProcess)
1028}
1029
1031 const SPIRVSubtarget &ST,
1032 MachineIRBuilder MIRBuilder) {
1034 for (MachineBasicBlock &MBB : MF) {
1035 for (MachineInstr &MI : MBB) {
1036 if (isSpvIntrinsic(MI, Intrinsic::spv_inline_asm) ||
1037 MI.getOpcode() == TargetOpcode::INLINEASM)
1038 ToProcess.push_back(&MI);
1039 }
1040 }
1041 if (ToProcess.size() == 0)
1042 return;
1043
1044 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly))
1045 report_fatal_error("Inline assembly instructions require the "
1046 "following SPIR-V extension: SPV_INTEL_inline_assembly",
1047 false);
1048
1049 insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess);
1050}
1051
1053 MachineIRBuilder MIB) {
1056 for (MachineBasicBlock &MBB : MF) {
1057 for (MachineInstr &MI : MBB) {
1058 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration) &&
1059 !isSpvIntrinsic(MI, Intrinsic::spv_assign_aliasing_decoration) &&
1060 !isSpvIntrinsic(MI, Intrinsic::spv_assign_fpmaxerror_decoration))
1061 continue;
1062 MIB.setInsertPt(*MI.getParent(), MI.getNextNode());
1063 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration)) {
1064 buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
1065 MI.getOperand(2).getMetadata(), ST);
1066 } else if (isSpvIntrinsic(MI,
1067 Intrinsic::spv_assign_fpmaxerror_decoration)) {
1069 MI.getOperand(2).getMetadata()->getOperand(0));
1070 uint32_t OpValue = OpV->getValueAPF().bitcastToAPInt().getZExtValue();
1071
1072 buildOpDecorate(MI.getOperand(1).getReg(), MIB,
1073 SPIRV::Decoration::FPMaxErrorDecorationINTEL,
1074 {OpValue});
1075 } else {
1076 GR->buildMemAliasingOpDecorate(MI.getOperand(1).getReg(), MIB,
1077 MI.getOperand(2).getImm(),
1078 MI.getOperand(3).getMetadata());
1079 }
1080
1081 ToErase.push_back(&MI);
1082 }
1083 }
1084 for (MachineInstr *MI : ToErase)
1086}
1087
1088// LLVM allows the switches to use registers as cases, while SPIR-V required
1089// those to be immediate values. This function replaces such operands with the
1090// equivalent immediate constant.
1093 MachineIRBuilder MIB) {
1094 MachineRegisterInfo &MRI = MF.getRegInfo();
1095 for (MachineBasicBlock &MBB : MF) {
1096 for (MachineInstr &MI : MBB) {
1097 if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))
1098 continue;
1099
1101 NewOperands.push_back(MI.getOperand(0)); // Opcode
1102 NewOperands.push_back(MI.getOperand(1)); // Condition
1103 NewOperands.push_back(MI.getOperand(2)); // Default
1104 for (unsigned i = 3; i < MI.getNumOperands(); i += 2) {
1105 Register Reg = MI.getOperand(i).getReg();
1106 MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI);
1107 NewOperands.push_back(
1109
1110 NewOperands.push_back(MI.getOperand(i + 1));
1111 }
1112
1113 assert(MI.getNumOperands() == NewOperands.size());
1114 while (MI.getNumOperands() > 0)
1115 MI.removeOperand(0);
1116 for (auto &MO : NewOperands)
1117 MI.addOperand(MO);
1118 }
1119 }
1120}
1121
1122// Some instructions are used during CodeGen but should never be emitted.
1123// Cleaning up those.
1125 SPIRVGlobalRegistry *GR) {
1127 for (MachineBasicBlock &MBB : MF) {
1128 for (MachineInstr &MI : MBB) {
1129 if (isSpvIntrinsic(MI, Intrinsic::spv_track_constant) ||
1130 MI.getOpcode() == TargetOpcode::G_BRINDIRECT)
1131 ToEraseMI.push_back(&MI);
1132 }
1133 }
1134
1135 for (MachineInstr *MI : ToEraseMI)
1137}
1138
1139// Find all usages of G_BLOCK_ADDR in our intrinsics and replace those
1140// operands/registers by the actual MBB it references.
1142 MachineIRBuilder MIB) {
1143 // Gather the reverse-mapping BB -> MBB.
1145 for (MachineBasicBlock &MBB : MF)
1146 BB2MBB[MBB.getBasicBlock()] = &MBB;
1147
1148 // Gather instructions requiring patching. For now, only those can use
1149 // G_BLOCK_ADDR.
1150 SmallVector<MachineInstr *, 8> InstructionsToPatch;
1151 for (MachineBasicBlock &MBB : MF) {
1152 for (MachineInstr &MI : MBB) {
1153 if (isSpvIntrinsic(MI, Intrinsic::spv_switch) ||
1154 isSpvIntrinsic(MI, Intrinsic::spv_loop_merge) ||
1155 isSpvIntrinsic(MI, Intrinsic::spv_selection_merge))
1156 InstructionsToPatch.push_back(&MI);
1157 }
1158 }
1159
1160 // For each instruction to fix, we replace all the G_BLOCK_ADDR operands by
1161 // the actual MBB it references. Once those references have been updated, we
1162 // can cleanup remaining G_BLOCK_ADDR references.
1163 SmallPtrSet<MachineBasicBlock *, 8> ClearAddressTaken;
1165 MachineRegisterInfo &MRI = MF.getRegInfo();
1166 for (MachineInstr *MI : InstructionsToPatch) {
1168 for (unsigned i = 0; i < MI->getNumOperands(); ++i) {
1169 // The operand is not a register, keep as-is.
1170 if (!MI->getOperand(i).isReg()) {
1171 NewOps.push_back(MI->getOperand(i));
1172 continue;
1173 }
1174
1175 Register Reg = MI->getOperand(i).getReg();
1176 MachineInstr *BuildMBB = MRI.getVRegDef(Reg);
1177 // The register is not the result of G_BLOCK_ADDR, keep as-is.
1178 if (!BuildMBB || BuildMBB->getOpcode() != TargetOpcode::G_BLOCK_ADDR) {
1179 NewOps.push_back(MI->getOperand(i));
1180 continue;
1181 }
1182
1183 assert(BuildMBB && BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&
1184 BuildMBB->getOperand(1).isBlockAddress() &&
1185 BuildMBB->getOperand(1).getBlockAddress());
1186 BasicBlock *BB =
1187 BuildMBB->getOperand(1).getBlockAddress()->getBasicBlock();
1188 auto It = BB2MBB.find(BB);
1189 if (It == BB2MBB.end())
1190 report_fatal_error("cannot find a machine basic block by a basic block "
1191 "in a switch statement");
1192 MachineBasicBlock *ReferencedBlock = It->second;
1193 NewOps.push_back(MachineOperand::CreateMBB(ReferencedBlock));
1194
1195 ClearAddressTaken.insert(ReferencedBlock);
1196 ToEraseMI.insert(BuildMBB);
1197 }
1198
1199 // Replace the operands.
1200 assert(MI->getNumOperands() == NewOps.size());
1201 while (MI->getNumOperands() > 0)
1202 MI->removeOperand(0);
1203 for (auto &MO : NewOps)
1204 MI->addOperand(MO);
1205
1206 if (MachineInstr *Next = MI->getNextNode()) {
1207 if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {
1208 ToEraseMI.insert(Next);
1209 Next = MI->getNextNode();
1210 }
1211 if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)
1212 ToEraseMI.insert(Next);
1213 }
1214 }
1215
1216 // BlockAddress operands were used to keep information between passes,
1217 // let's undo the "address taken" status to reflect that Succ doesn't
1218 // actually correspond to an IR-level basic block.
1219 for (MachineBasicBlock *Succ : ClearAddressTaken)
1220 Succ->setAddressTakenIRBlock(nullptr);
1221
1222 // If we just delete G_BLOCK_ADDR instructions with BlockAddress operands,
1223 // this leaves their BasicBlock counterparts in a "address taken" status. This
1224 // would make AsmPrinter to generate a series of unneeded labels of a "Address
1225 // of block that was removed by CodeGen" kind. Let's first ensure that we
1226 // don't have a dangling BlockAddress constants by zapping the BlockAddress
1227 // nodes, and only after that proceed with erasing G_BLOCK_ADDR instructions.
1228 Constant *Replacement =
1229 ConstantInt::get(Type::getInt32Ty(MF.getFunction().getContext()), 1);
1230 for (MachineInstr *BlockAddrI : ToEraseMI) {
1231 if (BlockAddrI->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
1232 BlockAddress *BA = const_cast<BlockAddress *>(
1233 BlockAddrI->getOperand(1).getBlockAddress());
1235 ConstantExpr::getIntToPtr(Replacement, BA->getType()));
1236 BA->destroyConstant();
1237 }
1238 invalidateAndEraseMI(GR, BlockAddrI);
1239 }
1240}
1241
1243 if (MBB.empty())
1244 return MBB.getNextNode() != nullptr;
1245
1246 // Branching SPIR-V intrinsics are not detected by this generic method.
1247 // Thus, we can only trust negative result.
1248 if (!MBB.canFallThrough())
1249 return false;
1250
1251 // Otherwise, we must manually check if we have a SPIR-V intrinsic which
1252 // prevent an implicit fallthrough.
1253 for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend();
1254 It != E; ++It) {
1255 if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
1256 return false;
1257 }
1258 return true;
1259}
1260
1262 MachineIRBuilder MIB) {
1263 // It is valid for MachineBasicBlocks to not finish with a branch instruction.
1264 // In such cases, they will simply fallthrough their immediate successor.
1265 for (MachineBasicBlock &MBB : MF) {
1267 continue;
1268
1269 assert(MBB.succ_size() == 1);
1270 MIB.setInsertPt(MBB, MBB.end());
1271 MIB.buildBr(**MBB.successors().begin());
1272 }
1273}
1274
1275bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
1276 // Initialize the type registry.
1277 const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
1278 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1279 GR->setCurrentFunc(MF);
1280 MachineIRBuilder MIB(MF);
1281 // a registry of target extension constants
1282 DenseMap<MachineInstr *, Type *> TargetExtConstTypes;
1283 // to keep record of tracked constants
1284 addConstantsToTrack(MF, GR, ST, TargetExtConstTypes);
1285 foldConstantsIntoIntrinsics(MF, GR, MIB);
1286 insertBitcasts(MF, GR, MIB);
1287 generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes);
1288
1289 processSwitchesConstants(MF, GR, MIB);
1290 processBlockAddr(MF, GR, MIB);
1292
1293 processInstrsWithTypeFolding(MF, GR, MIB);
1295 insertSpirvDecorations(MF, GR, MIB);
1296 insertInlineAsm(MF, GR, ST, MIB);
1297 lowerBitcasts(MF, GR, MIB);
1298
1299 return true;
1300}
1301
1302INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,
1303 false)
1304
1305char SPIRVPreLegalizer::ID = 0;
1306
1307FunctionPass *llvm::createSPIRVPreLegalizerPass() {
1308 return new SPIRVPreLegalizer();
1309}
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 SignSensitiveWideningInfo recordSignSensitiveOperandWidths(MachineFunction &MF, MachineRegisterInfo &MRI)
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 bool isSignSensitiveOp(const MachineInstr &MI)
static void invalidateAndEraseMI(SPIRVGlobalRegistry *GR, MachineInstr *MI)
static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB, DenseMap< MachineInstr *, Type * > &TargetExtConstTypes)
static void widenSignSensitiveOps(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, const SignSensitiveWideningInfo &Info)
Value * RHS
Value * LHS
APInt bitcastToAPInt() const
Definition APFloat.h:1467
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
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
bool isSigned() const
Definition InstrTypes.h:993
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
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:299
bool erase(const KeyT &Val)
Definition DenseMap.h:377
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.
MachineInstrBuilder buildSExtInReg(const DstOp &Res, const SrcOp &Op, int64_t ImmOp)
Build and insert Res = G_SEXT_INREG Op, ImmOp.
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
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:244
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
Definition MathExtras.h:386
void buildOpName(Register Target, StringRef Name, MachineIRBuilder &MIRBuilder)
Type * toTypedPointer(Type *Ty)
Definition SPIRVUtils.h:474
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)
#define N
SmallVector< MachineInstr * > Worklist
DenseMap< Register, unsigned > OrigWidth