LLVM 20.0.0git
SPIRVInstructionSelector.cpp
Go to the documentation of this file.
1//===- SPIRVInstructionSelector.cpp ------------------------------*- 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// This file implements the targeting of the InstructionSelector class for
10// SPIRV.
11// TODO: This should be generated by TableGen.
12//
13//===----------------------------------------------------------------------===//
14
17#include "SPIRV.h"
18#include "SPIRVGlobalRegistry.h"
19#include "SPIRVInstrInfo.h"
21#include "SPIRVRegisterInfo.h"
22#include "SPIRVTargetMachine.h"
23#include "SPIRVUtils.h"
24#include "llvm/ADT/APFloat.h"
32#include "llvm/IR/IntrinsicsSPIRV.h"
33#include "llvm/Support/Debug.h"
34
35namespace {
36
37struct SyncScopeIDs {
38 llvm::SyncScope::ID Work_ItemSSID;
39 llvm::SyncScope::ID WorkGroupSSID;
40 llvm::SyncScope::ID DeviceSSID;
41 llvm::SyncScope::ID AllSVMDevicesSSID;
42 llvm::SyncScope::ID SubGroupSSID;
43
44 SyncScopeIDs() {}
45 SyncScopeIDs(llvm::LLVMContext &Context) {
46 Work_ItemSSID = Context.getOrInsertSyncScopeID("work_item");
47 WorkGroupSSID = Context.getOrInsertSyncScopeID("workgroup");
48 DeviceSSID = Context.getOrInsertSyncScopeID("device");
49 AllSVMDevicesSSID = Context.getOrInsertSyncScopeID("all_svm_devices");
50 SubGroupSSID = Context.getOrInsertSyncScopeID("sub_group");
51 }
52};
53
54} // namespace
55
56#define DEBUG_TYPE "spirv-isel"
57
58using namespace llvm;
59namespace CL = SPIRV::OpenCLExtInst;
60namespace GL = SPIRV::GLSLExtInst;
61
63 std::vector<std::pair<SPIRV::InstructionSet::InstructionSet, uint32_t>>;
64
65namespace {
66
67#define GET_GLOBALISEL_PREDICATE_BITSET
68#include "SPIRVGenGlobalISel.inc"
69#undef GET_GLOBALISEL_PREDICATE_BITSET
70
71class SPIRVInstructionSelector : public InstructionSelector {
72 const SPIRVSubtarget &STI;
73 const SPIRVInstrInfo &TII;
75 const RegisterBankInfo &RBI;
78 SyncScopeIDs SSIDs;
79 MachineFunction *HasVRegsReset = nullptr;
80
81 /// We need to keep track of the number we give to anonymous global values to
82 /// generate the same name every time when this is needed.
83 mutable DenseMap<const GlobalValue *, unsigned> UnnamedGlobalIDs;
84
85public:
86 SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
87 const SPIRVSubtarget &ST,
88 const RegisterBankInfo &RBI);
89 void setupMF(MachineFunction &MF, GISelKnownBits *KB,
90 CodeGenCoverage *CoverageInfo, ProfileSummaryInfo *PSI,
91 BlockFrequencyInfo *BFI) override;
92 // Common selection code. Instruction-specific selection occurs in spvSelect.
93 bool select(MachineInstr &I) override;
94 static const char *getName() { return DEBUG_TYPE; }
95
96#define GET_GLOBALISEL_PREDICATES_DECL
97#include "SPIRVGenGlobalISel.inc"
98#undef GET_GLOBALISEL_PREDICATES_DECL
99
100#define GET_GLOBALISEL_TEMPORARIES_DECL
101#include "SPIRVGenGlobalISel.inc"
102#undef GET_GLOBALISEL_TEMPORARIES_DECL
103
104private:
105 void resetVRegsType(MachineFunction &MF);
106
107 // tblgen-erated 'select' implementation, used as the initial selector for
108 // the patterns that don't require complex C++.
109 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
110
111 // All instruction-specific selection that didn't happen in "select()".
112 // Is basically a large Switch/Case delegating to all other select method.
113 bool spvSelect(Register ResVReg, const SPIRVType *ResType,
114 MachineInstr &I) const;
115
116 bool selectGlobalValue(Register ResVReg, MachineInstr &I,
117 const MachineInstr *Init = nullptr) const;
118
119 bool selectUnOpWithSrc(Register ResVReg, const SPIRVType *ResType,
120 MachineInstr &I, Register SrcReg,
121 unsigned Opcode) const;
122 bool selectUnOp(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
123 unsigned Opcode) const;
124
125 bool selectBitcast(Register ResVReg, const SPIRVType *ResType,
126 MachineInstr &I) const;
127
128 bool selectLoad(Register ResVReg, const SPIRVType *ResType,
129 MachineInstr &I) const;
130 bool selectStore(MachineInstr &I) const;
131
132 bool selectStackSave(Register ResVReg, const SPIRVType *ResType,
133 MachineInstr &I) const;
134 bool selectStackRestore(MachineInstr &I) const;
135
136 bool selectMemOperation(Register ResVReg, MachineInstr &I) const;
137
138 bool selectAtomicRMW(Register ResVReg, const SPIRVType *ResType,
139 MachineInstr &I, unsigned NewOpcode,
140 unsigned NegateOpcode = 0) const;
141
142 bool selectAtomicCmpXchg(Register ResVReg, const SPIRVType *ResType,
143 MachineInstr &I) const;
144
145 bool selectFence(MachineInstr &I) const;
146
147 bool selectAddrSpaceCast(Register ResVReg, const SPIRVType *ResType,
148 MachineInstr &I) const;
149
150 bool selectAnyOrAll(Register ResVReg, const SPIRVType *ResType,
151 MachineInstr &I, unsigned OpType) const;
152
153 bool selectAll(Register ResVReg, const SPIRVType *ResType,
154 MachineInstr &I) const;
155
156 bool selectAny(Register ResVReg, const SPIRVType *ResType,
157 MachineInstr &I) const;
158
159 bool selectBitreverse(Register ResVReg, const SPIRVType *ResType,
160 MachineInstr &I) const;
161
162 bool selectBuildVector(Register ResVReg, const SPIRVType *ResType,
163 MachineInstr &I) const;
164 bool selectSplatVector(Register ResVReg, const SPIRVType *ResType,
165 MachineInstr &I) const;
166
167 bool selectCmp(Register ResVReg, const SPIRVType *ResType,
168 unsigned comparisonOpcode, MachineInstr &I) const;
169
170 bool selectICmp(Register ResVReg, const SPIRVType *ResType,
171 MachineInstr &I) const;
172 bool selectFCmp(Register ResVReg, const SPIRVType *ResType,
173 MachineInstr &I) const;
174
175 bool selectFmix(Register ResVReg, const SPIRVType *ResType,
176 MachineInstr &I) const;
177
178 bool selectLength(Register ResVReg, const SPIRVType *ResType,
179 MachineInstr &I) const;
180
181 bool selectFrac(Register ResVReg, const SPIRVType *ResType,
182 MachineInstr &I) const;
183
184 bool selectRsqrt(Register ResVReg, const SPIRVType *ResType,
185 MachineInstr &I) const;
186
187 void renderImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
188 int OpIdx) const;
189 void renderFImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
190 int OpIdx) const;
191
192 bool selectConst(Register ResVReg, const SPIRVType *ResType, const APInt &Imm,
193 MachineInstr &I) const;
194
195 bool selectSelect(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
196 bool IsSigned) const;
197 bool selectIToF(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
198 bool IsSigned, unsigned Opcode) const;
199 bool selectExt(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
200 bool IsSigned) const;
201
202 bool selectTrunc(Register ResVReg, const SPIRVType *ResType,
203 MachineInstr &I) const;
204
205 bool selectIntToBool(Register IntReg, Register ResVReg, MachineInstr &I,
206 const SPIRVType *intTy, const SPIRVType *boolTy) const;
207
208 bool selectOpUndef(Register ResVReg, const SPIRVType *ResType,
209 MachineInstr &I) const;
210 bool selectFreeze(Register ResVReg, const SPIRVType *ResType,
211 MachineInstr &I) const;
212 bool selectIntrinsic(Register ResVReg, const SPIRVType *ResType,
213 MachineInstr &I) const;
214 bool selectExtractVal(Register ResVReg, const SPIRVType *ResType,
215 MachineInstr &I) const;
216 bool selectInsertVal(Register ResVReg, const SPIRVType *ResType,
217 MachineInstr &I) const;
218 bool selectExtractElt(Register ResVReg, const SPIRVType *ResType,
219 MachineInstr &I) const;
220 bool selectInsertElt(Register ResVReg, const SPIRVType *ResType,
221 MachineInstr &I) const;
222 bool selectGEP(Register ResVReg, const SPIRVType *ResType,
223 MachineInstr &I) const;
224
225 bool selectFrameIndex(Register ResVReg, const SPIRVType *ResType,
226 MachineInstr &I) const;
227 bool selectAllocaArray(Register ResVReg, const SPIRVType *ResType,
228 MachineInstr &I) const;
229
230 bool selectBranch(MachineInstr &I) const;
231 bool selectBranchCond(MachineInstr &I) const;
232
233 bool selectPhi(Register ResVReg, const SPIRVType *ResType,
234 MachineInstr &I) const;
235
236 bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
237 MachineInstr &I, CL::OpenCLExtInst CLInst) const;
238 bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
239 MachineInstr &I, CL::OpenCLExtInst CLInst,
240 GL::GLSLExtInst GLInst) const;
241 bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
242 MachineInstr &I, const ExtInstList &ExtInsts) const;
243
244 bool selectLog10(Register ResVReg, const SPIRVType *ResType,
245 MachineInstr &I) const;
246
247 bool selectNormalize(Register ResVReg, const SPIRVType *ResType,
248 MachineInstr &I) const;
249
250 bool selectSaturate(Register ResVReg, const SPIRVType *ResType,
251 MachineInstr &I) const;
252
253 bool selectSpvThreadId(Register ResVReg, const SPIRVType *ResType,
254 MachineInstr &I) const;
255
257
258 Register buildI32Constant(uint32_t Val, MachineInstr &I,
259 const SPIRVType *ResType = nullptr) const;
260
261 Register buildZerosVal(const SPIRVType *ResType, MachineInstr &I) const;
262 Register buildZerosValF(const SPIRVType *ResType, MachineInstr &I) const;
263 Register buildOnesVal(bool AllOnes, const SPIRVType *ResType,
264 MachineInstr &I) const;
265 Register buildOnesValF(const SPIRVType *ResType, MachineInstr &I) const;
266
267 bool wrapIntoSpecConstantOp(MachineInstr &I,
268 SmallVector<Register> &CompositeArgs) const;
269};
270
271} // end anonymous namespace
272
273#define GET_GLOBALISEL_IMPL
274#include "SPIRVGenGlobalISel.inc"
275#undef GET_GLOBALISEL_IMPL
276
277SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
278 const SPIRVSubtarget &ST,
279 const RegisterBankInfo &RBI)
280 : InstructionSelector(), STI(ST), TII(*ST.getInstrInfo()),
281 TRI(*ST.getRegisterInfo()), RBI(RBI), GR(*ST.getSPIRVGlobalRegistry()),
283#include "SPIRVGenGlobalISel.inc"
286#include "SPIRVGenGlobalISel.inc"
288{
289}
290
291void SPIRVInstructionSelector::setupMF(MachineFunction &MF, GISelKnownBits *KB,
292 CodeGenCoverage *CoverageInfo,
294 BlockFrequencyInfo *BFI) {
295 SSIDs = SyncScopeIDs(MF.getFunction().getContext());
296 MRI = &MF.getRegInfo();
297 GR.setCurrentFunc(MF);
298 InstructionSelector::setupMF(MF, KB, CoverageInfo, PSI, BFI);
299}
300
301// Ensure that register classes correspond to pattern matching rules.
302void SPIRVInstructionSelector::resetVRegsType(MachineFunction &MF) {
303 if (HasVRegsReset == &MF)
304 return;
305 HasVRegsReset = &MF;
306
308 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
310 LLT Ty = MRI.getType(Reg);
311 if (Ty.isScalar())
312 MRI.setType(Reg, LLT::scalar(32));
313 else if (Ty.isVector() && !Ty.isPointer())
314 MRI.setType(Reg, LLT::scalar(32));
315 }
316 for (const auto &MBB : MF) {
317 for (const auto &MI : MBB) {
318 if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)
319 continue;
320 Register DstReg = MI.getOperand(0).getReg();
321 LLT DstType = MRI.getType(DstReg);
322 Register SrcReg = MI.getOperand(1).getReg();
323 LLT SrcType = MRI.getType(SrcReg);
324 if (DstType != SrcType)
325 MRI.setType(DstReg, MRI.getType(SrcReg));
326
327 const TargetRegisterClass *DstRC = MRI.getRegClassOrNull(DstReg);
328 const TargetRegisterClass *SrcRC = MRI.getRegClassOrNull(SrcReg);
329 if (DstRC != SrcRC && SrcRC)
330 MRI.setRegClass(DstReg, SrcRC);
331 }
332 }
333}
334
335static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI);
336
337// Defined in SPIRVLegalizerInfo.cpp.
338extern bool isTypeFoldingSupported(unsigned Opcode);
339
340bool SPIRVInstructionSelector::select(MachineInstr &I) {
341 resetVRegsType(*I.getParent()->getParent());
342
343 assert(I.getParent() && "Instruction should be in a basic block!");
344 assert(I.getParent()->getParent() && "Instruction should be in a function!");
345
346 Register Opcode = I.getOpcode();
347 // If it's not a GMIR instruction, we've selected it already.
348 if (!isPreISelGenericOpcode(Opcode)) {
349 if (Opcode == SPIRV::ASSIGN_TYPE) { // These pseudos aren't needed any more.
350 Register DstReg = I.getOperand(0).getReg();
351 Register SrcReg = I.getOperand(1).getReg();
352 auto *Def = MRI->getVRegDef(SrcReg);
353 if (isTypeFoldingSupported(Def->getOpcode())) {
354 if (MRI->getType(DstReg).isPointer())
355 MRI->setType(DstReg, LLT::scalar(32));
356 bool Res = selectImpl(I, *CoverageInfo);
357 assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT);
358 if (Res)
359 return Res;
360 }
361 MRI->setRegClass(DstReg, &SPIRV::iIDRegClass);
362 MRI->replaceRegWith(SrcReg, DstReg);
363 I.removeFromParent();
364 return true;
365 } else if (I.getNumDefs() == 1) {
366 // Make all vregs 32 bits (for SPIR-V IDs).
367 MRI->setType(I.getOperand(0).getReg(), LLT::scalar(32));
368 }
370 }
371
372 if (I.getNumOperands() != I.getNumExplicitOperands()) {
373 LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
374 return false;
375 }
376
377 // Common code for getting return reg+type, and removing selected instr
378 // from parent occurs here. Instr-specific selection happens in spvSelect().
379 bool HasDefs = I.getNumDefs() > 0;
380 Register ResVReg = HasDefs ? I.getOperand(0).getReg() : Register(0);
381 SPIRVType *ResType = HasDefs ? GR.getSPIRVTypeForVReg(ResVReg) : nullptr;
382 assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
383 if (spvSelect(ResVReg, ResType, I)) {
384 if (HasDefs) // Make all vregs 32 bits (for SPIR-V IDs).
385 for (unsigned i = 0; i < I.getNumDefs(); ++i)
386 MRI->setType(I.getOperand(i).getReg(), LLT::scalar(32));
387 I.removeFromParent();
388 return true;
389 }
390 return false;
391}
392
393bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
394 const SPIRVType *ResType,
395 MachineInstr &I) const {
396 const unsigned Opcode = I.getOpcode();
397 if (isTypeFoldingSupported(Opcode) && Opcode != TargetOpcode::G_CONSTANT)
398 return selectImpl(I, *CoverageInfo);
399 switch (Opcode) {
400 case TargetOpcode::G_CONSTANT:
401 return selectConst(ResVReg, ResType, I.getOperand(1).getCImm()->getValue(),
402 I);
403 case TargetOpcode::G_GLOBAL_VALUE:
404 return selectGlobalValue(ResVReg, I);
405 case TargetOpcode::G_IMPLICIT_DEF:
406 return selectOpUndef(ResVReg, ResType, I);
407 case TargetOpcode::G_FREEZE:
408 return selectFreeze(ResVReg, ResType, I);
409
410 case TargetOpcode::G_INTRINSIC:
411 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
412 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
413 return selectIntrinsic(ResVReg, ResType, I);
414 case TargetOpcode::G_BITREVERSE:
415 return selectBitreverse(ResVReg, ResType, I);
416
417 case TargetOpcode::G_BUILD_VECTOR:
418 return selectBuildVector(ResVReg, ResType, I);
419 case TargetOpcode::G_SPLAT_VECTOR:
420 return selectSplatVector(ResVReg, ResType, I);
421
422 case TargetOpcode::G_SHUFFLE_VECTOR: {
423 MachineBasicBlock &BB = *I.getParent();
424 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle))
425 .addDef(ResVReg)
426 .addUse(GR.getSPIRVTypeID(ResType))
427 .addUse(I.getOperand(1).getReg())
428 .addUse(I.getOperand(2).getReg());
429 for (auto V : I.getOperand(3).getShuffleMask())
430 MIB.addImm(V);
431 return MIB.constrainAllUses(TII, TRI, RBI);
432 }
433 case TargetOpcode::G_MEMMOVE:
434 case TargetOpcode::G_MEMCPY:
435 case TargetOpcode::G_MEMSET:
436 return selectMemOperation(ResVReg, I);
437
438 case TargetOpcode::G_ICMP:
439 return selectICmp(ResVReg, ResType, I);
440 case TargetOpcode::G_FCMP:
441 return selectFCmp(ResVReg, ResType, I);
442
443 case TargetOpcode::G_FRAME_INDEX:
444 return selectFrameIndex(ResVReg, ResType, I);
445
446 case TargetOpcode::G_LOAD:
447 return selectLoad(ResVReg, ResType, I);
448 case TargetOpcode::G_STORE:
449 return selectStore(I);
450
451 case TargetOpcode::G_BR:
452 return selectBranch(I);
453 case TargetOpcode::G_BRCOND:
454 return selectBranchCond(I);
455
456 case TargetOpcode::G_PHI:
457 return selectPhi(ResVReg, ResType, I);
458
459 case TargetOpcode::G_FPTOSI:
460 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
461 case TargetOpcode::G_FPTOUI:
462 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
463
464 case TargetOpcode::G_SITOFP:
465 return selectIToF(ResVReg, ResType, I, true, SPIRV::OpConvertSToF);
466 case TargetOpcode::G_UITOFP:
467 return selectIToF(ResVReg, ResType, I, false, SPIRV::OpConvertUToF);
468
469 case TargetOpcode::G_CTPOP:
470 return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitCount);
471 case TargetOpcode::G_SMIN:
472 return selectExtInst(ResVReg, ResType, I, CL::s_min, GL::SMin);
473 case TargetOpcode::G_UMIN:
474 return selectExtInst(ResVReg, ResType, I, CL::u_min, GL::UMin);
475
476 case TargetOpcode::G_SMAX:
477 return selectExtInst(ResVReg, ResType, I, CL::s_max, GL::SMax);
478 case TargetOpcode::G_UMAX:
479 return selectExtInst(ResVReg, ResType, I, CL::u_max, GL::UMax);
480
481 case TargetOpcode::G_FMA:
482 return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
483
484 case TargetOpcode::G_FPOW:
485 return selectExtInst(ResVReg, ResType, I, CL::pow, GL::Pow);
486 case TargetOpcode::G_FPOWI:
487 return selectExtInst(ResVReg, ResType, I, CL::pown);
488
489 case TargetOpcode::G_FEXP:
490 return selectExtInst(ResVReg, ResType, I, CL::exp, GL::Exp);
491 case TargetOpcode::G_FEXP2:
492 return selectExtInst(ResVReg, ResType, I, CL::exp2, GL::Exp2);
493
494 case TargetOpcode::G_FLOG:
495 return selectExtInst(ResVReg, ResType, I, CL::log, GL::Log);
496 case TargetOpcode::G_FLOG2:
497 return selectExtInst(ResVReg, ResType, I, CL::log2, GL::Log2);
498 case TargetOpcode::G_FLOG10:
499 return selectLog10(ResVReg, ResType, I);
500
501 case TargetOpcode::G_FABS:
502 return selectExtInst(ResVReg, ResType, I, CL::fabs, GL::FAbs);
503 case TargetOpcode::G_ABS:
504 return selectExtInst(ResVReg, ResType, I, CL::s_abs, GL::SAbs);
505
506 case TargetOpcode::G_FMINNUM:
507 case TargetOpcode::G_FMINIMUM:
508 return selectExtInst(ResVReg, ResType, I, CL::fmin, GL::NMin);
509 case TargetOpcode::G_FMAXNUM:
510 case TargetOpcode::G_FMAXIMUM:
511 return selectExtInst(ResVReg, ResType, I, CL::fmax, GL::NMax);
512
513 case TargetOpcode::G_FCOPYSIGN:
514 return selectExtInst(ResVReg, ResType, I, CL::copysign);
515
516 case TargetOpcode::G_FCEIL:
517 return selectExtInst(ResVReg, ResType, I, CL::ceil, GL::Ceil);
518 case TargetOpcode::G_FFLOOR:
519 return selectExtInst(ResVReg, ResType, I, CL::floor, GL::Floor);
520
521 case TargetOpcode::G_FCOS:
522 return selectExtInst(ResVReg, ResType, I, CL::cos, GL::Cos);
523 case TargetOpcode::G_FSIN:
524 return selectExtInst(ResVReg, ResType, I, CL::sin, GL::Sin);
525 case TargetOpcode::G_FTAN:
526 return selectExtInst(ResVReg, ResType, I, CL::tan, GL::Tan);
527 case TargetOpcode::G_FACOS:
528 return selectExtInst(ResVReg, ResType, I, CL::acos, GL::Acos);
529 case TargetOpcode::G_FASIN:
530 return selectExtInst(ResVReg, ResType, I, CL::asin, GL::Asin);
531 case TargetOpcode::G_FATAN:
532 return selectExtInst(ResVReg, ResType, I, CL::atan, GL::Atan);
533 case TargetOpcode::G_FCOSH:
534 return selectExtInst(ResVReg, ResType, I, CL::cosh, GL::Cosh);
535 case TargetOpcode::G_FSINH:
536 return selectExtInst(ResVReg, ResType, I, CL::sinh, GL::Sinh);
537 case TargetOpcode::G_FTANH:
538 return selectExtInst(ResVReg, ResType, I, CL::tanh, GL::Tanh);
539
540 case TargetOpcode::G_FSQRT:
541 return selectExtInst(ResVReg, ResType, I, CL::sqrt, GL::Sqrt);
542
543 case TargetOpcode::G_CTTZ:
544 case TargetOpcode::G_CTTZ_ZERO_UNDEF:
545 return selectExtInst(ResVReg, ResType, I, CL::ctz);
546 case TargetOpcode::G_CTLZ:
547 case TargetOpcode::G_CTLZ_ZERO_UNDEF:
548 return selectExtInst(ResVReg, ResType, I, CL::clz);
549
550 case TargetOpcode::G_INTRINSIC_ROUND:
551 return selectExtInst(ResVReg, ResType, I, CL::round, GL::Round);
552 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
553 return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven);
554 case TargetOpcode::G_INTRINSIC_TRUNC:
555 return selectExtInst(ResVReg, ResType, I, CL::trunc, GL::Trunc);
556 case TargetOpcode::G_FRINT:
557 case TargetOpcode::G_FNEARBYINT:
558 return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven);
559
560 case TargetOpcode::G_SMULH:
561 return selectExtInst(ResVReg, ResType, I, CL::s_mul_hi);
562 case TargetOpcode::G_UMULH:
563 return selectExtInst(ResVReg, ResType, I, CL::u_mul_hi);
564
565 case TargetOpcode::G_SADDSAT:
566 return selectExtInst(ResVReg, ResType, I, CL::s_add_sat);
567 case TargetOpcode::G_UADDSAT:
568 return selectExtInst(ResVReg, ResType, I, CL::u_add_sat);
569 case TargetOpcode::G_SSUBSAT:
570 return selectExtInst(ResVReg, ResType, I, CL::s_sub_sat);
571 case TargetOpcode::G_USUBSAT:
572 return selectExtInst(ResVReg, ResType, I, CL::u_sub_sat);
573
574 case TargetOpcode::G_SEXT:
575 return selectExt(ResVReg, ResType, I, true);
576 case TargetOpcode::G_ANYEXT:
577 case TargetOpcode::G_ZEXT:
578 return selectExt(ResVReg, ResType, I, false);
579 case TargetOpcode::G_TRUNC:
580 return selectTrunc(ResVReg, ResType, I);
581 case TargetOpcode::G_FPTRUNC:
582 case TargetOpcode::G_FPEXT:
583 return selectUnOp(ResVReg, ResType, I, SPIRV::OpFConvert);
584
585 case TargetOpcode::G_PTRTOINT:
586 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertPtrToU);
587 case TargetOpcode::G_INTTOPTR:
588 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertUToPtr);
589 case TargetOpcode::G_BITCAST:
590 return selectBitcast(ResVReg, ResType, I);
591 case TargetOpcode::G_ADDRSPACE_CAST:
592 return selectAddrSpaceCast(ResVReg, ResType, I);
593 case TargetOpcode::G_PTR_ADD: {
594 // Currently, we get G_PTR_ADD only as a result of translating
595 // global variables, initialized with constant expressions like GV + Const
596 // (see test opencl/basic/progvar_prog_scope_init.ll).
597 // TODO: extend the handler once we have other cases.
598 assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
599 Register GV = I.getOperand(1).getReg();
600 MachineRegisterInfo::def_instr_iterator II = MRI->def_instr_begin(GV);
601 (void)II;
602 assert(((*II).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
603 (*II).getOpcode() == TargetOpcode::COPY ||
604 (*II).getOpcode() == SPIRV::OpVariable) &&
605 isImm(I.getOperand(2), MRI));
606 Register Idx = buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I);
607 MachineBasicBlock &BB = *I.getParent();
608 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
609 .addDef(ResVReg)
610 .addUse(GR.getSPIRVTypeID(ResType))
611 .addImm(static_cast<uint32_t>(
612 SPIRV::Opcode::InBoundsPtrAccessChain))
613 .addUse(GV)
614 .addUse(Idx)
615 .addUse(I.getOperand(2).getReg());
616 return MIB.constrainAllUses(TII, TRI, RBI);
617 }
618
619 case TargetOpcode::G_ATOMICRMW_OR:
620 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicOr);
621 case TargetOpcode::G_ATOMICRMW_ADD:
622 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicIAdd);
623 case TargetOpcode::G_ATOMICRMW_AND:
624 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicAnd);
625 case TargetOpcode::G_ATOMICRMW_MAX:
626 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMax);
627 case TargetOpcode::G_ATOMICRMW_MIN:
628 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMin);
629 case TargetOpcode::G_ATOMICRMW_SUB:
630 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicISub);
631 case TargetOpcode::G_ATOMICRMW_XOR:
632 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicXor);
633 case TargetOpcode::G_ATOMICRMW_UMAX:
634 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMax);
635 case TargetOpcode::G_ATOMICRMW_UMIN:
636 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMin);
637 case TargetOpcode::G_ATOMICRMW_XCHG:
638 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicExchange);
639 case TargetOpcode::G_ATOMIC_CMPXCHG:
640 return selectAtomicCmpXchg(ResVReg, ResType, I);
641
642 case TargetOpcode::G_ATOMICRMW_FADD:
643 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFAddEXT);
644 case TargetOpcode::G_ATOMICRMW_FSUB:
645 // Translate G_ATOMICRMW_FSUB to OpAtomicFAddEXT with negative value operand
646 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFAddEXT,
647 SPIRV::OpFNegate);
648 case TargetOpcode::G_ATOMICRMW_FMIN:
649 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFMinEXT);
650 case TargetOpcode::G_ATOMICRMW_FMAX:
651 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFMaxEXT);
652
653 case TargetOpcode::G_FENCE:
654 return selectFence(I);
655
656 case TargetOpcode::G_STACKSAVE:
657 return selectStackSave(ResVReg, ResType, I);
658 case TargetOpcode::G_STACKRESTORE:
659 return selectStackRestore(I);
660
661 case TargetOpcode::G_UNMERGE_VALUES:
662 return selectUnmergeValues(I);
663
664 default:
665 return false;
666 }
667}
668
669bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
670 const SPIRVType *ResType,
672 CL::OpenCLExtInst CLInst) const {
673 return selectExtInst(ResVReg, ResType, I,
674 {{SPIRV::InstructionSet::OpenCL_std, CLInst}});
675}
676
677bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
678 const SPIRVType *ResType,
680 CL::OpenCLExtInst CLInst,
681 GL::GLSLExtInst GLInst) const {
682 ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst},
683 {SPIRV::InstructionSet::GLSL_std_450, GLInst}};
684 return selectExtInst(ResVReg, ResType, I, ExtInsts);
685}
686
687bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
688 const SPIRVType *ResType,
690 const ExtInstList &Insts) const {
691
692 for (const auto &Ex : Insts) {
693 SPIRV::InstructionSet::InstructionSet Set = Ex.first;
694 uint32_t Opcode = Ex.second;
695 if (STI.canUseExtInstSet(Set)) {
696 MachineBasicBlock &BB = *I.getParent();
697 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
698 .addDef(ResVReg)
699 .addUse(GR.getSPIRVTypeID(ResType))
700 .addImm(static_cast<uint32_t>(Set))
701 .addImm(Opcode);
702 const unsigned NumOps = I.getNumOperands();
703 for (unsigned i = 1; i < NumOps; ++i)
704 MIB.add(I.getOperand(i));
705 return MIB.constrainAllUses(TII, TRI, RBI);
706 }
707 }
708 return false;
709}
710
711bool SPIRVInstructionSelector::selectUnOpWithSrc(Register ResVReg,
712 const SPIRVType *ResType,
714 Register SrcReg,
715 unsigned Opcode) const {
716 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
717 .addDef(ResVReg)
718 .addUse(GR.getSPIRVTypeID(ResType))
719 .addUse(SrcReg)
720 .constrainAllUses(TII, TRI, RBI);
721}
722
723bool SPIRVInstructionSelector::selectUnOp(Register ResVReg,
724 const SPIRVType *ResType,
726 unsigned Opcode) const {
727 if (STI.isOpenCLEnv() && I.getOperand(1).isReg()) {
728 Register SrcReg = I.getOperand(1).getReg();
729 bool IsGV = false;
731 MRI->def_instr_begin(SrcReg);
732 DefIt != MRI->def_instr_end(); DefIt = std::next(DefIt)) {
733 if ((*DefIt).getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
734 IsGV = true;
735 break;
736 }
737 }
738 if (IsGV) {
739 uint32_t SpecOpcode = 0;
740 switch (Opcode) {
741 case SPIRV::OpConvertPtrToU:
742 SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertPtrToU);
743 break;
744 case SPIRV::OpConvertUToPtr:
745 SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertUToPtr);
746 break;
747 }
748 if (SpecOpcode)
749 return BuildMI(*I.getParent(), I, I.getDebugLoc(),
750 TII.get(SPIRV::OpSpecConstantOp))
751 .addDef(ResVReg)
752 .addUse(GR.getSPIRVTypeID(ResType))
753 .addImm(SpecOpcode)
754 .addUse(SrcReg)
755 .constrainAllUses(TII, TRI, RBI);
756 }
757 }
758 return selectUnOpWithSrc(ResVReg, ResType, I, I.getOperand(1).getReg(),
759 Opcode);
760}
761
762bool SPIRVInstructionSelector::selectBitcast(Register ResVReg,
763 const SPIRVType *ResType,
764 MachineInstr &I) const {
765 Register OpReg = I.getOperand(1).getReg();
766 SPIRVType *OpType = OpReg.isValid() ? GR.getSPIRVTypeForVReg(OpReg) : nullptr;
767 if (!GR.isBitcastCompatible(ResType, OpType))
768 report_fatal_error("incompatible result and operand types in a bitcast");
769 return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast);
770}
771
772static SPIRV::Scope::Scope getScope(SyncScope::ID Ord,
773 const SyncScopeIDs &SSIDs) {
774 if (Ord == SyncScope::SingleThread || Ord == SSIDs.Work_ItemSSID)
775 return SPIRV::Scope::Invocation;
776 else if (Ord == SyncScope::System || Ord == SSIDs.DeviceSSID)
777 return SPIRV::Scope::Device;
778 else if (Ord == SSIDs.WorkGroupSSID)
779 return SPIRV::Scope::Workgroup;
780 else if (Ord == SSIDs.AllSVMDevicesSSID)
781 return SPIRV::Scope::CrossDevice;
782 else if (Ord == SSIDs.SubGroupSSID)
783 return SPIRV::Scope::Subgroup;
784 else
785 // OpenCL approach is: "The functions that do not have memory_scope argument
786 // have the same semantics as the corresponding functions with the
787 // memory_scope argument set to memory_scope_device." See ref.: //
788 // https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_C.html#atomic-functions
789 // In our case if the scope is unknown, assuming that SPIR-V code is to be
790 // consumed in an OpenCL environment, we use the same approach and set the
791 // scope to memory_scope_device.
792 return SPIRV::Scope::Device;
793}
794
796 MachineInstrBuilder &MIB) {
797 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
798 if (MemOp->isVolatile())
799 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
800 if (MemOp->isNonTemporal())
801 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
802 if (MemOp->getAlign().value())
803 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned);
804
805 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) {
806 MIB.addImm(SpvMemOp);
807 if (SpvMemOp & static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned))
808 MIB.addImm(MemOp->getAlign().value());
809 }
810}
811
813 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
814 if (Flags & MachineMemOperand::Flags::MOVolatile)
815 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
816 if (Flags & MachineMemOperand::Flags::MONonTemporal)
817 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
818
819 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None))
820 MIB.addImm(SpvMemOp);
821}
822
823bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
824 const SPIRVType *ResType,
825 MachineInstr &I) const {
826 unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0;
827 Register Ptr = I.getOperand(1 + OpOffset).getReg();
828 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
829 .addDef(ResVReg)
830 .addUse(GR.getSPIRVTypeID(ResType))
831 .addUse(Ptr);
832 if (!I.getNumMemOperands()) {
833 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
834 I.getOpcode() ==
835 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
836 addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
837 } else {
838 addMemoryOperands(*I.memoperands_begin(), MIB);
839 }
840 return MIB.constrainAllUses(TII, TRI, RBI);
841}
842
843bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
844 unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0;
845 Register StoreVal = I.getOperand(0 + OpOffset).getReg();
846 Register Ptr = I.getOperand(1 + OpOffset).getReg();
847 MachineBasicBlock &BB = *I.getParent();
848 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpStore))
849 .addUse(Ptr)
850 .addUse(StoreVal);
851 if (!I.getNumMemOperands()) {
852 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
853 I.getOpcode() ==
854 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
855 addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
856 } else {
857 addMemoryOperands(*I.memoperands_begin(), MIB);
858 }
859 return MIB.constrainAllUses(TII, TRI, RBI);
860}
861
862bool SPIRVInstructionSelector::selectStackSave(Register ResVReg,
863 const SPIRVType *ResType,
864 MachineInstr &I) const {
865 if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array))
867 "llvm.stacksave intrinsic: this instruction requires the following "
868 "SPIR-V extension: SPV_INTEL_variable_length_array",
869 false);
870 MachineBasicBlock &BB = *I.getParent();
871 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSaveMemoryINTEL))
872 .addDef(ResVReg)
873 .addUse(GR.getSPIRVTypeID(ResType))
874 .constrainAllUses(TII, TRI, RBI);
875}
876
877bool SPIRVInstructionSelector::selectStackRestore(MachineInstr &I) const {
878 if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array))
880 "llvm.stackrestore intrinsic: this instruction requires the following "
881 "SPIR-V extension: SPV_INTEL_variable_length_array",
882 false);
883 if (!I.getOperand(0).isReg())
884 return false;
885 MachineBasicBlock &BB = *I.getParent();
886 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpRestoreMemoryINTEL))
887 .addUse(I.getOperand(0).getReg())
888 .constrainAllUses(TII, TRI, RBI);
889}
890
891bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg,
892 MachineInstr &I) const {
893 MachineBasicBlock &BB = *I.getParent();
894 Register SrcReg = I.getOperand(1).getReg();
895 if (I.getOpcode() == TargetOpcode::G_MEMSET) {
896 assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
897 unsigned Val = getIConstVal(I.getOperand(1).getReg(), MRI);
898 unsigned Num = getIConstVal(I.getOperand(2).getReg(), MRI);
899 SPIRVType *ValTy = GR.getOrCreateSPIRVIntegerType(8, I, TII);
900 SPIRVType *ArrTy = GR.getOrCreateSPIRVArrayType(ValTy, Num, I, TII);
901 Register Const = GR.getOrCreateConstIntArray(Val, Num, I, ArrTy, TII);
902 SPIRVType *VarTy = GR.getOrCreateSPIRVPointerType(
903 ArrTy, I, TII, SPIRV::StorageClass::UniformConstant);
904 // TODO: check if we have such GV, add init, use buildGlobalVariable.
905 Function &CurFunction = GR.CurMF->getFunction();
906 Type *LLVMArrTy =
907 ArrayType::get(IntegerType::get(CurFunction.getContext(), 8), Num);
908 // Module takes ownership of the global var.
909 GlobalVariable *GV = new GlobalVariable(*CurFunction.getParent(), LLVMArrTy,
911 Constant::getNullValue(LLVMArrTy));
912 Register VarReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
913 GR.add(GV, GR.CurMF, VarReg);
914
915 buildOpDecorate(VarReg, I, TII, SPIRV::Decoration::Constant, {});
916 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
917 .addDef(VarReg)
918 .addUse(GR.getSPIRVTypeID(VarTy))
919 .addImm(SPIRV::StorageClass::UniformConstant)
920 .addUse(Const)
921 .constrainAllUses(TII, TRI, RBI);
922 SPIRVType *SourceTy = GR.getOrCreateSPIRVPointerType(
923 ValTy, I, TII, SPIRV::StorageClass::UniformConstant);
924 SrcReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
925 selectUnOpWithSrc(SrcReg, SourceTy, I, VarReg, SPIRV::OpBitcast);
926 }
927 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemorySized))
928 .addUse(I.getOperand(0).getReg())
929 .addUse(SrcReg)
930 .addUse(I.getOperand(2).getReg());
931 if (I.getNumMemOperands())
932 addMemoryOperands(*I.memoperands_begin(), MIB);
933 bool Result = MIB.constrainAllUses(TII, TRI, RBI);
934 if (ResVReg.isValid() && ResVReg != MIB->getOperand(0).getReg())
935 BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), ResVReg)
936 .addUse(MIB->getOperand(0).getReg());
937 return Result;
938}
939
940bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg,
941 const SPIRVType *ResType,
943 unsigned NewOpcode,
944 unsigned NegateOpcode) const {
945 assert(I.hasOneMemOperand());
946 const MachineMemOperand *MemOp = *I.memoperands_begin();
948 static_cast<uint32_t>(getScope(MemOp->getSyncScopeID(), SSIDs));
949 Register ScopeReg = buildI32Constant(Scope, I);
950
951 Register Ptr = I.getOperand(1).getReg();
952 // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll
953 // auto ScSem =
954 // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr));
955 AtomicOrdering AO = MemOp->getSuccessOrdering();
956 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
957 Register MemSemReg = buildI32Constant(MemSem /*| ScSem*/, I);
958
959 bool Result = false;
960 Register ValueReg = I.getOperand(2).getReg();
961 if (NegateOpcode != 0) {
962 // Translation with negative value operand is requested
963 Register TmpReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
964 Result |= selectUnOpWithSrc(TmpReg, ResType, I, ValueReg, NegateOpcode);
965 ValueReg = TmpReg;
966 }
967
968 Result |= BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode))
969 .addDef(ResVReg)
970 .addUse(GR.getSPIRVTypeID(ResType))
971 .addUse(Ptr)
972 .addUse(ScopeReg)
973 .addUse(MemSemReg)
974 .addUse(ValueReg)
975 .constrainAllUses(TII, TRI, RBI);
976 return Result;
977}
978
979bool SPIRVInstructionSelector::selectUnmergeValues(MachineInstr &I) const {
980 unsigned ArgI = I.getNumOperands() - 1;
981 Register SrcReg =
982 I.getOperand(ArgI).isReg() ? I.getOperand(ArgI).getReg() : Register(0);
983 SPIRVType *DefType =
984 SrcReg.isValid() ? GR.getSPIRVTypeForVReg(SrcReg) : nullptr;
985 if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector)
987 "cannot select G_UNMERGE_VALUES with a non-vector argument");
988
989 SPIRVType *ScalarType =
990 GR.getSPIRVTypeForVReg(DefType->getOperand(1).getReg());
991 MachineBasicBlock &BB = *I.getParent();
992 bool Res = false;
993 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
994 Register ResVReg = I.getOperand(i).getReg();
995 SPIRVType *ResType = GR.getSPIRVTypeForVReg(ResVReg);
996 if (!ResType) {
997 // There was no "assign type" actions, let's fix this now
998 ResType = ScalarType;
999 MRI->setRegClass(ResVReg, &SPIRV::iIDRegClass);
1000 MRI->setType(ResVReg, LLT::scalar(GR.getScalarOrVectorBitWidth(ResType)));
1001 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF);
1002 }
1003 auto MIB =
1004 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
1005 .addDef(ResVReg)
1006 .addUse(GR.getSPIRVTypeID(ResType))
1007 .addUse(SrcReg)
1008 .addImm(static_cast<int64_t>(i));
1009 Res |= MIB.constrainAllUses(TII, TRI, RBI);
1010 }
1011 return Res;
1012}
1013
1014bool SPIRVInstructionSelector::selectFence(MachineInstr &I) const {
1015 AtomicOrdering AO = AtomicOrdering(I.getOperand(0).getImm());
1016 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
1017 Register MemSemReg = buildI32Constant(MemSem, I);
1018 SyncScope::ID Ord = SyncScope::ID(I.getOperand(1).getImm());
1019 uint32_t Scope = static_cast<uint32_t>(getScope(Ord, SSIDs));
1020 Register ScopeReg = buildI32Constant(Scope, I);
1021 MachineBasicBlock &BB = *I.getParent();
1022 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMemoryBarrier))
1023 .addUse(ScopeReg)
1024 .addUse(MemSemReg)
1025 .constrainAllUses(TII, TRI, RBI);
1026}
1027
1028bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg,
1029 const SPIRVType *ResType,
1030 MachineInstr &I) const {
1031 Register ScopeReg;
1032 Register MemSemEqReg;
1033 Register MemSemNeqReg;
1034 Register Ptr = I.getOperand(2).getReg();
1035 if (!isa<GIntrinsic>(I)) {
1036 assert(I.hasOneMemOperand());
1037 const MachineMemOperand *MemOp = *I.memoperands_begin();
1038 unsigned Scope =
1039 static_cast<uint32_t>(getScope(MemOp->getSyncScopeID(), SSIDs));
1040 ScopeReg = buildI32Constant(Scope, I);
1041
1042 unsigned ScSem = static_cast<uint32_t>(
1043 getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr)));
1044 AtomicOrdering AO = MemOp->getSuccessOrdering();
1045 unsigned MemSemEq = static_cast<uint32_t>(getMemSemantics(AO)) | ScSem;
1046 MemSemEqReg = buildI32Constant(MemSemEq, I);
1047 AtomicOrdering FO = MemOp->getFailureOrdering();
1048 unsigned MemSemNeq = static_cast<uint32_t>(getMemSemantics(FO)) | ScSem;
1049 MemSemNeqReg =
1050 MemSemEq == MemSemNeq ? MemSemEqReg : buildI32Constant(MemSemNeq, I);
1051 } else {
1052 ScopeReg = I.getOperand(5).getReg();
1053 MemSemEqReg = I.getOperand(6).getReg();
1054 MemSemNeqReg = I.getOperand(7).getReg();
1055 }
1056
1057 Register Cmp = I.getOperand(3).getReg();
1058 Register Val = I.getOperand(4).getReg();
1059 SPIRVType *SpvValTy = GR.getSPIRVTypeForVReg(Val);
1060 Register ACmpRes = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1061 const DebugLoc &DL = I.getDebugLoc();
1062 bool Result =
1063 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpAtomicCompareExchange))
1064 .addDef(ACmpRes)
1065 .addUse(GR.getSPIRVTypeID(SpvValTy))
1066 .addUse(Ptr)
1067 .addUse(ScopeReg)
1068 .addUse(MemSemEqReg)
1069 .addUse(MemSemNeqReg)
1070 .addUse(Val)
1071 .addUse(Cmp)
1072 .constrainAllUses(TII, TRI, RBI);
1073 Register CmpSuccReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1074 SPIRVType *BoolTy = GR.getOrCreateSPIRVBoolType(I, TII);
1075 Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpIEqual))
1076 .addDef(CmpSuccReg)
1077 .addUse(GR.getSPIRVTypeID(BoolTy))
1078 .addUse(ACmpRes)
1079 .addUse(Cmp)
1080 .constrainAllUses(TII, TRI, RBI);
1081 Register TmpReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1082 Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
1083 .addDef(TmpReg)
1084 .addUse(GR.getSPIRVTypeID(ResType))
1085 .addUse(ACmpRes)
1086 .addUse(GR.getOrCreateUndef(I, ResType, TII))
1087 .addImm(0)
1088 .constrainAllUses(TII, TRI, RBI);
1089 Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
1090 .addDef(ResVReg)
1091 .addUse(GR.getSPIRVTypeID(ResType))
1092 .addUse(CmpSuccReg)
1093 .addUse(TmpReg)
1094 .addImm(1)
1095 .constrainAllUses(TII, TRI, RBI);
1096 return Result;
1097}
1098
1099static bool isGenericCastablePtr(SPIRV::StorageClass::StorageClass SC) {
1100 switch (SC) {
1101 case SPIRV::StorageClass::Workgroup:
1102 case SPIRV::StorageClass::CrossWorkgroup:
1103 case SPIRV::StorageClass::Function:
1104 return true;
1105 default:
1106 return false;
1107 }
1108}
1109
1110static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) {
1111 switch (SC) {
1112 case SPIRV::StorageClass::DeviceOnlyINTEL:
1113 case SPIRV::StorageClass::HostOnlyINTEL:
1114 return true;
1115 default:
1116 return false;
1117 }
1118}
1119
1120// In SPIR-V address space casting can only happen to and from the Generic
1121// storage class. We can also only cast Workgroup, CrossWorkgroup, or Function
1122// pointers to and from Generic pointers. As such, we can convert e.g. from
1123// Workgroup to Function by going via a Generic pointer as an intermediary. All
1124// other combinations can only be done by a bitcast, and are probably not safe.
1125bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
1126 const SPIRVType *ResType,
1127 MachineInstr &I) const {
1128 // If the AddrSpaceCast user is single and in OpConstantComposite or
1129 // OpVariable, we should select OpSpecConstantOp.
1130 auto UIs = MRI->use_instructions(ResVReg);
1131 if (!UIs.empty() && ++UIs.begin() == UIs.end() &&
1132 (UIs.begin()->getOpcode() == SPIRV::OpConstantComposite ||
1133 UIs.begin()->getOpcode() == SPIRV::OpVariable ||
1134 isSpvIntrinsic(*UIs.begin(), Intrinsic::spv_init_global))) {
1135 Register NewReg = I.getOperand(1).getReg();
1136 MachineBasicBlock &BB = *I.getParent();
1137 SPIRVType *SpvBaseTy = GR.getOrCreateSPIRVIntegerType(8, I, TII);
1138 ResType = GR.getOrCreateSPIRVPointerType(SpvBaseTy, I, TII,
1139 SPIRV::StorageClass::Generic);
1140 bool Result =
1141 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
1142 .addDef(ResVReg)
1143 .addUse(GR.getSPIRVTypeID(ResType))
1144 .addImm(static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric))
1145 .addUse(NewReg)
1146 .constrainAllUses(TII, TRI, RBI);
1147 return Result;
1148 }
1149 Register SrcPtr = I.getOperand(1).getReg();
1150 SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
1151 SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtr);
1152 SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResVReg);
1153
1154 // don't generate a cast between identical storage classes
1155 if (SrcSC == DstSC)
1156 return BuildMI(*I.getParent(), I, I.getDebugLoc(),
1157 TII.get(TargetOpcode::COPY))
1158 .addDef(ResVReg)
1159 .addUse(SrcPtr)
1160 .constrainAllUses(TII, TRI, RBI);
1161
1162 // Casting from an eligible pointer to Generic.
1163 if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC))
1164 return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
1165 // Casting from Generic to an eligible pointer.
1166 if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC))
1167 return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
1168 // Casting between 2 eligible pointers using Generic as an intermediary.
1169 if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
1170 Register Tmp = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1171 SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
1172 GR.getPointeeType(SrcPtrTy), I, TII, SPIRV::StorageClass::Generic);
1173 MachineBasicBlock &BB = *I.getParent();
1174 const DebugLoc &DL = I.getDebugLoc();
1175 bool Success = BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric))
1176 .addDef(Tmp)
1177 .addUse(GR.getSPIRVTypeID(GenericPtrTy))
1178 .addUse(SrcPtr)
1179 .constrainAllUses(TII, TRI, RBI);
1180 return Success && BuildMI(BB, I, DL, TII.get(SPIRV::OpGenericCastToPtr))
1181 .addDef(ResVReg)
1182 .addUse(GR.getSPIRVTypeID(ResType))
1183 .addUse(Tmp)
1184 .constrainAllUses(TII, TRI, RBI);
1185 }
1186
1187 // Check if instructions from the SPV_INTEL_usm_storage_classes extension may
1188 // be applied
1189 if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::CrossWorkgroup)
1190 return selectUnOp(ResVReg, ResType, I,
1191 SPIRV::OpPtrCastToCrossWorkgroupINTEL);
1192 if (SrcSC == SPIRV::StorageClass::CrossWorkgroup && isUSMStorageClass(DstSC))
1193 return selectUnOp(ResVReg, ResType, I,
1194 SPIRV::OpCrossWorkgroupCastToPtrINTEL);
1195 if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::Generic)
1196 return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
1197 if (SrcSC == SPIRV::StorageClass::Generic && isUSMStorageClass(DstSC))
1198 return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
1199
1200 // Bitcast for pointers requires that the address spaces must match
1201 return false;
1202}
1203
1204static unsigned getFCmpOpcode(unsigned PredNum) {
1205 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
1206 switch (Pred) {
1207 case CmpInst::FCMP_OEQ:
1208 return SPIRV::OpFOrdEqual;
1209 case CmpInst::FCMP_OGE:
1210 return SPIRV::OpFOrdGreaterThanEqual;
1211 case CmpInst::FCMP_OGT:
1212 return SPIRV::OpFOrdGreaterThan;
1213 case CmpInst::FCMP_OLE:
1214 return SPIRV::OpFOrdLessThanEqual;
1215 case CmpInst::FCMP_OLT:
1216 return SPIRV::OpFOrdLessThan;
1217 case CmpInst::FCMP_ONE:
1218 return SPIRV::OpFOrdNotEqual;
1219 case CmpInst::FCMP_ORD:
1220 return SPIRV::OpOrdered;
1221 case CmpInst::FCMP_UEQ:
1222 return SPIRV::OpFUnordEqual;
1223 case CmpInst::FCMP_UGE:
1224 return SPIRV::OpFUnordGreaterThanEqual;
1225 case CmpInst::FCMP_UGT:
1226 return SPIRV::OpFUnordGreaterThan;
1227 case CmpInst::FCMP_ULE:
1228 return SPIRV::OpFUnordLessThanEqual;
1229 case CmpInst::FCMP_ULT:
1230 return SPIRV::OpFUnordLessThan;
1231 case CmpInst::FCMP_UNE:
1232 return SPIRV::OpFUnordNotEqual;
1233 case CmpInst::FCMP_UNO:
1234 return SPIRV::OpUnordered;
1235 default:
1236 llvm_unreachable("Unknown predicate type for FCmp");
1237 }
1238}
1239
1240static unsigned getICmpOpcode(unsigned PredNum) {
1241 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
1242 switch (Pred) {
1243 case CmpInst::ICMP_EQ:
1244 return SPIRV::OpIEqual;
1245 case CmpInst::ICMP_NE:
1246 return SPIRV::OpINotEqual;
1247 case CmpInst::ICMP_SGE:
1248 return SPIRV::OpSGreaterThanEqual;
1249 case CmpInst::ICMP_SGT:
1250 return SPIRV::OpSGreaterThan;
1251 case CmpInst::ICMP_SLE:
1252 return SPIRV::OpSLessThanEqual;
1253 case CmpInst::ICMP_SLT:
1254 return SPIRV::OpSLessThan;
1255 case CmpInst::ICMP_UGE:
1256 return SPIRV::OpUGreaterThanEqual;
1257 case CmpInst::ICMP_UGT:
1258 return SPIRV::OpUGreaterThan;
1259 case CmpInst::ICMP_ULE:
1260 return SPIRV::OpULessThanEqual;
1261 case CmpInst::ICMP_ULT:
1262 return SPIRV::OpULessThan;
1263 default:
1264 llvm_unreachable("Unknown predicate type for ICmp");
1265 }
1266}
1267
1268static unsigned getPtrCmpOpcode(unsigned Pred) {
1269 switch (static_cast<CmpInst::Predicate>(Pred)) {
1270 case CmpInst::ICMP_EQ:
1271 return SPIRV::OpPtrEqual;
1272 case CmpInst::ICMP_NE:
1273 return SPIRV::OpPtrNotEqual;
1274 default:
1275 llvm_unreachable("Unknown predicate type for pointer comparison");
1276 }
1277}
1278
1279// Return the logical operation, or abort if none exists.
1280static unsigned getBoolCmpOpcode(unsigned PredNum) {
1281 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
1282 switch (Pred) {
1283 case CmpInst::ICMP_EQ:
1284 return SPIRV::OpLogicalEqual;
1285 case CmpInst::ICMP_NE:
1286 return SPIRV::OpLogicalNotEqual;
1287 default:
1288 llvm_unreachable("Unknown predicate type for Bool comparison");
1289 }
1290}
1291
1292static APFloat getZeroFP(const Type *LLVMFloatTy) {
1293 if (!LLVMFloatTy)
1294 return APFloat::getZero(APFloat::IEEEsingle());
1295 switch (LLVMFloatTy->getScalarType()->getTypeID()) {
1296 case Type::HalfTyID:
1297 return APFloat::getZero(APFloat::IEEEhalf());
1298 default:
1299 case Type::FloatTyID:
1300 return APFloat::getZero(APFloat::IEEEsingle());
1301 case Type::DoubleTyID:
1302 return APFloat::getZero(APFloat::IEEEdouble());
1303 }
1304}
1305
1306static APFloat getOneFP(const Type *LLVMFloatTy) {
1307 if (!LLVMFloatTy)
1308 return APFloat::getOne(APFloat::IEEEsingle());
1309 switch (LLVMFloatTy->getScalarType()->getTypeID()) {
1310 case Type::HalfTyID:
1311 return APFloat::getOne(APFloat::IEEEhalf());
1312 default:
1313 case Type::FloatTyID:
1314 return APFloat::getOne(APFloat::IEEEsingle());
1315 case Type::DoubleTyID:
1316 return APFloat::getOne(APFloat::IEEEdouble());
1317 }
1318}
1319
1320bool SPIRVInstructionSelector::selectAnyOrAll(Register ResVReg,
1321 const SPIRVType *ResType,
1322 MachineInstr &I,
1323 unsigned OpAnyOrAll) const {
1324 assert(I.getNumOperands() == 3);
1325 assert(I.getOperand(2).isReg());
1326 MachineBasicBlock &BB = *I.getParent();
1327 Register InputRegister = I.getOperand(2).getReg();
1328 SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister);
1329
1330 if (!InputType)
1331 report_fatal_error("Input Type could not be determined.");
1332
1333 bool IsBoolTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeBool);
1334 bool IsVectorTy = InputType->getOpcode() == SPIRV::OpTypeVector;
1335 if (IsBoolTy && !IsVectorTy) {
1336 assert(ResVReg == I.getOperand(0).getReg());
1337 return BuildMI(*I.getParent(), I, I.getDebugLoc(),
1338 TII.get(TargetOpcode::COPY))
1339 .addDef(ResVReg)
1340 .addUse(InputRegister)
1341 .constrainAllUses(TII, TRI, RBI);
1342 }
1343
1344 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
1345 unsigned SpirvNotEqualId =
1346 IsFloatTy ? SPIRV::OpFOrdNotEqual : SPIRV::OpINotEqual;
1347 SPIRVType *SpvBoolScalarTy = GR.getOrCreateSPIRVBoolType(I, TII);
1348 SPIRVType *SpvBoolTy = SpvBoolScalarTy;
1349 Register NotEqualReg = ResVReg;
1350
1351 if (IsVectorTy) {
1352 NotEqualReg = IsBoolTy ? InputRegister
1353 : MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1354 const unsigned NumElts = InputType->getOperand(2).getImm();
1355 SpvBoolTy = GR.getOrCreateSPIRVVectorType(SpvBoolTy, NumElts, I, TII);
1356 }
1357
1358 if (!IsBoolTy) {
1359 Register ConstZeroReg =
1360 IsFloatTy ? buildZerosValF(InputType, I) : buildZerosVal(InputType, I);
1361
1362 BuildMI(BB, I, I.getDebugLoc(), TII.get(SpirvNotEqualId))
1363 .addDef(NotEqualReg)
1364 .addUse(GR.getSPIRVTypeID(SpvBoolTy))
1365 .addUse(InputRegister)
1366 .addUse(ConstZeroReg)
1367 .constrainAllUses(TII, TRI, RBI);
1368 }
1369
1370 if (!IsVectorTy)
1371 return true;
1372
1373 return BuildMI(BB, I, I.getDebugLoc(), TII.get(OpAnyOrAll))
1374 .addDef(ResVReg)
1375 .addUse(GR.getSPIRVTypeID(SpvBoolScalarTy))
1376 .addUse(NotEqualReg)
1377 .constrainAllUses(TII, TRI, RBI);
1378}
1379
1380bool SPIRVInstructionSelector::selectAll(Register ResVReg,
1381 const SPIRVType *ResType,
1382 MachineInstr &I) const {
1383 return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAll);
1384}
1385
1386bool SPIRVInstructionSelector::selectAny(Register ResVReg,
1387 const SPIRVType *ResType,
1388 MachineInstr &I) const {
1389 return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAny);
1390}
1391
1392bool SPIRVInstructionSelector::selectFmix(Register ResVReg,
1393 const SPIRVType *ResType,
1394 MachineInstr &I) const {
1395
1396 assert(I.getNumOperands() == 5);
1397 assert(I.getOperand(2).isReg());
1398 assert(I.getOperand(3).isReg());
1399 assert(I.getOperand(4).isReg());
1400 MachineBasicBlock &BB = *I.getParent();
1401
1402 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1403 .addDef(ResVReg)
1404 .addUse(GR.getSPIRVTypeID(ResType))
1405 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1406 .addImm(GL::FMix)
1407 .addUse(I.getOperand(2).getReg())
1408 .addUse(I.getOperand(3).getReg())
1409 .addUse(I.getOperand(4).getReg())
1410 .constrainAllUses(TII, TRI, RBI);
1411}
1412
1413bool SPIRVInstructionSelector::selectLength(Register ResVReg,
1414 const SPIRVType *ResType,
1415 MachineInstr &I) const {
1416
1417 assert(I.getNumOperands() == 3);
1418 assert(I.getOperand(2).isReg());
1419 MachineBasicBlock &BB = *I.getParent();
1420
1421 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1422 .addDef(ResVReg)
1423 .addUse(GR.getSPIRVTypeID(ResType))
1424 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1425 .addImm(GL::Length)
1426 .addUse(I.getOperand(2).getReg())
1427 .constrainAllUses(TII, TRI, RBI);
1428}
1429
1430bool SPIRVInstructionSelector::selectFrac(Register ResVReg,
1431 const SPIRVType *ResType,
1432 MachineInstr &I) const {
1433
1434 assert(I.getNumOperands() == 3);
1435 assert(I.getOperand(2).isReg());
1436 MachineBasicBlock &BB = *I.getParent();
1437
1438 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1439 .addDef(ResVReg)
1440 .addUse(GR.getSPIRVTypeID(ResType))
1441 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1442 .addImm(GL::Fract)
1443 .addUse(I.getOperand(2).getReg())
1444 .constrainAllUses(TII, TRI, RBI);
1445}
1446
1447bool SPIRVInstructionSelector::selectNormalize(Register ResVReg,
1448 const SPIRVType *ResType,
1449 MachineInstr &I) const {
1450
1451 assert(I.getNumOperands() == 3);
1452 assert(I.getOperand(2).isReg());
1453 MachineBasicBlock &BB = *I.getParent();
1454
1455 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1456 .addDef(ResVReg)
1457 .addUse(GR.getSPIRVTypeID(ResType))
1458 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1459 .addImm(GL::Normalize)
1460 .addUse(I.getOperand(2).getReg())
1461 .constrainAllUses(TII, TRI, RBI);
1462}
1463
1464bool SPIRVInstructionSelector::selectRsqrt(Register ResVReg,
1465 const SPIRVType *ResType,
1466 MachineInstr &I) const {
1467
1468 assert(I.getNumOperands() == 3);
1469 assert(I.getOperand(2).isReg());
1470 MachineBasicBlock &BB = *I.getParent();
1471
1472 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1473 .addDef(ResVReg)
1474 .addUse(GR.getSPIRVTypeID(ResType))
1475 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1476 .addImm(GL::InverseSqrt)
1477 .addUse(I.getOperand(2).getReg())
1478 .constrainAllUses(TII, TRI, RBI);
1479}
1480
1481/// Transform saturate(x) to clamp(x, 0.0f, 1.0f) as SPIRV
1482/// does not have a saturate builtin.
1483bool SPIRVInstructionSelector::selectSaturate(Register ResVReg,
1484 const SPIRVType *ResType,
1485 MachineInstr &I) const {
1486 assert(I.getNumOperands() == 3);
1487 assert(I.getOperand(2).isReg());
1488 MachineBasicBlock &BB = *I.getParent();
1489 Register VZero = buildZerosValF(ResType, I);
1490 Register VOne = buildOnesValF(ResType, I);
1491
1492 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1493 .addDef(ResVReg)
1494 .addUse(GR.getSPIRVTypeID(ResType))
1495 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1496 .addImm(GL::FClamp)
1497 .addUse(I.getOperand(2).getReg())
1498 .addUse(VZero)
1499 .addUse(VOne)
1500 .constrainAllUses(TII, TRI, RBI);
1501}
1502
1503bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
1504 const SPIRVType *ResType,
1505 MachineInstr &I) const {
1506 MachineBasicBlock &BB = *I.getParent();
1507 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse))
1508 .addDef(ResVReg)
1509 .addUse(GR.getSPIRVTypeID(ResType))
1510 .addUse(I.getOperand(1).getReg())
1511 .constrainAllUses(TII, TRI, RBI);
1512}
1513
1514bool SPIRVInstructionSelector::selectFreeze(Register ResVReg,
1515 const SPIRVType *ResType,
1516 MachineInstr &I) const {
1517 // There is no way to implement `freeze` correctly without support on SPIR-V
1518 // standard side, but we may at least address a simple (static) case when
1519 // undef/poison value presence is obvious. The main benefit of even
1520 // incomplete `freeze` support is preventing of translation from crashing due
1521 // to lack of support on legalization and instruction selection steps.
1522 if (!I.getOperand(0).isReg() || !I.getOperand(1).isReg())
1523 return false;
1524 Register OpReg = I.getOperand(1).getReg();
1525 if (MachineInstr *Def = MRI->getVRegDef(OpReg)) {
1526 Register Reg;
1527 switch (Def->getOpcode()) {
1528 case SPIRV::ASSIGN_TYPE:
1529 if (MachineInstr *AssignToDef =
1530 MRI->getVRegDef(Def->getOperand(1).getReg())) {
1531 if (AssignToDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
1532 Reg = Def->getOperand(2).getReg();
1533 }
1534 break;
1535 case SPIRV::OpUndef:
1536 Reg = Def->getOperand(1).getReg();
1537 break;
1538 }
1539 unsigned DestOpCode;
1540 if (Reg.isValid()) {
1541 DestOpCode = SPIRV::OpConstantNull;
1542 } else {
1543 DestOpCode = TargetOpcode::COPY;
1544 Reg = OpReg;
1545 }
1546 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DestOpCode))
1547 .addDef(I.getOperand(0).getReg())
1548 .addUse(Reg)
1549 .constrainAllUses(TII, TRI, RBI);
1550 }
1551 return false;
1552}
1553
1555 const SPIRVType *ResType) {
1556 Register OpReg = ResType->getOperand(2).getReg();
1557 SPIRVType *OpDef = MRI->getVRegDef(OpReg);
1558 if (!OpDef)
1559 return 0;
1560 if (OpDef->getOpcode() == SPIRV::ASSIGN_TYPE &&
1561 OpDef->getOperand(1).isReg()) {
1562 if (SPIRVType *RefDef = MRI->getVRegDef(OpDef->getOperand(1).getReg()))
1563 OpDef = RefDef;
1564 }
1565 unsigned N = OpDef->getOpcode() == TargetOpcode::G_CONSTANT
1566 ? OpDef->getOperand(1).getCImm()->getValue().getZExtValue()
1567 : 0;
1568 return N;
1569}
1570
1571// Return true if the type represents a constant register
1573 SmallPtrSet<SPIRVType *, 4> &Visited) {
1574 if (OpDef->getOpcode() == SPIRV::ASSIGN_TYPE &&
1575 OpDef->getOperand(1).isReg()) {
1576 if (SPIRVType *RefDef = MRI->getVRegDef(OpDef->getOperand(1).getReg()))
1577 OpDef = RefDef;
1578 }
1579
1580 if (Visited.contains(OpDef))
1581 return true;
1582 Visited.insert(OpDef);
1583
1584 unsigned Opcode = OpDef->getOpcode();
1585 switch (Opcode) {
1586 case TargetOpcode::G_CONSTANT:
1587 case TargetOpcode::G_FCONSTANT:
1588 return true;
1589 case TargetOpcode::G_INTRINSIC:
1590 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
1591 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
1592 return cast<GIntrinsic>(*OpDef).getIntrinsicID() ==
1593 Intrinsic::spv_const_composite;
1594 case TargetOpcode::G_BUILD_VECTOR:
1595 case TargetOpcode::G_SPLAT_VECTOR: {
1596 for (unsigned i = OpDef->getNumExplicitDefs(); i < OpDef->getNumOperands();
1597 i++) {
1598 SPIRVType *OpNestedDef =
1599 OpDef->getOperand(i).isReg()
1600 ? MRI->getVRegDef(OpDef->getOperand(i).getReg())
1601 : nullptr;
1602 if (OpNestedDef && !isConstReg(MRI, OpNestedDef, Visited))
1603 return false;
1604 }
1605 return true;
1606 }
1607 }
1608 return false;
1609}
1610
1611// Return true if the virtual register represents a constant
1614 if (SPIRVType *OpDef = MRI->getVRegDef(OpReg))
1615 return isConstReg(MRI, OpDef, Visited);
1616 return false;
1617}
1618
1619bool SPIRVInstructionSelector::selectBuildVector(Register ResVReg,
1620 const SPIRVType *ResType,
1621 MachineInstr &I) const {
1622 unsigned N = 0;
1623 if (ResType->getOpcode() == SPIRV::OpTypeVector)
1624 N = GR.getScalarOrVectorComponentCount(ResType);
1625 else if (ResType->getOpcode() == SPIRV::OpTypeArray)
1626 N = getArrayComponentCount(MRI, ResType);
1627 else
1628 report_fatal_error("Cannot select G_BUILD_VECTOR with a non-vector result");
1629 if (I.getNumExplicitOperands() - I.getNumExplicitDefs() != N)
1630 report_fatal_error("G_BUILD_VECTOR and the result type are inconsistent");
1631
1632 // check if we may construct a constant vector
1633 bool IsConst = true;
1634 for (unsigned i = I.getNumExplicitDefs();
1635 i < I.getNumExplicitOperands() && IsConst; ++i)
1636 if (!isConstReg(MRI, I.getOperand(i).getReg()))
1637 IsConst = false;
1638
1639 if (!IsConst && N < 2)
1641 "There must be at least two constituent operands in a vector");
1642
1643 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
1644 TII.get(IsConst ? SPIRV::OpConstantComposite
1645 : SPIRV::OpCompositeConstruct))
1646 .addDef(ResVReg)
1647 .addUse(GR.getSPIRVTypeID(ResType));
1648 for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i)
1649 MIB.addUse(I.getOperand(i).getReg());
1650 return MIB.constrainAllUses(TII, TRI, RBI);
1651}
1652
1653bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg,
1654 const SPIRVType *ResType,
1655 MachineInstr &I) const {
1656 unsigned N = 0;
1657 if (ResType->getOpcode() == SPIRV::OpTypeVector)
1658 N = GR.getScalarOrVectorComponentCount(ResType);
1659 else if (ResType->getOpcode() == SPIRV::OpTypeArray)
1660 N = getArrayComponentCount(MRI, ResType);
1661 else
1662 report_fatal_error("Cannot select G_SPLAT_VECTOR with a non-vector result");
1663
1664 unsigned OpIdx = I.getNumExplicitDefs();
1665 if (!I.getOperand(OpIdx).isReg())
1666 report_fatal_error("Unexpected argument in G_SPLAT_VECTOR");
1667
1668 // check if we may construct a constant vector
1669 Register OpReg = I.getOperand(OpIdx).getReg();
1670 bool IsConst = isConstReg(MRI, OpReg);
1671
1672 if (!IsConst && N < 2)
1674 "There must be at least two constituent operands in a vector");
1675
1676 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
1677 TII.get(IsConst ? SPIRV::OpConstantComposite
1678 : SPIRV::OpCompositeConstruct))
1679 .addDef(ResVReg)
1680 .addUse(GR.getSPIRVTypeID(ResType));
1681 for (unsigned i = 0; i < N; ++i)
1682 MIB.addUse(OpReg);
1683 return MIB.constrainAllUses(TII, TRI, RBI);
1684}
1685
1686bool SPIRVInstructionSelector::selectCmp(Register ResVReg,
1687 const SPIRVType *ResType,
1688 unsigned CmpOpc,
1689 MachineInstr &I) const {
1690 Register Cmp0 = I.getOperand(2).getReg();
1691 Register Cmp1 = I.getOperand(3).getReg();
1692 assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() ==
1693 GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() &&
1694 "CMP operands should have the same type");
1695 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(CmpOpc))
1696 .addDef(ResVReg)
1697 .addUse(GR.getSPIRVTypeID(ResType))
1698 .addUse(Cmp0)
1699 .addUse(Cmp1)
1700 .constrainAllUses(TII, TRI, RBI);
1701}
1702
1703bool SPIRVInstructionSelector::selectICmp(Register ResVReg,
1704 const SPIRVType *ResType,
1705 MachineInstr &I) const {
1706 auto Pred = I.getOperand(1).getPredicate();
1707 unsigned CmpOpc;
1708
1709 Register CmpOperand = I.getOperand(2).getReg();
1710 if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer))
1711 CmpOpc = getPtrCmpOpcode(Pred);
1712 else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool))
1713 CmpOpc = getBoolCmpOpcode(Pred);
1714 else
1715 CmpOpc = getICmpOpcode(Pred);
1716 return selectCmp(ResVReg, ResType, CmpOpc, I);
1717}
1718
1719void SPIRVInstructionSelector::renderFImm32(MachineInstrBuilder &MIB,
1720 const MachineInstr &I,
1721 int OpIdx) const {
1722 assert(I.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
1723 "Expected G_FCONSTANT");
1724 const ConstantFP *FPImm = I.getOperand(1).getFPImm();
1725 addNumImm(FPImm->getValueAPF().bitcastToAPInt(), MIB);
1726}
1727
1728void SPIRVInstructionSelector::renderImm32(MachineInstrBuilder &MIB,
1729 const MachineInstr &I,
1730 int OpIdx) const {
1731 assert(I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
1732 "Expected G_CONSTANT");
1733 addNumImm(I.getOperand(1).getCImm()->getValue(), MIB);
1734}
1735
1737SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I,
1738 const SPIRVType *ResType) const {
1739 Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32);
1740 const SPIRVType *SpvI32Ty =
1741 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII);
1742 // Find a constant in DT or build a new one.
1743 auto ConstInt = ConstantInt::get(LLVMTy, Val);
1744 Register NewReg = GR.find(ConstInt, GR.CurMF);
1745 if (!NewReg.isValid()) {
1746 NewReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
1747 GR.add(ConstInt, GR.CurMF, NewReg);
1749 MachineBasicBlock &BB = *I.getParent();
1750 if (Val == 0) {
1751 MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
1752 .addDef(NewReg)
1753 .addUse(GR.getSPIRVTypeID(SpvI32Ty));
1754 } else {
1755 MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
1756 .addDef(NewReg)
1757 .addUse(GR.getSPIRVTypeID(SpvI32Ty))
1758 .addImm(APInt(32, Val).getZExtValue());
1759 }
1761 }
1762 return NewReg;
1763}
1764
1765bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
1766 const SPIRVType *ResType,
1767 MachineInstr &I) const {
1768 unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate());
1769 return selectCmp(ResVReg, ResType, CmpOp, I);
1770}
1771
1772Register SPIRVInstructionSelector::buildZerosVal(const SPIRVType *ResType,
1773 MachineInstr &I) const {
1774 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
1775 bool ZeroAsNull = STI.isOpenCLEnv();
1776 if (ResType->getOpcode() == SPIRV::OpTypeVector)
1777 return GR.getOrCreateConstVector(0UL, I, ResType, TII, ZeroAsNull);
1778 return GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
1779}
1780
1781Register SPIRVInstructionSelector::buildZerosValF(const SPIRVType *ResType,
1782 MachineInstr &I) const {
1783 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
1784 bool ZeroAsNull = STI.isOpenCLEnv();
1785 APFloat VZero = getZeroFP(GR.getTypeForSPIRVType(ResType));
1786 if (ResType->getOpcode() == SPIRV::OpTypeVector)
1787 return GR.getOrCreateConstVector(VZero, I, ResType, TII, ZeroAsNull);
1788 return GR.getOrCreateConstFP(VZero, I, ResType, TII, ZeroAsNull);
1789}
1790
1791Register SPIRVInstructionSelector::buildOnesValF(const SPIRVType *ResType,
1792 MachineInstr &I) const {
1793 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
1794 bool ZeroAsNull = STI.isOpenCLEnv();
1795 APFloat VOne = getOneFP(GR.getTypeForSPIRVType(ResType));
1796 if (ResType->getOpcode() == SPIRV::OpTypeVector)
1797 return GR.getOrCreateConstVector(VOne, I, ResType, TII, ZeroAsNull);
1798 return GR.getOrCreateConstFP(VOne, I, ResType, TII, ZeroAsNull);
1799}
1800
1801Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
1802 const SPIRVType *ResType,
1803 MachineInstr &I) const {
1804 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
1805 APInt One =
1806 AllOnes ? APInt::getAllOnes(BitWidth) : APInt::getOneBitSet(BitWidth, 0);
1807 if (ResType->getOpcode() == SPIRV::OpTypeVector)
1808 return GR.getOrCreateConstVector(One.getZExtValue(), I, ResType, TII);
1809 return GR.getOrCreateConstInt(One.getZExtValue(), I, ResType, TII);
1810}
1811
1812bool SPIRVInstructionSelector::selectSelect(Register ResVReg,
1813 const SPIRVType *ResType,
1814 MachineInstr &I,
1815 bool IsSigned) const {
1816 // To extend a bool, we need to use OpSelect between constants.
1817 Register ZeroReg = buildZerosVal(ResType, I);
1818 Register OneReg = buildOnesVal(IsSigned, ResType, I);
1819 bool IsScalarBool =
1820 GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool);
1821 unsigned Opcode =
1822 IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectSIVCond;
1823 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
1824 .addDef(ResVReg)
1825 .addUse(GR.getSPIRVTypeID(ResType))
1826 .addUse(I.getOperand(1).getReg())
1827 .addUse(OneReg)
1828 .addUse(ZeroReg)
1829 .constrainAllUses(TII, TRI, RBI);
1830}
1831
1832bool SPIRVInstructionSelector::selectIToF(Register ResVReg,
1833 const SPIRVType *ResType,
1834 MachineInstr &I, bool IsSigned,
1835 unsigned Opcode) const {
1836 Register SrcReg = I.getOperand(1).getReg();
1837 // We can convert bool value directly to float type without OpConvert*ToF,
1838 // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
1839 if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) {
1840 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
1841 SPIRVType *TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII);
1842 if (ResType->getOpcode() == SPIRV::OpTypeVector) {
1843 const unsigned NumElts = ResType->getOperand(2).getImm();
1844 TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII);
1845 }
1846 SrcReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1847 selectSelect(SrcReg, TmpType, I, false);
1848 }
1849 return selectUnOpWithSrc(ResVReg, ResType, I, SrcReg, Opcode);
1850}
1851
1852bool SPIRVInstructionSelector::selectExt(Register ResVReg,
1853 const SPIRVType *ResType,
1854 MachineInstr &I, bool IsSigned) const {
1855 Register SrcReg = I.getOperand(1).getReg();
1856 if (GR.isScalarOrVectorOfType(SrcReg, SPIRV::OpTypeBool))
1857 return selectSelect(ResVReg, ResType, I, IsSigned);
1858
1859 SPIRVType *SrcType = GR.getSPIRVTypeForVReg(SrcReg);
1860 if (SrcType == ResType)
1861 return BuildMI(*I.getParent(), I, I.getDebugLoc(),
1862 TII.get(TargetOpcode::COPY))
1863 .addDef(ResVReg)
1864 .addUse(SrcReg)
1865 .constrainAllUses(TII, TRI, RBI);
1866
1867 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
1868 return selectUnOp(ResVReg, ResType, I, Opcode);
1869}
1870
1871bool SPIRVInstructionSelector::selectIntToBool(Register IntReg,
1872 Register ResVReg,
1873 MachineInstr &I,
1874 const SPIRVType *IntTy,
1875 const SPIRVType *BoolTy) const {
1876 // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
1877 Register BitIntReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1878 bool IsVectorTy = IntTy->getOpcode() == SPIRV::OpTypeVector;
1879 unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
1880 Register Zero = buildZerosVal(IntTy, I);
1881 Register One = buildOnesVal(false, IntTy, I);
1882 MachineBasicBlock &BB = *I.getParent();
1883 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
1884 .addDef(BitIntReg)
1885 .addUse(GR.getSPIRVTypeID(IntTy))
1886 .addUse(IntReg)
1887 .addUse(One)
1888 .constrainAllUses(TII, TRI, RBI);
1889 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
1890 .addDef(ResVReg)
1891 .addUse(GR.getSPIRVTypeID(BoolTy))
1892 .addUse(BitIntReg)
1893 .addUse(Zero)
1894 .constrainAllUses(TII, TRI, RBI);
1895}
1896
1897bool SPIRVInstructionSelector::selectTrunc(Register ResVReg,
1898 const SPIRVType *ResType,
1899 MachineInstr &I) const {
1900 Register IntReg = I.getOperand(1).getReg();
1901 const SPIRVType *ArgType = GR.getSPIRVTypeForVReg(IntReg);
1902 if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool))
1903 return selectIntToBool(IntReg, ResVReg, I, ArgType, ResType);
1904 if (ArgType == ResType)
1905 return BuildMI(*I.getParent(), I, I.getDebugLoc(),
1906 TII.get(TargetOpcode::COPY))
1907 .addDef(ResVReg)
1908 .addUse(IntReg)
1909 .constrainAllUses(TII, TRI, RBI);
1910 bool IsSigned = GR.isScalarOrVectorSigned(ResType);
1911 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
1912 return selectUnOp(ResVReg, ResType, I, Opcode);
1913}
1914
1915bool SPIRVInstructionSelector::selectConst(Register ResVReg,
1916 const SPIRVType *ResType,
1917 const APInt &Imm,
1918 MachineInstr &I) const {
1919 unsigned TyOpcode = ResType->getOpcode();
1920 assert(TyOpcode != SPIRV::OpTypePointer || Imm.isZero());
1921 MachineBasicBlock &BB = *I.getParent();
1922 if ((TyOpcode == SPIRV::OpTypePointer || TyOpcode == SPIRV::OpTypeEvent) &&
1923 Imm.isZero())
1924 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
1925 .addDef(ResVReg)
1926 .addUse(GR.getSPIRVTypeID(ResType))
1927 .constrainAllUses(TII, TRI, RBI);
1928 if (TyOpcode == SPIRV::OpTypeInt) {
1929 assert(Imm.getBitWidth() <= 64 && "Unsupported integer width!");
1930 Register Reg = GR.getOrCreateConstInt(Imm.getZExtValue(), I, ResType, TII);
1931 if (Reg == ResVReg)
1932 return true;
1933 return BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY))
1934 .addDef(ResVReg)
1935 .addUse(Reg)
1936 .constrainAllUses(TII, TRI, RBI);
1937 }
1938 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
1939 .addDef(ResVReg)
1940 .addUse(GR.getSPIRVTypeID(ResType));
1941 // <=32-bit integers should be caught by the sdag pattern.
1942 assert(Imm.getBitWidth() > 32);
1943 addNumImm(Imm, MIB);
1944 return MIB.constrainAllUses(TII, TRI, RBI);
1945}
1946
1947bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg,
1948 const SPIRVType *ResType,
1949 MachineInstr &I) const {
1950 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
1951 .addDef(ResVReg)
1952 .addUse(GR.getSPIRVTypeID(ResType))
1953 .constrainAllUses(TII, TRI, RBI);
1954}
1955
1957 assert(MO.isReg());
1958 const SPIRVType *TypeInst = MRI->getVRegDef(MO.getReg());
1959 if (TypeInst->getOpcode() == SPIRV::ASSIGN_TYPE) {
1960 assert(TypeInst->getOperand(1).isReg());
1961 MachineInstr *ImmInst = MRI->getVRegDef(TypeInst->getOperand(1).getReg());
1962 return ImmInst->getOpcode() == TargetOpcode::G_CONSTANT;
1963 }
1964 return TypeInst->getOpcode() == SPIRV::OpConstantI;
1965}
1966
1967static int64_t foldImm(const MachineOperand &MO, MachineRegisterInfo *MRI) {
1968 const SPIRVType *TypeInst = MRI->getVRegDef(MO.getReg());
1969 if (TypeInst->getOpcode() == SPIRV::OpConstantI)
1970 return TypeInst->getOperand(2).getImm();
1971 MachineInstr *ImmInst = MRI->getVRegDef(TypeInst->getOperand(1).getReg());
1972 assert(ImmInst->getOpcode() == TargetOpcode::G_CONSTANT);
1973 return ImmInst->getOperand(1).getCImm()->getZExtValue();
1974}
1975
1976bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg,
1977 const SPIRVType *ResType,
1978 MachineInstr &I) const {
1979 MachineBasicBlock &BB = *I.getParent();
1980 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeInsert))
1981 .addDef(ResVReg)
1982 .addUse(GR.getSPIRVTypeID(ResType))
1983 // object to insert
1984 .addUse(I.getOperand(3).getReg())
1985 // composite to insert into
1986 .addUse(I.getOperand(2).getReg());
1987 for (unsigned i = 4; i < I.getNumOperands(); i++)
1988 MIB.addImm(foldImm(I.getOperand(i), MRI));
1989 return MIB.constrainAllUses(TII, TRI, RBI);
1990}
1991
1992bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg,
1993 const SPIRVType *ResType,
1994 MachineInstr &I) const {
1995 MachineBasicBlock &BB = *I.getParent();
1996 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
1997 .addDef(ResVReg)
1998 .addUse(GR.getSPIRVTypeID(ResType))
1999 .addUse(I.getOperand(2).getReg());
2000 for (unsigned i = 3; i < I.getNumOperands(); i++)
2001 MIB.addImm(foldImm(I.getOperand(i), MRI));
2002 return MIB.constrainAllUses(TII, TRI, RBI);
2003}
2004
2005bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg,
2006 const SPIRVType *ResType,
2007 MachineInstr &I) const {
2008 if (isImm(I.getOperand(4), MRI))
2009 return selectInsertVal(ResVReg, ResType, I);
2010 MachineBasicBlock &BB = *I.getParent();
2011 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorInsertDynamic))
2012 .addDef(ResVReg)
2013 .addUse(GR.getSPIRVTypeID(ResType))
2014 .addUse(I.getOperand(2).getReg())
2015 .addUse(I.getOperand(3).getReg())
2016 .addUse(I.getOperand(4).getReg())
2017 .constrainAllUses(TII, TRI, RBI);
2018}
2019
2020bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg,
2021 const SPIRVType *ResType,
2022 MachineInstr &I) const {
2023 if (isImm(I.getOperand(3), MRI))
2024 return selectExtractVal(ResVReg, ResType, I);
2025 MachineBasicBlock &BB = *I.getParent();
2026 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorExtractDynamic))
2027 .addDef(ResVReg)
2028 .addUse(GR.getSPIRVTypeID(ResType))
2029 .addUse(I.getOperand(2).getReg())
2030 .addUse(I.getOperand(3).getReg())
2031 .constrainAllUses(TII, TRI, RBI);
2032}
2033
2034bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
2035 const SPIRVType *ResType,
2036 MachineInstr &I) const {
2037 const bool IsGEPInBounds = I.getOperand(2).getImm();
2038
2039 // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator only
2040 // relies on PtrAccessChain, so we'll try not to deviate. For Vulkan however,
2041 // we have to use Op[InBounds]AccessChain.
2042 const unsigned Opcode = STI.isVulkanEnv()
2043 ? (IsGEPInBounds ? SPIRV::OpInBoundsAccessChain
2044 : SPIRV::OpAccessChain)
2045 : (IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
2046 : SPIRV::OpPtrAccessChain);
2047
2048 auto Res = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
2049 .addDef(ResVReg)
2050 .addUse(GR.getSPIRVTypeID(ResType))
2051 // Object to get a pointer to.
2052 .addUse(I.getOperand(3).getReg());
2053 // Adding indices.
2054 const unsigned StartingIndex =
2055 (Opcode == SPIRV::OpAccessChain || Opcode == SPIRV::OpInBoundsAccessChain)
2056 ? 5
2057 : 4;
2058 for (unsigned i = StartingIndex; i < I.getNumExplicitOperands(); ++i)
2059 Res.addUse(I.getOperand(i).getReg());
2060 return Res.constrainAllUses(TII, TRI, RBI);
2061}
2062
2063// Maybe wrap a value into OpSpecConstantOp
2064bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
2065 MachineInstr &I, SmallVector<Register> &CompositeArgs) const {
2066 bool Result = true;
2067 unsigned Lim = I.getNumExplicitOperands();
2068 for (unsigned i = I.getNumExplicitDefs() + 1; i < Lim; ++i) {
2069 Register OpReg = I.getOperand(i).getReg();
2070 SPIRVType *OpDefine = MRI->getVRegDef(OpReg);
2071 SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpReg);
2073 if (!OpDefine || !OpType || isConstReg(MRI, OpDefine, Visited) ||
2074 OpDefine->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
2075 GR.isAggregateType(OpType)) {
2076 // The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed
2077 // by selectAddrSpaceCast()
2078 CompositeArgs.push_back(OpReg);
2079 continue;
2080 }
2081 MachineFunction *MF = I.getMF();
2082 Register WrapReg = GR.find(OpDefine, MF);
2083 if (WrapReg.isValid()) {
2084 CompositeArgs.push_back(WrapReg);
2085 continue;
2086 }
2087 // Create a new register for the wrapper
2088 WrapReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
2089 GR.add(OpDefine, MF, WrapReg);
2090 CompositeArgs.push_back(WrapReg);
2091 // Decorate the wrapper register and generate a new instruction
2092 MRI->setType(WrapReg, LLT::pointer(0, 32));
2093 GR.assignSPIRVTypeToVReg(OpType, WrapReg, *MF);
2094 MachineBasicBlock &BB = *I.getParent();
2095 Result = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
2096 .addDef(WrapReg)
2097 .addUse(GR.getSPIRVTypeID(OpType))
2098 .addImm(static_cast<uint32_t>(SPIRV::Opcode::Bitcast))
2099 .addUse(OpReg)
2100 .constrainAllUses(TII, TRI, RBI);
2101 if (!Result)
2102 break;
2103 }
2104 return Result;
2105}
2106
2107bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
2108 const SPIRVType *ResType,
2109 MachineInstr &I) const {
2110 MachineBasicBlock &BB = *I.getParent();
2111 Intrinsic::ID IID = cast<GIntrinsic>(I).getIntrinsicID();
2112 switch (IID) {
2113 case Intrinsic::spv_load:
2114 return selectLoad(ResVReg, ResType, I);
2115 case Intrinsic::spv_store:
2116 return selectStore(I);
2117 case Intrinsic::spv_extractv:
2118 return selectExtractVal(ResVReg, ResType, I);
2119 case Intrinsic::spv_insertv:
2120 return selectInsertVal(ResVReg, ResType, I);
2121 case Intrinsic::spv_extractelt:
2122 return selectExtractElt(ResVReg, ResType, I);
2123 case Intrinsic::spv_insertelt:
2124 return selectInsertElt(ResVReg, ResType, I);
2125 case Intrinsic::spv_gep:
2126 return selectGEP(ResVReg, ResType, I);
2127 case Intrinsic::spv_unref_global:
2128 case Intrinsic::spv_init_global: {
2129 MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());
2130 MachineInstr *Init = I.getNumExplicitOperands() > 2
2131 ? MRI->getVRegDef(I.getOperand(2).getReg())
2132 : nullptr;
2133 assert(MI);
2134 return selectGlobalValue(MI->getOperand(0).getReg(), *MI, Init);
2135 }
2136 case Intrinsic::spv_undef: {
2137 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
2138 .addDef(ResVReg)
2139 .addUse(GR.getSPIRVTypeID(ResType));
2140 return MIB.constrainAllUses(TII, TRI, RBI);
2141 }
2142 case Intrinsic::spv_const_composite: {
2143 // If no values are attached, the composite is null constant.
2144 bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
2145 // Select a proper instruction.
2146 unsigned Opcode = SPIRV::OpConstantNull;
2147 SmallVector<Register> CompositeArgs;
2148 if (!IsNull) {
2149 Opcode = SPIRV::OpConstantComposite;
2150 if (!wrapIntoSpecConstantOp(I, CompositeArgs))
2151 return false;
2152 }
2153 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
2154 .addDef(ResVReg)
2155 .addUse(GR.getSPIRVTypeID(ResType));
2156 // skip type MD node we already used when generated assign.type for this
2157 if (!IsNull) {
2158 for (Register OpReg : CompositeArgs)
2159 MIB.addUse(OpReg);
2160 }
2161 return MIB.constrainAllUses(TII, TRI, RBI);
2162 }
2163 case Intrinsic::spv_assign_name: {
2164 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName));
2165 MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg());
2166 for (unsigned i = I.getNumExplicitDefs() + 2;
2167 i < I.getNumExplicitOperands(); ++i) {
2168 MIB.addImm(I.getOperand(i).getImm());
2169 }
2170 return MIB.constrainAllUses(TII, TRI, RBI);
2171 }
2172 case Intrinsic::spv_switch: {
2173 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch));
2174 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
2175 if (I.getOperand(i).isReg())
2176 MIB.addReg(I.getOperand(i).getReg());
2177 else if (I.getOperand(i).isCImm())
2178 addNumImm(I.getOperand(i).getCImm()->getValue(), MIB);
2179 else if (I.getOperand(i).isMBB())
2180 MIB.addMBB(I.getOperand(i).getMBB());
2181 else
2182 llvm_unreachable("Unexpected OpSwitch operand");
2183 }
2184 return MIB.constrainAllUses(TII, TRI, RBI);
2185 }
2186 case Intrinsic::spv_cmpxchg:
2187 return selectAtomicCmpXchg(ResVReg, ResType, I);
2188 case Intrinsic::spv_unreachable:
2189 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUnreachable));
2190 break;
2191 case Intrinsic::spv_alloca:
2192 return selectFrameIndex(ResVReg, ResType, I);
2193 case Intrinsic::spv_alloca_array:
2194 return selectAllocaArray(ResVReg, ResType, I);
2195 case Intrinsic::spv_assume:
2196 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))
2197 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAssumeTrueKHR))
2198 .addUse(I.getOperand(1).getReg());
2199 break;
2200 case Intrinsic::spv_expect:
2201 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))
2202 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExpectKHR))
2203 .addDef(ResVReg)
2204 .addUse(GR.getSPIRVTypeID(ResType))
2205 .addUse(I.getOperand(2).getReg())
2206 .addUse(I.getOperand(3).getReg());
2207 break;
2208 case Intrinsic::spv_thread_id:
2209 return selectSpvThreadId(ResVReg, ResType, I);
2210 case Intrinsic::spv_all:
2211 return selectAll(ResVReg, ResType, I);
2212 case Intrinsic::spv_any:
2213 return selectAny(ResVReg, ResType, I);
2214 case Intrinsic::spv_lerp:
2215 return selectFmix(ResVReg, ResType, I);
2216 case Intrinsic::spv_length:
2217 return selectLength(ResVReg, ResType, I);
2218 case Intrinsic::spv_frac:
2219 return selectFrac(ResVReg, ResType, I);
2220 case Intrinsic::spv_normalize:
2221 return selectNormalize(ResVReg, ResType, I);
2222 case Intrinsic::spv_rsqrt:
2223 return selectRsqrt(ResVReg, ResType, I);
2224 case Intrinsic::spv_lifetime_start:
2225 case Intrinsic::spv_lifetime_end: {
2226 unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
2227 : SPIRV::OpLifetimeStop;
2228 int64_t Size = I.getOperand(I.getNumExplicitDefs() + 1).getImm();
2229 Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 2).getReg();
2230 if (Size == -1)
2231 Size = 0;
2232 BuildMI(BB, I, I.getDebugLoc(), TII.get(Op)).addUse(PtrReg).addImm(Size);
2233 } break;
2234 case Intrinsic::spv_saturate:
2235 return selectSaturate(ResVReg, ResType, I);
2236 default: {
2237 std::string DiagMsg;
2238 raw_string_ostream OS(DiagMsg);
2239 I.print(OS);
2240 DiagMsg = "Intrinsic selection not implemented: " + DiagMsg;
2241 report_fatal_error(DiagMsg.c_str(), false);
2242 }
2243 }
2244 return true;
2245}
2246
2247bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg,
2248 const SPIRVType *ResType,
2249 MachineInstr &I) const {
2250 // there was an allocation size parameter to the allocation instruction
2251 // that is not 1
2252 MachineBasicBlock &BB = *I.getParent();
2253 return BuildMI(BB, I, I.getDebugLoc(),
2254 TII.get(SPIRV::OpVariableLengthArrayINTEL))
2255 .addDef(ResVReg)
2256 .addUse(GR.getSPIRVTypeID(ResType))
2257 .addUse(I.getOperand(2).getReg())
2258 .constrainAllUses(TII, TRI, RBI);
2259}
2260
2261bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg,
2262 const SPIRVType *ResType,
2263 MachineInstr &I) const {
2264 // Change order of instructions if needed: all OpVariable instructions in a
2265 // function must be the first instructions in the first block
2266 MachineFunction *MF = I.getParent()->getParent();
2267 MachineBasicBlock *MBB = &MF->front();
2268 auto It = MBB->SkipPHIsAndLabels(MBB->begin()), E = MBB->end();
2269 bool IsHeader = false;
2270 unsigned Opcode;
2271 for (; It != E && It != I; ++It) {
2272 Opcode = It->getOpcode();
2273 if (Opcode == SPIRV::OpFunction || Opcode == SPIRV::OpFunctionParameter) {
2274 IsHeader = true;
2275 } else if (IsHeader &&
2276 !(Opcode == SPIRV::ASSIGN_TYPE || Opcode == SPIRV::OpLabel)) {
2277 ++It;
2278 break;
2279 }
2280 }
2281 return BuildMI(*MBB, It, It->getDebugLoc(), TII.get(SPIRV::OpVariable))
2282 .addDef(ResVReg)
2283 .addUse(GR.getSPIRVTypeID(ResType))
2284 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
2285 .constrainAllUses(TII, TRI, RBI);
2286}
2287
2288bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const {
2289 // InstructionSelector walks backwards through the instructions. We can use
2290 // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
2291 // first, so can generate an OpBranchConditional here. If there is no
2292 // G_BRCOND, we just use OpBranch for a regular unconditional branch.
2293 const MachineInstr *PrevI = I.getPrevNode();
2294 MachineBasicBlock &MBB = *I.getParent();
2295 if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) {
2296 return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
2297 .addUse(PrevI->getOperand(0).getReg())
2298 .addMBB(PrevI->getOperand(1).getMBB())
2299 .addMBB(I.getOperand(0).getMBB())
2300 .constrainAllUses(TII, TRI, RBI);
2301 }
2302 return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch))
2303 .addMBB(I.getOperand(0).getMBB())
2304 .constrainAllUses(TII, TRI, RBI);
2305}
2306
2307bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const {
2308 // InstructionSelector walks backwards through the instructions. For an
2309 // explicit conditional branch with no fallthrough, we use both a G_BR and a
2310 // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
2311 // generate the OpBranchConditional in selectBranch above.
2312 //
2313 // If an OpBranchConditional has been generated, we simply return, as the work
2314 // is alread done. If there is no OpBranchConditional, LLVM must be relying on
2315 // implicit fallthrough to the next basic block, so we need to create an
2316 // OpBranchConditional with an explicit "false" argument pointing to the next
2317 // basic block that LLVM would fall through to.
2318 const MachineInstr *NextI = I.getNextNode();
2319 // Check if this has already been successfully selected.
2320 if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional)
2321 return true;
2322 // Must be relying on implicit block fallthrough, so generate an
2323 // OpBranchConditional with the "next" basic block as the "false" target.
2324 MachineBasicBlock &MBB = *I.getParent();
2325 unsigned NextMBBNum = MBB.getNextNode()->getNumber();
2326 MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum);
2327 return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
2328 .addUse(I.getOperand(0).getReg())
2329 .addMBB(I.getOperand(1).getMBB())
2330 .addMBB(NextMBB)
2331 .constrainAllUses(TII, TRI, RBI);
2332}
2333
2334bool SPIRVInstructionSelector::selectPhi(Register ResVReg,
2335 const SPIRVType *ResType,
2336 MachineInstr &I) const {
2337 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpPhi))
2338 .addDef(ResVReg)
2339 .addUse(GR.getSPIRVTypeID(ResType));
2340 const unsigned NumOps = I.getNumOperands();
2341 for (unsigned i = 1; i < NumOps; i += 2) {
2342 MIB.addUse(I.getOperand(i + 0).getReg());
2343 MIB.addMBB(I.getOperand(i + 1).getMBB());
2344 }
2345 return MIB.constrainAllUses(TII, TRI, RBI);
2346}
2347
2348bool SPIRVInstructionSelector::selectGlobalValue(
2349 Register ResVReg, MachineInstr &I, const MachineInstr *Init) const {
2350 // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
2351 MachineIRBuilder MIRBuilder(I);
2352 const GlobalValue *GV = I.getOperand(1).getGlobal();
2353 Type *GVType = toTypedPointer(GR.getDeducedGlobalValueType(GV));
2354 SPIRVType *PointerBaseType;
2355 if (GVType->isArrayTy()) {
2356 SPIRVType *ArrayElementType =
2357 GR.getOrCreateSPIRVType(GVType->getArrayElementType(), MIRBuilder,
2358 SPIRV::AccessQualifier::ReadWrite, false);
2359 PointerBaseType = GR.getOrCreateSPIRVArrayType(
2360 ArrayElementType, GVType->getArrayNumElements(), I, TII);
2361 } else {
2362 PointerBaseType = GR.getOrCreateSPIRVType(
2363 GVType, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false);
2364 }
2365 SPIRVType *ResType = GR.getOrCreateSPIRVPointerType(
2366 PointerBaseType, I, TII,
2368
2369 std::string GlobalIdent;
2370 if (!GV->hasName()) {
2371 unsigned &ID = UnnamedGlobalIDs[GV];
2372 if (ID == 0)
2373 ID = UnnamedGlobalIDs.size();
2374 GlobalIdent = "__unnamed_" + Twine(ID).str();
2375 } else {
2376 GlobalIdent = GV->getGlobalIdentifier();
2377 }
2378
2379 // Behaviour of functions as operands depends on availability of the
2380 // corresponding extension (SPV_INTEL_function_pointers):
2381 // - If there is an extension to operate with functions as operands:
2382 // We create a proper constant operand and evaluate a correct type for a
2383 // function pointer.
2384 // - Without the required extension:
2385 // We have functions as operands in tests with blocks of instruction e.g. in
2386 // transcoding/global_block.ll. These operands are not used and should be
2387 // substituted by zero constants. Their type is expected to be always
2388 // OpTypePointer Function %uchar.
2389 if (isa<Function>(GV)) {
2390 const Constant *ConstVal = GV;
2391 MachineBasicBlock &BB = *I.getParent();
2392 Register NewReg = GR.find(ConstVal, GR.CurMF);
2393 if (!NewReg.isValid()) {
2394 Register NewReg = ResVReg;
2395 GR.add(ConstVal, GR.CurMF, NewReg);
2396 const Function *GVFun =
2397 STI.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
2398 ? dyn_cast<Function>(GV)
2399 : nullptr;
2400 if (GVFun) {
2401 // References to a function via function pointers generate virtual
2402 // registers without a definition. We will resolve it later, during
2403 // module analysis stage.
2404 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
2405 Register FuncVReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
2406 MRI->setRegClass(FuncVReg, &SPIRV::iIDRegClass);
2408 BuildMI(BB, I, I.getDebugLoc(),
2409 TII.get(SPIRV::OpConstantFunctionPointerINTEL))
2410 .addDef(NewReg)
2411 .addUse(GR.getSPIRVTypeID(ResType))
2412 .addUse(FuncVReg);
2413 // mapping the function pointer to the used Function
2414 GR.recordFunctionPointer(&MB.getInstr()->getOperand(2), GVFun);
2415 return MB.constrainAllUses(TII, TRI, RBI);
2416 }
2417 return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
2418 .addDef(NewReg)
2419 .addUse(GR.getSPIRVTypeID(ResType))
2420 .constrainAllUses(TII, TRI, RBI);
2421 }
2422 assert(NewReg != ResVReg);
2423 return BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY))
2424 .addDef(ResVReg)
2425 .addUse(NewReg)
2426 .constrainAllUses(TII, TRI, RBI);
2427 }
2428 auto GlobalVar = cast<GlobalVariable>(GV);
2429 assert(GlobalVar->getName() != "llvm.global.annotations");
2430
2431 bool HasInit = GlobalVar->hasInitializer() &&
2432 !isa<UndefValue>(GlobalVar->getInitializer());
2433 // Skip empty declaration for GVs with initilaizers till we get the decl with
2434 // passed initializer.
2435 if (HasInit && !Init)
2436 return true;
2437
2438 unsigned AddrSpace = GV->getAddressSpace();
2439 SPIRV::StorageClass::StorageClass Storage =
2440 addressSpaceToStorageClass(AddrSpace, STI);
2441 bool HasLnkTy = GV->getLinkage() != GlobalValue::InternalLinkage &&
2442 Storage != SPIRV::StorageClass::Function;
2443 SPIRV::LinkageType::LinkageType LnkType =
2445 ? SPIRV::LinkageType::Import
2447 STI.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr)
2448 ? SPIRV::LinkageType::LinkOnceODR
2449 : SPIRV::LinkageType::Export);
2450
2451 Register Reg = GR.buildGlobalVariable(ResVReg, ResType, GlobalIdent, GV,
2452 Storage, Init, GlobalVar->isConstant(),
2453 HasLnkTy, LnkType, MIRBuilder, true);
2454 return Reg.isValid();
2455}
2456
2457bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
2458 const SPIRVType *ResType,
2459 MachineInstr &I) const {
2460 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
2461 return selectExtInst(ResVReg, ResType, I, CL::log10);
2462 }
2463
2464 // There is no log10 instruction in the GLSL Extended Instruction set, so it
2465 // is implemented as:
2466 // log10(x) = log2(x) * (1 / log2(10))
2467 // = log2(x) * 0.30103
2468
2469 MachineIRBuilder MIRBuilder(I);
2470 MachineBasicBlock &BB = *I.getParent();
2471
2472 // Build log2(x).
2473 Register VarReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
2474 bool Result =
2475 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
2476 .addDef(VarReg)
2477 .addUse(GR.getSPIRVTypeID(ResType))
2478 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
2479 .addImm(GL::Log2)
2480 .add(I.getOperand(1))
2481 .constrainAllUses(TII, TRI, RBI);
2482
2483 // Build 0.30103.
2484 assert(ResType->getOpcode() == SPIRV::OpTypeVector ||
2485 ResType->getOpcode() == SPIRV::OpTypeFloat);
2486 // TODO: Add matrix implementation once supported by the HLSL frontend.
2487 const SPIRVType *SpirvScalarType =
2488 ResType->getOpcode() == SPIRV::OpTypeVector
2489 ? GR.getSPIRVTypeForVReg(ResType->getOperand(1).getReg())
2490 : ResType;
2491 Register ScaleReg =
2492 GR.buildConstantFP(APFloat(0.30103f), MIRBuilder, SpirvScalarType);
2493
2494 // Multiply log2(x) by 0.30103 to get log10(x) result.
2495 auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector
2496 ? SPIRV::OpVectorTimesScalar
2497 : SPIRV::OpFMulS;
2498 Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
2499 .addDef(ResVReg)
2500 .addUse(GR.getSPIRVTypeID(ResType))
2501 .addUse(VarReg)
2502 .addUse(ScaleReg)
2503 .constrainAllUses(TII, TRI, RBI);
2504
2505 return Result;
2506}
2507
2508bool SPIRVInstructionSelector::selectSpvThreadId(Register ResVReg,
2509 const SPIRVType *ResType,
2510 MachineInstr &I) const {
2511 // DX intrinsic: @llvm.dx.thread.id(i32)
2512 // ID Name Description
2513 // 93 ThreadId reads the thread ID
2514
2515 MachineIRBuilder MIRBuilder(I);
2516 const SPIRVType *U32Type = GR.getOrCreateSPIRVIntegerType(32, MIRBuilder);
2517 const SPIRVType *Vec3Ty =
2518 GR.getOrCreateSPIRVVectorType(U32Type, 3, MIRBuilder);
2519 const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType(
2520 Vec3Ty, MIRBuilder, SPIRV::StorageClass::Input);
2521
2522 // Create new register for GlobalInvocationID builtin variable.
2523 Register NewRegister =
2524 MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
2525 MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 32));
2526 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
2527
2528 // Build GlobalInvocationID global variable with the necessary decorations.
2529 Register Variable = GR.buildGlobalVariable(
2530 NewRegister, PtrType,
2531 getLinkStringForBuiltIn(SPIRV::BuiltIn::GlobalInvocationId), nullptr,
2532 SPIRV::StorageClass::Input, nullptr, true, true,
2533 SPIRV::LinkageType::Import, MIRBuilder, false);
2534
2535 // Create new register for loading value.
2536 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
2537 Register LoadedRegister = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
2538 MIRBuilder.getMRI()->setType(LoadedRegister, LLT::pointer(0, 32));
2539 GR.assignSPIRVTypeToVReg(Vec3Ty, LoadedRegister, MIRBuilder.getMF());
2540
2541 // Load v3uint value from the global variable.
2542 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
2543 .addDef(LoadedRegister)
2544 .addUse(GR.getSPIRVTypeID(Vec3Ty))
2545 .addUse(Variable);
2546
2547 // Get Thread ID index. Expecting operand is a constant immediate value,
2548 // wrapped in a type assignment.
2549 assert(I.getOperand(2).isReg());
2550 Register ThreadIdReg = I.getOperand(2).getReg();
2551 SPIRVType *ConstTy = this->MRI->getVRegDef(ThreadIdReg);
2552 assert(ConstTy && ConstTy->getOpcode() == SPIRV::ASSIGN_TYPE &&
2553 ConstTy->getOperand(1).isReg());
2554 Register ConstReg = ConstTy->getOperand(1).getReg();
2555 const MachineInstr *Const = this->MRI->getVRegDef(ConstReg);
2556 assert(Const && Const->getOpcode() == TargetOpcode::G_CONSTANT);
2557 const llvm::APInt &Val = Const->getOperand(1).getCImm()->getValue();
2558 const uint32_t ThreadId = Val.getZExtValue();
2559
2560 // Extract the thread ID from the loaded vector value.
2561 MachineBasicBlock &BB = *I.getParent();
2562 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
2563 .addDef(ResVReg)
2564 .addUse(GR.getSPIRVTypeID(ResType))
2565 .addUse(LoadedRegister)
2566 .addImm(ThreadId);
2567 return MIB.constrainAllUses(TII, TRI, RBI);
2568}
2569
2570namespace llvm {
2573 const SPIRVSubtarget &Subtarget,
2574 const RegisterBankInfo &RBI) {
2575 return new SPIRVInstructionSelector(TM, Subtarget, RBI);
2576}
2577} // namespace llvm
unsigned const MachineRegisterInfo * MRI
#define Success
This file declares a class to represent arbitrary precision floating point values and provide a varie...
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define LLVM_DEBUG(X)
Definition: Debug.h:101
uint64_t Size
#define DEBUG_TYPE
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition: MD5.cpp:58
unsigned const TargetRegisterInfo * TRI
uint64_t IntrinsicInst * II
static StringRef getName(Value *V)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
std::vector< std::pair< SPIRV::InstructionSet::InstructionSet, uint32_t > > ExtInstList
#define GET_GLOBALISEL_PREDICATES_INIT
#define GET_GLOBALISEL_TEMPORARIES_INIT
static APFloat getOneFP(const Type *LLVMFloatTy)
static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC)
static APFloat getZeroFP(const Type *LLVMFloatTy)
static void addMemoryOperands(MachineMemOperand *MemOp, MachineInstrBuilder &MIB)
static unsigned getFCmpOpcode(unsigned PredNum)
bool isTypeFoldingSupported(unsigned Opcode)
static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI)
static unsigned getBoolCmpOpcode(unsigned PredNum)
static unsigned getICmpOpcode(unsigned PredNum)
static bool isConstReg(MachineRegisterInfo *MRI, SPIRVType *OpDef, SmallPtrSet< SPIRVType *, 4 > &Visited)
static int64_t foldImm(const MachineOperand &MO, MachineRegisterInfo *MRI)
static bool isGenericCastablePtr(SPIRV::StorageClass::StorageClass SC)
static SPIRV::Scope::Scope getScope(SyncScope::ID Ord, const SyncScopeIDs &SSIDs)
static unsigned getPtrCmpOpcode(unsigned Pred)
static unsigned getArrayComponentCount(MachineRegisterInfo *MRI, const SPIRVType *ResType)
raw_pwrite_stream & OS
static APFloat getOne(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative One.
Definition: APFloat.h:1003
APInt bitcastToAPInt() const
Definition: APFloat.h:1266
static APFloat getZero(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Zero.
Definition: APFloat.h:994
Class for arbitrary precision integers.
Definition: APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition: APInt.h:212
uint64_t getZExtValue() const
Get zero extended value.
Definition: APInt.h:1498
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition: InstrTypes.h:757
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition: InstrTypes.h:760
@ ICMP_SLT
signed less than
Definition: InstrTypes.h:786
@ ICMP_SLE
signed less or equal
Definition: InstrTypes.h:787
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition: InstrTypes.h:763
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition: InstrTypes.h:772
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition: InstrTypes.h:761
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition: InstrTypes.h:762
@ ICMP_UGE
unsigned greater or equal
Definition: InstrTypes.h:781
@ ICMP_UGT
unsigned greater than
Definition: InstrTypes.h:780
@ ICMP_SGT
signed greater than
Definition: InstrTypes.h:784
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition: InstrTypes.h:771
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition: InstrTypes.h:765
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition: InstrTypes.h:768
@ ICMP_ULT
unsigned less than
Definition: InstrTypes.h:782
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition: InstrTypes.h:769
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition: InstrTypes.h:764
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition: InstrTypes.h:766
@ ICMP_EQ
equal
Definition: InstrTypes.h:778
@ ICMP_NE
not equal
Definition: InstrTypes.h:779
@ ICMP_SGE
signed greater or equal
Definition: InstrTypes.h:785
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition: InstrTypes.h:773
@ ICMP_ULE
unsigned less or equal
Definition: InstrTypes.h:783
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition: InstrTypes.h:770
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition: InstrTypes.h:767
ConstantFP - Floating Point Values [float, double].
Definition: Constants.h:269
const APFloat & getValueAPF() const
Definition: Constants.h:312
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition: Constants.h:155
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition: Constants.h:146
This is an important base class in LLVM.
Definition: Constant.h:42
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Definition: Constants.cpp:370
This class represents an Operation in the Expression.
A debug info location.
Definition: DebugLoc.h:33
const Function & getFunction() const
Definition: Function.h:170
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:380
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition: Globals.cpp:290
LinkageTypes getLinkage() const
Definition: GlobalValue.h:546
unsigned getAddressSpace() const
Definition: GlobalValue.h:205
Module * getParent()
Get the module that this global value is contained inside of...
Definition: GlobalValue.h:656
static std::string getGlobalIdentifier(StringRef Name, GlobalValue::LinkageTypes Linkage, StringRef FileName)
Return the modified name for a global value suitable to be used as the key for a global lookup (e....
Definition: Globals.cpp:153
bool hasAvailableExternallyLinkage() const
Definition: GlobalValue.h:512
@ InternalLinkage
Rename collisions when linking (static functions).
Definition: GlobalValue.h:59
@ LinkOnceODRLinkage
Same, but only replaced by something equivalent.
Definition: GlobalValue.h:55
static IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition: Type.cpp:266
constexpr bool isScalar() const
Definition: LowLevelType.h:146
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelType.h:42
constexpr bool isVector() const
Definition: LowLevelType.h:148
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
Definition: LowLevelType.h:57
constexpr bool isPointer() const
Definition: LowLevelType.h:149
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
SyncScope::ID getOrInsertSyncScopeID(StringRef SSN)
getOrInsertSyncScopeID - Maps synchronization scope name to synchronization scope ID.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
iterator SkipPHIsAndLabels(iterator I)
Return the first instruction in MBB after I that is not a PHI or a label.
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.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
bool constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
Definition: MachineInstr.h:69
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:569
unsigned getNumExplicitDefs() const
Returns the number of non-implicit definitions.
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:579
A description of a memory reference used in the backend.
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.
MachineBasicBlock * getMBB() const
Register getReg() const
getReg - Returns the register number.
defusechain_iterator - This class provides iterator support for machine operands in the function that...
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
Analysis providing profile information.
Holds all the information related to register banks.
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
Definition: Register.h:84
constexpr bool isValid() const
Definition: Register.h:116
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:367
bool contains(ConstPtrType Ptr) const
Definition: SmallPtrSet.h:441
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:502
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
std::string str() const
Return the twine contents as a std::string.
Definition: Twine.cpp:17
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
bool isArrayTy() const
True if this is an instance of ArrayType.
Definition: Type.h:248
Type * getArrayElementType() const
Definition: Type.h:399
uint64_t getArrayNumElements() const
@ HalfTyID
16-bit floating point type
Definition: Type.h:56
@ FloatTyID
32-bit floating point type
Definition: Type.h:58
@ DoubleTyID
64-bit floating point type
Definition: Type.h:59
TypeID getTypeID() const
Return the type id for the type.
Definition: Type.h:136
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition: Type.h:343
bool hasName() const
Definition: Value.h:261
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition: ilist_node.h:353
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:661
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char IsConst[]
Key for Kernel::Arg::Metadata::mIsConst.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
Definition: LLVMContext.h:54
@ System
Synchronized with respect to all concurrently executing threads.
Definition: LLVMContext.h:57
Reg
All possible values of the reg field in the ModR/M byte.
NodeAddr< DefNode * > Def
Definition: RDFGraph.h:384
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB)
Definition: SPIRVUtils.cpp:80
bool constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
Definition: Utils.cpp:155
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
Definition: TargetOpcodes.h:30
uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI)
Definition: SPIRVUtils.cpp:273
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
Definition: SPIRVUtils.cpp:218
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, const std::vector< uint32_t > &DecArgs, StringRef StrImm)
Definition: SPIRVUtils.cpp:117
Type * toTypedPointer(Type *Ty)
Definition: SPIRVUtils.h:208
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
Definition: SPIRVUtils.cpp:190
AtomicOrdering
Atomic ordering for LLVM's memory model.
InstructionSelector * createSPIRVInstructionSelector(const SPIRVTargetMachine &TM, const SPIRVSubtarget &Subtarget, const RegisterBankInfo &RBI)
constexpr unsigned BitWidth
Definition: BitmaskEnum.h:191
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
Definition: SPIRVUtils.cpp:279
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
Definition: SPIRVUtils.cpp:236
std::string getLinkStringForBuiltIn(SPIRV::BuiltIn::BuiltIn BuiltInValue)
#define N