LLVM 23.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"
20#include "SPIRVRegisterInfo.h"
21#include "SPIRVTargetMachine.h"
22#include "SPIRVUtils.h"
23#include "llvm/ADT/APFloat.h"
33#include "llvm/IR/IntrinsicsSPIRV.h"
34#include "llvm/Support/Debug.h"
36
37#define DEBUG_TYPE "spirv-isel"
38
39using namespace llvm;
40namespace CL = SPIRV::OpenCLExtInst;
41namespace GL = SPIRV::GLSLExtInst;
42
44 std::vector<std::pair<SPIRV::InstructionSet::InstructionSet, uint32_t>>;
45
46namespace {
47
48struct ImageOperands {
49 std::optional<Register> Bias;
50 std::optional<Register> Offset;
51 std::optional<Register> MinLod;
52 std::optional<Register> GradX;
53 std::optional<Register> GradY;
54 std::optional<Register> Lod;
55 std::optional<Register> Compare;
56};
57
58llvm::SPIRV::SelectionControl::SelectionControl
59getSelectionOperandForImm(int Imm) {
60 if (Imm == 2)
61 return SPIRV::SelectionControl::Flatten;
62 if (Imm == 1)
63 return SPIRV::SelectionControl::DontFlatten;
64 if (Imm == 0)
65 return SPIRV::SelectionControl::None;
66 llvm_unreachable("Invalid immediate");
67}
68
69#define GET_GLOBALISEL_PREDICATE_BITSET
70#include "SPIRVGenGlobalISel.inc"
71#undef GET_GLOBALISEL_PREDICATE_BITSET
72
73class SPIRVInstructionSelector : public InstructionSelector {
74 const SPIRVSubtarget &STI;
75 const SPIRVInstrInfo &TII;
77 const RegisterBankInfo &RBI;
80 MachineFunction *HasVRegsReset = nullptr;
81
82 /// We need to keep track of the number we give to anonymous global values to
83 /// generate the same name every time when this is needed.
84 mutable DenseMap<const GlobalValue *, unsigned> UnnamedGlobalIDs;
86
87public:
88 SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
89 const SPIRVSubtarget &ST,
90 const RegisterBankInfo &RBI);
91 void setupMF(MachineFunction &MF, GISelValueTracking *VT,
92 CodeGenCoverage *CoverageInfo, ProfileSummaryInfo *PSI,
93 BlockFrequencyInfo *BFI) override;
94 // Common selection code. Instruction-specific selection occurs in spvSelect.
95 bool select(MachineInstr &I) override;
96 static const char *getName() { return DEBUG_TYPE; }
97
98#define GET_GLOBALISEL_PREDICATES_DECL
99#include "SPIRVGenGlobalISel.inc"
100#undef GET_GLOBALISEL_PREDICATES_DECL
101
102#define GET_GLOBALISEL_TEMPORARIES_DECL
103#include "SPIRVGenGlobalISel.inc"
104#undef GET_GLOBALISEL_TEMPORARIES_DECL
105
106private:
107 void resetVRegsType(MachineFunction &MF);
108 void removeDeadInstruction(MachineInstr &MI) const;
109 void removeOpNamesForDeadMI(MachineInstr &MI) const;
110
111 // tblgen-erated 'select' implementation, used as the initial selector for
112 // the patterns that don't require complex C++.
113 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
114
115 // All instruction-specific selection that didn't happen in "select()".
116 // Is basically a large Switch/Case delegating to all other select method.
117 bool spvSelect(Register ResVReg, SPIRVTypeInst ResType,
118 MachineInstr &I) const;
119
120 bool selectFirstBitHigh(Register ResVReg, SPIRVTypeInst ResType,
121 MachineInstr &I, bool IsSigned) const;
122
123 bool selectFirstBitLow(Register ResVReg, SPIRVTypeInst ResType,
124 MachineInstr &I) const;
125
126 bool selectFirstBitSet16(Register ResVReg, SPIRVTypeInst ResType,
127 MachineInstr &I, unsigned ExtendOpcode,
128 unsigned BitSetOpcode) const;
129
130 bool selectFirstBitSet32(Register ResVReg, SPIRVTypeInst ResType,
131 MachineInstr &I, Register SrcReg,
132 unsigned BitSetOpcode) const;
133
134 bool selectFirstBitSet64(Register ResVReg, SPIRVTypeInst ResType,
135 MachineInstr &I, Register SrcReg,
136 unsigned BitSetOpcode, bool SwapPrimarySide) const;
137
138 bool selectFirstBitSet64Overflow(Register ResVReg, SPIRVTypeInst ResType,
139 MachineInstr &I, Register SrcReg,
140 unsigned BitSetOpcode,
141 bool SwapPrimarySide) const;
142
143 bool selectGlobalValue(Register ResVReg, MachineInstr &I,
144 const MachineInstr *Init = nullptr) const;
145
146 bool selectOpWithSrcs(Register ResVReg, SPIRVTypeInst ResType,
147 MachineInstr &I, std::vector<Register> SrcRegs,
148 unsigned Opcode) const;
149
150 bool selectUnOp(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
151 unsigned Opcode) const;
152
153 bool selectBitcast(Register ResVReg, SPIRVTypeInst ResType,
154 MachineInstr &I) const;
155
156 bool selectLoad(Register ResVReg, SPIRVTypeInst ResType,
157 MachineInstr &I) const;
158 bool selectStore(MachineInstr &I) const;
159
160 bool selectStackSave(Register ResVReg, SPIRVTypeInst ResType,
161 MachineInstr &I) const;
162 bool selectStackRestore(MachineInstr &I) const;
163
164 bool selectMemOperation(Register ResVReg, MachineInstr &I) const;
165 Register getOrCreateMemSetGlobal(MachineInstr &I) const;
166 bool selectCopyMemory(MachineInstr &I, Register SrcReg) const;
167 bool selectCopyMemorySized(MachineInstr &I, Register SrcReg) const;
168
169 bool selectAtomicRMW(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
170 unsigned NewOpcode, unsigned NegateOpcode = 0) const;
171
172 bool selectAtomicCmpXchg(Register ResVReg, SPIRVTypeInst ResType,
173 MachineInstr &I) const;
174
175 bool selectFence(MachineInstr &I) const;
176
177 bool selectAddrSpaceCast(Register ResVReg, SPIRVTypeInst ResType,
178 MachineInstr &I) const;
179
180 bool selectAnyOrAll(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
181 unsigned OpType) const;
182
183 bool selectAll(Register ResVReg, SPIRVTypeInst ResType,
184 MachineInstr &I) const;
185
186 bool selectAny(Register ResVReg, SPIRVTypeInst ResType,
187 MachineInstr &I) const;
188
189 bool selectBitreverse(Register ResVReg, SPIRVTypeInst ResType,
190 MachineInstr &I) const;
191
192 bool selectBitreverse16(Register ResVReg, SPIRVTypeInst ResType,
193 MachineInstr &I, Register Op) const;
194
195 bool selectBitreverse32(Register ResVReg, SPIRVTypeInst ResType,
196 MachineInstr &I, Register Op) const;
197
198 bool selectBuildVector(Register ResVReg, SPIRVTypeInst ResType,
199 MachineInstr &I) const;
200 bool selectSplatVector(Register ResVReg, SPIRVTypeInst ResType,
201 MachineInstr &I) const;
202
203 bool selectCmp(Register ResVReg, SPIRVTypeInst ResType,
204 unsigned comparisonOpcode, MachineInstr &I) const;
205 bool selectDiscard(Register ResVReg, SPIRVTypeInst ResType,
206 MachineInstr &I) const;
207
208 bool selectICmp(Register ResVReg, SPIRVTypeInst ResType,
209 MachineInstr &I) const;
210 bool selectFCmp(Register ResVReg, SPIRVTypeInst ResType,
211 MachineInstr &I) const;
212
213 bool selectSign(Register ResVReg, SPIRVTypeInst ResType,
214 MachineInstr &I) const;
215
216 bool selectFloatDot(Register ResVReg, SPIRVTypeInst ResType,
217 MachineInstr &I) const;
218
219 bool selectOverflowArith(Register ResVReg, SPIRVTypeInst ResType,
220 MachineInstr &I, unsigned Opcode) const;
221 bool selectDebugTrap(Register ResVReg, SPIRVTypeInst ResType,
222 MachineInstr &I) const;
223
224 bool selectIntegerDot(Register ResVReg, SPIRVTypeInst ResType,
225 MachineInstr &I, bool Signed) const;
226
227 bool selectIntegerDotExpansion(Register ResVReg, SPIRVTypeInst ResType,
228 MachineInstr &I) const;
229
230 bool selectOpIsInf(Register ResVReg, SPIRVTypeInst ResType,
231 MachineInstr &I) const;
232
233 bool selectOpIsNan(Register ResVReg, SPIRVTypeInst ResType,
234 MachineInstr &I) const;
235
236 template <bool Signed>
237 bool selectDot4AddPacked(Register ResVReg, SPIRVTypeInst ResType,
238 MachineInstr &I) const;
239 template <bool Signed>
240 bool selectDot4AddPackedExpansion(Register ResVReg, SPIRVTypeInst ResType,
241 MachineInstr &I) const;
242
243 bool selectWavePrefixBitCount(Register ResVReg, SPIRVTypeInst ResType,
244 MachineInstr &I) const;
245
246 template <typename PickOpcodeFn>
247 bool selectWaveReduce(Register ResVReg, SPIRVTypeInst ResType,
248 MachineInstr &I, bool IsUnsigned,
249 PickOpcodeFn &&PickOpcode) const;
250
251 bool selectWaveReduceOp(Register ResVReg, SPIRVTypeInst ResType,
252 MachineInstr &I, unsigned Opcode) const;
253
254 bool selectWaveReduceMax(Register ResVReg, SPIRVTypeInst ResType,
255 MachineInstr &I, bool IsUnsigned) const;
256
257 bool selectWaveReduceMin(Register ResVReg, SPIRVTypeInst ResType,
258 MachineInstr &I, bool IsUnsigned) const;
259
260 bool selectWaveReduceSum(Register ResVReg, SPIRVTypeInst ResType,
261 MachineInstr &I) const;
262
263 bool selectWaveReduceProduct(Register ResVReg, const SPIRVTypeInst ResType,
264 MachineInstr &I) const;
265
266 template <typename PickOpcodeFn>
267 bool selectWaveExclusiveScan(Register ResVReg, SPIRVTypeInst ResType,
268 MachineInstr &I, bool IsUnsigned,
269 PickOpcodeFn &&PickOpcode) const;
270
271 bool selectWaveExclusiveScanSum(Register ResVReg, SPIRVTypeInst ResType,
272 MachineInstr &I) const;
273
274 bool selectWaveExclusiveScanProduct(Register ResVReg, SPIRVTypeInst ResType,
275 MachineInstr &I) const;
276
277 bool selectQuadSwap(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
278 unsigned Direction) const;
279
280 bool selectConst(Register ResVReg, SPIRVTypeInst ResType,
281 MachineInstr &I) const;
282
283 bool selectSelect(Register ResVReg, SPIRVTypeInst ResType,
284 MachineInstr &I) const;
285 bool selectBoolToInt(Register ResVReg, SPIRVTypeInst ResType,
286 Register BooleanVReg, MachineInstr &InsertAt,
287 bool IsSigned) const;
288 bool selectIToF(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
289 bool IsSigned, unsigned Opcode) const;
290 bool selectExt(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
291 bool IsSigned) const;
292
293 bool selectTrunc(Register ResVReg, SPIRVTypeInst ResType,
294 MachineInstr &I) const;
295
296 bool selectSUCmp(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
297 bool IsSigned) const;
298
299 bool selectIntToBool(Register IntReg, Register ResVReg, MachineInstr &I,
300 SPIRVTypeInst intTy, SPIRVTypeInst boolTy) const;
301
302 bool selectOpUndef(Register ResVReg, SPIRVTypeInst ResType,
303 MachineInstr &I) const;
304 bool selectFreeze(Register ResVReg, SPIRVTypeInst ResType,
305 MachineInstr &I) const;
306 bool selectIntrinsic(Register ResVReg, SPIRVTypeInst ResType,
307 MachineInstr &I) const;
308 bool selectExtractVal(Register ResVReg, SPIRVTypeInst ResType,
309 MachineInstr &I) const;
310 bool selectInsertVal(Register ResVReg, SPIRVTypeInst ResType,
311 MachineInstr &I) const;
312 bool selectExtractElt(Register ResVReg, SPIRVTypeInst ResType,
313 MachineInstr &I) const;
314 bool selectInsertElt(Register ResVReg, SPIRVTypeInst ResType,
315 MachineInstr &I) const;
316 bool selectGEP(Register ResVReg, SPIRVTypeInst ResType,
317 MachineInstr &I) const;
318
319 bool selectMaskedGather(Register ResVReg, SPIRVTypeInst ResType,
320 MachineInstr &I) const;
321 bool selectMaskedScatter(MachineInstr &I) const;
322
323 bool diagnoseUnsupported(const MachineInstr &I, const Twine &Msg) const;
324
325 bool selectFrameIndex(Register ResVReg, SPIRVTypeInst ResType,
326 MachineInstr &I) const;
327 bool selectAllocaArray(Register ResVReg, SPIRVTypeInst ResType,
328 MachineInstr &I) const;
329
330 bool selectBranch(MachineInstr &I) const;
331 bool selectBranchCond(MachineInstr &I) const;
332
333 bool selectPhi(Register ResVReg, MachineInstr &I) const;
334
335 bool selectExtInst(Register ResVReg, SPIRVTypeInst RestType, MachineInstr &I,
336 GL::GLSLExtInst GLInst, bool setMIFlags = true,
337 bool useMISrc = true,
338 ArrayRef<Register> SrcRegs = {}) const;
339 bool selectExtInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
340 CL::OpenCLExtInst CLInst, bool setMIFlags = true,
341 bool useMISrc = true,
342 ArrayRef<Register> SrcRegs = {}) const;
343 bool selectExtInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
344 CL::OpenCLExtInst CLInst, GL::GLSLExtInst GLInst,
345 bool setMIFlags = true, bool useMISrc = true,
346 ArrayRef<Register> SrcRegs = {}) const;
347 bool selectExtInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
348 const ExtInstList &ExtInsts, bool setMIFlags = true,
349 bool useMISrc = true,
350 ArrayRef<Register> SrcRegs = {}) const;
351
352 bool selectLog10(Register ResVReg, SPIRVTypeInst ResType,
353 MachineInstr &I) const;
354
355 bool selectFpowi(Register ResVReg, SPIRVTypeInst ResType,
356 MachineInstr &I) const;
357
358 bool selectSaturate(Register ResVReg, SPIRVTypeInst ResType,
359 MachineInstr &I) const;
360
361 bool selectWaveOpInst(Register ResVReg, SPIRVTypeInst ResType,
362 MachineInstr &I, unsigned Opcode) const;
363
364 bool selectWaveActiveCountBits(Register ResVReg, SPIRVTypeInst ResType,
365 MachineInstr &I) const;
366
367 bool selectWaveActiveAllEqual(Register ResVReg, SPIRVTypeInst ResType,
368 MachineInstr &I) const;
369
370 bool selectUnmergeValues(MachineInstr &I) const;
371
372 bool selectHandleFromBinding(Register &ResVReg, SPIRVTypeInst ResType,
373 MachineInstr &I) const;
374
375 bool selectCounterHandleFromBinding(Register &ResVReg, SPIRVTypeInst ResType,
376 MachineInstr &I) const;
377
378 bool selectReadImageIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
379 MachineInstr &I) const;
380 bool selectSampleBasicIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
381 MachineInstr &I) const;
382 bool selectSampleBiasIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
383 MachineInstr &I) const;
384 bool selectSampleGradIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
385 MachineInstr &I) const;
386 bool selectSampleLevelIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
387 MachineInstr &I) const;
388 bool selectLoadLevelIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
389 MachineInstr &I) const;
390 bool selectSampleCmpIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
391 MachineInstr &I) const;
392 bool selectSampleCmpLevelZeroIntrinsic(Register &ResVReg,
393 SPIRVTypeInst ResType,
394 MachineInstr &I) const;
395 bool selectGatherIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
396 MachineInstr &I) const;
397 bool selectImageWriteIntrinsic(MachineInstr &I) const;
398 bool selectResourceGetPointer(Register &ResVReg, SPIRVTypeInst ResType,
399 MachineInstr &I) const;
400 bool selectPushConstantGetPointer(Register &ResVReg, SPIRVTypeInst ResType,
401 MachineInstr &I) const;
402 bool selectResourceNonUniformIndex(Register &ResVReg, SPIRVTypeInst ResType,
403 MachineInstr &I) const;
404 bool selectModf(Register ResVReg, SPIRVTypeInst ResType,
405 MachineInstr &I) const;
406 bool selectUpdateCounter(Register &ResVReg, SPIRVTypeInst ResType,
407 MachineInstr &I) const;
408 bool selectFrexp(Register ResVReg, SPIRVTypeInst ResType,
409 MachineInstr &I) const;
410 bool selectSincos(Register ResVReg, SPIRVTypeInst ResType,
411 MachineInstr &I) const;
412 bool selectExp10(Register ResVReg, SPIRVTypeInst ResType,
413 MachineInstr &I) const;
414 bool selectDerivativeInst(Register ResVReg, SPIRVTypeInst ResType,
415 MachineInstr &I, const unsigned DPdOpCode) const;
416 // Utilities
417 Register buildI32Constant(uint32_t Val, MachineInstr &I,
418 SPIRVTypeInst ResType = nullptr) const;
419
420 Register buildZerosVal(SPIRVTypeInst ResType, MachineInstr &I) const;
421 bool isScalarOrVectorIntConstantZero(Register Reg) const;
422 Register buildZerosValF(SPIRVTypeInst ResType, MachineInstr &I) const;
423 Register buildOnesVal(bool AllOnes, SPIRVTypeInst ResType,
424 MachineInstr &I) const;
425 Register buildOnesValF(SPIRVTypeInst ResType, MachineInstr &I) const;
426
427 bool wrapIntoSpecConstantOp(MachineInstr &I,
428 SmallVector<Register> &CompositeArgs) const;
429
430 Register getUcharPtrTypeReg(MachineInstr &I,
431 SPIRV::StorageClass::StorageClass SC) const;
432 MachineInstrBuilder buildSpecConstantOp(MachineInstr &I, Register Dest,
433 Register Src, Register DestType,
434 uint32_t Opcode) const;
435 MachineInstrBuilder buildConstGenericPtr(MachineInstr &I, Register SrcPtr,
436 SPIRVTypeInst SrcPtrTy) const;
437 Register buildPointerToResource(SPIRVTypeInst ResType,
438 SPIRV::StorageClass::StorageClass SC,
439 uint32_t Set, uint32_t Binding,
440 uint32_t ArraySize, Register IndexReg,
441 StringRef Name,
442 MachineIRBuilder MIRBuilder) const;
443 SPIRVTypeInst widenTypeToVec4(SPIRVTypeInst Type, MachineInstr &I) const;
444 bool extractSubvector(Register &ResVReg, SPIRVTypeInst ResType,
445 Register &ReadReg, MachineInstr &InsertionPoint) const;
446 bool generateImageReadOrFetch(Register &ResVReg, SPIRVTypeInst ResType,
447 Register ImageReg, Register IdxReg,
448 DebugLoc Loc, MachineInstr &Pos,
449 const ImageOperands *ImOps = nullptr) const;
450 bool generateSampleImage(Register ResVReg, SPIRVTypeInst ResType,
451 Register ImageReg, Register SamplerReg,
452 Register CoordinateReg, const ImageOperands &ImOps,
453 DebugLoc Loc, MachineInstr &I) const;
454 bool BuildCOPY(Register DestReg, Register SrcReg, MachineInstr &I) const;
455 bool loadVec3BuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue,
456 Register ResVReg, SPIRVTypeInst ResType,
457 MachineInstr &I) const;
458 bool loadBuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue,
459 Register ResVReg, SPIRVTypeInst ResType,
460 MachineInstr &I) const;
461 bool loadHandleBeforePosition(Register &HandleReg, SPIRVTypeInst ResType,
462 GIntrinsic &HandleDef, MachineInstr &Pos) const;
463 void decorateUsesAsNonUniform(Register &NonUniformReg) const;
464 void errorIfInstrOutsideShader(MachineInstr &I) const;
465};
466
467bool sampledTypeIsSignedInteger(const llvm::Type *HandleType) {
468 const TargetExtType *TET = cast<TargetExtType>(HandleType);
469 if (TET->getTargetExtName() == "spirv.Image") {
470 return false;
471 }
472 assert(TET->getTargetExtName() == "spirv.SignedImage");
473 return TET->getTypeParameter(0)->isIntegerTy();
474}
475} // end anonymous namespace
476
477#define GET_GLOBALISEL_IMPL
478#include "SPIRVGenGlobalISel.inc"
479#undef GET_GLOBALISEL_IMPL
480
481SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
482 const SPIRVSubtarget &ST,
483 const RegisterBankInfo &RBI)
484 : InstructionSelector(), STI(ST), TII(*ST.getInstrInfo()),
485 TRI(*ST.getRegisterInfo()), RBI(RBI), GR(*ST.getSPIRVGlobalRegistry()),
486 MRI(nullptr),
488#include "SPIRVGenGlobalISel.inc"
491#include "SPIRVGenGlobalISel.inc"
493{
494}
495
496void SPIRVInstructionSelector::setupMF(MachineFunction &MF,
498 CodeGenCoverage *CoverageInfo,
500 BlockFrequencyInfo *BFI) {
501 MRI = &MF.getRegInfo();
502 GR.setCurrentFunc(MF);
503 InstructionSelector::setupMF(MF, VT, CoverageInfo, PSI, BFI);
504}
505
506// Ensure that register classes correspond to pattern matching rules.
507void SPIRVInstructionSelector::resetVRegsType(MachineFunction &MF) {
508 if (HasVRegsReset == &MF)
509 return;
510 HasVRegsReset = &MF;
511
512 MachineRegisterInfo &MRI = MF.getRegInfo();
513 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
514 Register Reg = Register::index2VirtReg(I);
515 LLT RegType = MRI.getType(Reg);
516 if (RegType.isScalar())
517 MRI.setType(Reg, LLT::scalar(64));
518 else if (RegType.isPointer())
519 MRI.setType(Reg, LLT::pointer(0, 64));
520 else if (RegType.isVector())
522 }
523 for (const auto &MBB : MF) {
524 for (const auto &MI : MBB) {
525 if (isPreISelGenericOpcode(MI.getOpcode()))
526 GR.erase(&MI);
527 if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)
528 continue;
529
530 Register DstReg = MI.getOperand(0).getReg();
531 LLT DstType = MRI.getType(DstReg);
532 Register SrcReg = MI.getOperand(1).getReg();
533 LLT SrcType = MRI.getType(SrcReg);
534 if (DstType != SrcType)
535 MRI.setType(DstReg, MRI.getType(SrcReg));
536
537 const TargetRegisterClass *DstRC = MRI.getRegClassOrNull(DstReg);
538 const TargetRegisterClass *SrcRC = MRI.getRegClassOrNull(SrcReg);
539 if (DstRC != SrcRC && SrcRC)
540 MRI.setRegClass(DstReg, SrcRC);
541 }
542 }
543}
544
545// Return true if the MachineInstr represents a constant register
546static bool isConstReg(MachineRegisterInfo *MRI, MachineInstr *OpDef) {
547
548 SmallVector<MachineInstr *> Stack = {OpDef};
550
551 while (!Stack.empty()) {
552 MachineInstr *MI = Stack.pop_back_val();
553 MI = passCopy(MI, MRI);
554 if (!Visited.insert(MI).second)
555 continue;
556 switch (MI->getOpcode()) {
557 case TargetOpcode::G_INTRINSIC:
558 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
559 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: {
561 unsigned IntrID = GIntr->getIntrinsicID();
562 if (IntrID != Intrinsic::spv_const_composite &&
563 IntrID != Intrinsic::spv_undef)
564 return false;
565 continue;
566 }
567 case TargetOpcode::G_BUILD_VECTOR:
568 case TargetOpcode::G_SPLAT_VECTOR:
569 for (unsigned i = OpDef->getNumExplicitDefs();
570 i < OpDef->getNumOperands(); i++) {
571 if (!OpDef->getOperand(i).isReg())
572 continue;
573 MachineInstr *OpNestedDef =
574 MRI->getVRegDef(OpDef->getOperand(i).getReg());
575 Stack.push_back(OpNestedDef);
576 }
577 continue;
578 case TargetOpcode::G_CONSTANT:
579 case TargetOpcode::G_FCONSTANT:
580 case TargetOpcode::G_IMPLICIT_DEF:
581 case SPIRV::OpConstantTrue:
582 case SPIRV::OpConstantFalse:
583 case SPIRV::OpConstantI:
584 case SPIRV::OpConstantF:
585 case SPIRV::OpConstantComposite:
586 case SPIRV::OpConstantCompositeContinuedINTEL:
587 case SPIRV::OpConstantSampler:
588 case SPIRV::OpConstantNull:
589 case SPIRV::OpUndef:
590 case SPIRV::OpConstantFunctionPointerINTEL:
591 continue;
592 default:
593 return false;
594 }
595 }
596 return true;
597}
598
599// Return true if the virtual register represents a constant
600static bool isConstReg(MachineRegisterInfo *MRI, Register OpReg) {
601 if (MachineInstr *OpDef = MRI->getVRegDef(OpReg))
602 return isConstReg(MRI, OpDef);
603 return false;
604}
605
606// TODO(168736): We should make this either a flag in tabelgen
607// or reduce our dependence on the global registry, so we can remove this
608// function. It can easily be missed when new intrinsics are added.
609
610// Most SPIR-V intrinsics are considered to have side-effects in their tablegen
611// definition because they are referenced in the global registry. This is a list
612// of intrinsics that have no side effects other than their references in the
613// global registry.
615 switch (ID) {
616 // This is not an exhaustive list and may need to be updated.
617 case Intrinsic::spv_all:
618 case Intrinsic::spv_alloca:
619 case Intrinsic::spv_any:
620 case Intrinsic::spv_bitcast:
621 case Intrinsic::spv_const_composite:
622 case Intrinsic::spv_cross:
623 case Intrinsic::spv_degrees:
624 case Intrinsic::spv_distance:
625 case Intrinsic::spv_extractelt:
626 case Intrinsic::spv_extractv:
627 case Intrinsic::spv_faceforward:
628 case Intrinsic::spv_fdot:
629 case Intrinsic::spv_firstbitlow:
630 case Intrinsic::spv_firstbitshigh:
631 case Intrinsic::spv_firstbituhigh:
632 case Intrinsic::spv_frac:
633 case Intrinsic::spv_gep:
634 case Intrinsic::spv_global_offset:
635 case Intrinsic::spv_global_size:
636 case Intrinsic::spv_group_id:
637 case Intrinsic::spv_insertelt:
638 case Intrinsic::spv_insertv:
639 case Intrinsic::spv_isinf:
640 case Intrinsic::spv_isnan:
641 case Intrinsic::spv_lerp:
642 case Intrinsic::spv_length:
643 case Intrinsic::spv_normalize:
644 case Intrinsic::spv_num_subgroups:
645 case Intrinsic::spv_num_workgroups:
646 case Intrinsic::spv_ptrcast:
647 case Intrinsic::spv_radians:
648 case Intrinsic::spv_reflect:
649 case Intrinsic::spv_refract:
650 case Intrinsic::spv_resource_getpointer:
651 case Intrinsic::spv_resource_handlefrombinding:
652 case Intrinsic::spv_resource_handlefromimplicitbinding:
653 case Intrinsic::spv_resource_nonuniformindex:
654 case Intrinsic::spv_resource_sample:
655 case Intrinsic::spv_rsqrt:
656 case Intrinsic::spv_saturate:
657 case Intrinsic::spv_sdot:
658 case Intrinsic::spv_sign:
659 case Intrinsic::spv_smoothstep:
660 case Intrinsic::spv_step:
661 case Intrinsic::spv_subgroup_id:
662 case Intrinsic::spv_subgroup_local_invocation_id:
663 case Intrinsic::spv_subgroup_max_size:
664 case Intrinsic::spv_subgroup_size:
665 case Intrinsic::spv_thread_id:
666 case Intrinsic::spv_thread_id_in_group:
667 case Intrinsic::spv_udot:
668 case Intrinsic::spv_undef:
669 case Intrinsic::spv_value_md:
670 case Intrinsic::spv_workgroup_size:
671 return false;
672 default:
673 return true;
674 }
675}
676
677// TODO(168736): We should make this either a flag in tabelgen
678// or reduce our dependence on the global registry, so we can remove this
679// function. It can easily be missed when new intrinsics are added.
680static bool isOpcodeWithNoSideEffects(unsigned Opcode) {
681 switch (Opcode) {
682 case SPIRV::OpTypeVoid:
683 case SPIRV::OpTypeBool:
684 case SPIRV::OpTypeInt:
685 case SPIRV::OpTypeFloat:
686 case SPIRV::OpTypeVector:
687 case SPIRV::OpTypeMatrix:
688 case SPIRV::OpTypeImage:
689 case SPIRV::OpTypeSampler:
690 case SPIRV::OpTypeSampledImage:
691 case SPIRV::OpTypeArray:
692 case SPIRV::OpTypeRuntimeArray:
693 case SPIRV::OpTypeStruct:
694 case SPIRV::OpTypeOpaque:
695 case SPIRV::OpTypePointer:
696 case SPIRV::OpTypeFunction:
697 case SPIRV::OpTypeEvent:
698 case SPIRV::OpTypeDeviceEvent:
699 case SPIRV::OpTypeReserveId:
700 case SPIRV::OpTypeQueue:
701 case SPIRV::OpTypePipe:
702 case SPIRV::OpTypeForwardPointer:
703 case SPIRV::OpTypePipeStorage:
704 case SPIRV::OpTypeNamedBarrier:
705 case SPIRV::OpTypeAccelerationStructureNV:
706 case SPIRV::OpTypeCooperativeMatrixNV:
707 case SPIRV::OpTypeCooperativeMatrixKHR:
708 return true;
709 default:
710 return false;
711 }
712}
713
714bool isDead(const MachineInstr &MI, const MachineRegisterInfo &MRI) {
715 // If there are no definitions, then assume there is some other
716 // side-effect that makes this instruction live.
717 if (MI.getNumDefs() == 0)
718 return false;
719
720 for (const auto &MO : MI.all_defs()) {
721 Register Reg = MO.getReg();
722 if (Reg.isPhysical()) {
723 LLVM_DEBUG(dbgs() << "Not dead: def of physical register " << Reg);
724 return false;
725 }
726 for (const auto &UseMI : MRI.use_nodbg_instructions(Reg)) {
727 if (UseMI.getOpcode() != SPIRV::OpName) {
728 LLVM_DEBUG(dbgs() << "Not dead: def " << MO << " has use in " << UseMI);
729 return false;
730 }
731 }
732 }
733
734 if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE || MI.isFakeUse() ||
735 MI.isLifetimeMarker()) {
737 dbgs()
738 << "Not dead: Opcode is LOCAL_ESCAPE, fake use, or lifetime marker.\n");
739 return false;
740 }
741 if (MI.isPHI()) {
742 LLVM_DEBUG(dbgs() << "Dead: Phi instruction with no uses.\n");
743 return true;
744 }
745
746 // It is possible that the only side effect is that the instruction is
747 // referenced in the global registry. If that is the only side effect, the
748 // intrinsic is dead.
749 if (MI.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
750 MI.getOpcode() == TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS) {
751 const auto &Intr = cast<GIntrinsic>(MI);
752 if (!intrinsicHasSideEffects(Intr.getIntrinsicID())) {
753 LLVM_DEBUG(dbgs() << "Dead: Intrinsic with no real side effects.\n");
754 return true;
755 }
756 }
757
758 if (MI.mayStore() || MI.isCall() ||
759 (MI.mayLoad() && MI.hasOrderedMemoryRef()) || MI.isPosition() ||
760 MI.isDebugInstr() || MI.isTerminator() || MI.isJumpTableDebugInfo()) {
761 LLVM_DEBUG(dbgs() << "Not dead: instruction has side effects.\n");
762 return false;
763 }
764
765 if (isPreISelGenericOpcode(MI.getOpcode())) {
766 // TODO: Is there a generic way to check if the opcode has side effects?
767 LLVM_DEBUG(dbgs() << "Dead: Generic opcode with no uses.\n");
768 return true;
769 }
770
771 if (isOpcodeWithNoSideEffects(MI.getOpcode())) {
772 LLVM_DEBUG(dbgs() << "Dead: known opcode with no side effects\n");
773 return true;
774 }
775
776 return false;
777}
778
779void SPIRVInstructionSelector::removeOpNamesForDeadMI(MachineInstr &MI) const {
780 // Delete the OpName that uses the result if there is one.
781 for (const auto &MO : MI.all_defs()) {
782 Register Reg = MO.getReg();
783 if (Reg.isPhysical())
784 continue;
785 SmallVector<MachineInstr *, 4> UselessOpNames;
786 for (MachineInstr &UseMI : MRI->use_nodbg_instructions(Reg)) {
787 assert(UseMI.getOpcode() == SPIRV::OpName &&
788 "There is still a use of the dead function.");
789 UselessOpNames.push_back(&UseMI);
790 }
791 for (MachineInstr *OpNameMI : UselessOpNames) {
792 GR.invalidateMachineInstr(OpNameMI);
793 OpNameMI->eraseFromParent();
794 }
795 }
796}
797
798void SPIRVInstructionSelector::removeDeadInstruction(MachineInstr &MI) const {
799 salvageDebugInfo(*MRI, MI);
801 removeOpNamesForDeadMI(MI);
802 MI.eraseFromParent();
803}
804
805bool SPIRVInstructionSelector::select(MachineInstr &I) {
806 resetVRegsType(*I.getParent()->getParent());
807
808 assert(I.getParent() && "Instruction should be in a basic block!");
809 assert(I.getParent()->getParent() && "Instruction should be in a function!");
810
811 LLVM_DEBUG(dbgs() << "Checking if instruction is dead: " << I;);
812 if (isDead(I, *MRI)) {
813 LLVM_DEBUG(dbgs() << "Instruction is dead.\n");
814 removeDeadInstruction(I);
815 return true;
816 }
817
818 Register Opcode = I.getOpcode();
819 // If it's not a GMIR instruction, we've selected it already.
820 if (!isPreISelGenericOpcode(Opcode)) {
821 if (Opcode == SPIRV::ASSIGN_TYPE) { // These pseudos aren't needed any more.
822 Register DstReg = I.getOperand(0).getReg();
823 Register SrcReg = I.getOperand(1).getReg();
824 auto *Def = MRI->getVRegDef(SrcReg);
825 if (isTypeFoldingSupported(Def->getOpcode()) &&
826 Def->getOpcode() != TargetOpcode::G_CONSTANT &&
827 Def->getOpcode() != TargetOpcode::G_FCONSTANT) {
828 if (Def->getOpcode() == TargetOpcode::G_SELECT) {
829 Register SelectDstReg = Def->getOperand(0).getReg();
830 bool SuccessToSelectSelect [[maybe_unused]] = selectSelect(
831 SelectDstReg, GR.getSPIRVTypeForVReg(SelectDstReg), *Def);
832 assert(SuccessToSelectSelect);
834 Def->eraseFromParent();
835 MRI->replaceRegWith(DstReg, SelectDstReg);
837 I.eraseFromParent();
838 return true;
839 }
840
841 bool Res = selectImpl(I, *CoverageInfo);
842 LLVM_DEBUG({
843 if (!Res && Def->getOpcode() != TargetOpcode::G_CONSTANT) {
844 dbgs() << "Unexpected pattern in ASSIGN_TYPE.\nInstruction: ";
845 I.print(dbgs());
846 }
847 });
848 assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT);
849 if (Res) {
850 if (!isTriviallyDead(*Def, *MRI) && isDead(*Def, *MRI))
851 DeadMIs.insert(Def);
852 return Res;
853 }
854 }
855 MRI->setRegClass(SrcReg, MRI->getRegClass(DstReg));
856 MRI->replaceRegWith(SrcReg, DstReg);
858 I.eraseFromParent();
859 return true;
860 } else if (I.getNumDefs() == 1) {
861 // Make all vregs 64 bits (for SPIR-V IDs).
862 MRI->setType(I.getOperand(0).getReg(), LLT::scalar(64));
863 }
865 return true;
866 }
867
868 if (DeadMIs.contains(&I)) {
869 // if the instruction has been already made dead by folding it away
870 // erase it
871 LLVM_DEBUG(dbgs() << "Instruction is folded and dead.\n");
872 removeDeadInstruction(I);
873 DeadMIs.erase(&I);
874 return true;
875 }
876
877 if (I.getNumOperands() != I.getNumExplicitOperands()) {
878 LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
879 return false;
880 }
881
882 // Common code for getting return reg+type, and removing selected instr
883 // from parent occurs here. Instr-specific selection happens in spvSelect().
884 bool HasDefs = I.getNumDefs() > 0;
885 Register ResVReg = HasDefs ? I.getOperand(0).getReg() : Register(0);
886 SPIRVTypeInst ResType = HasDefs ? GR.getSPIRVTypeForVReg(ResVReg) : nullptr;
887 assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
888 I.getOpcode() == TargetOpcode::G_IMPLICIT_DEF);
889 if (spvSelect(ResVReg, ResType, I)) {
890 if (HasDefs) // Make all vregs 64 bits (for SPIR-V IDs).
891 for (unsigned i = 0; i < I.getNumDefs(); ++i)
892 MRI->setType(I.getOperand(i).getReg(), LLT::scalar(64));
894 I.eraseFromParent();
895 return true;
896 }
897 return false;
898}
899
900static bool mayApplyGenericSelection(unsigned Opcode) {
901 switch (Opcode) {
902 case TargetOpcode::G_CONSTANT:
903 case TargetOpcode::G_FCONSTANT:
904 return false;
905 case TargetOpcode::G_SADDO:
906 case TargetOpcode::G_SSUBO:
907 return true;
908 }
909 return isTypeFoldingSupported(Opcode);
910}
911
912bool SPIRVInstructionSelector::BuildCOPY(Register DestReg, Register SrcReg,
913 MachineInstr &I) const {
914 const TargetRegisterClass *DstRC = MRI->getRegClassOrNull(DestReg);
915 const TargetRegisterClass *SrcRC = MRI->getRegClassOrNull(SrcReg);
916 if (DstRC != SrcRC && SrcRC)
917 MRI->setRegClass(DestReg, SrcRC);
918 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::COPY))
919 .addDef(DestReg)
920 .addUse(SrcReg)
921 .constrainAllUses(TII, TRI, RBI);
922 return true;
923}
924
925bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
926 SPIRVTypeInst ResType,
927 MachineInstr &I) const {
928 const unsigned Opcode = I.getOpcode();
929 if (mayApplyGenericSelection(Opcode))
930 return selectImpl(I, *CoverageInfo);
931 switch (Opcode) {
932 case TargetOpcode::G_CONSTANT:
933 case TargetOpcode::G_FCONSTANT:
934 return selectConst(ResVReg, ResType, I);
935 case TargetOpcode::G_GLOBAL_VALUE:
936 return selectGlobalValue(ResVReg, I);
937 case TargetOpcode::G_IMPLICIT_DEF:
938 return selectOpUndef(ResVReg, ResType, I);
939 case TargetOpcode::G_FREEZE:
940 return selectFreeze(ResVReg, ResType, I);
941
942 case TargetOpcode::G_INTRINSIC:
943 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
944 case TargetOpcode::G_INTRINSIC_CONVERGENT:
945 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
946 return selectIntrinsic(ResVReg, ResType, I);
947 case TargetOpcode::G_BITREVERSE:
948 return selectBitreverse(ResVReg, ResType, I);
949
950 case TargetOpcode::G_BUILD_VECTOR:
951 return selectBuildVector(ResVReg, ResType, I);
952 case TargetOpcode::G_SPLAT_VECTOR:
953 return selectSplatVector(ResVReg, ResType, I);
954
955 case TargetOpcode::G_SHUFFLE_VECTOR: {
956 MachineBasicBlock &BB = *I.getParent();
957 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle))
958 .addDef(ResVReg)
959 .addUse(GR.getSPIRVTypeID(ResType))
960 .addUse(I.getOperand(1).getReg())
961 .addUse(I.getOperand(2).getReg());
962 for (auto V : I.getOperand(3).getShuffleMask())
963 MIB.addImm(V);
964 MIB.constrainAllUses(TII, TRI, RBI);
965 return true;
966 }
967 case TargetOpcode::G_MEMMOVE:
968 case TargetOpcode::G_MEMCPY:
969 case TargetOpcode::G_MEMSET:
970 return selectMemOperation(ResVReg, I);
971
972 case TargetOpcode::G_ICMP:
973 return selectICmp(ResVReg, ResType, I);
974 case TargetOpcode::G_FCMP:
975 return selectFCmp(ResVReg, ResType, I);
976
977 case TargetOpcode::G_FRAME_INDEX:
978 return selectFrameIndex(ResVReg, ResType, I);
979
980 case TargetOpcode::G_LOAD:
981 return selectLoad(ResVReg, ResType, I);
982 case TargetOpcode::G_STORE:
983 return selectStore(I);
984
985 case TargetOpcode::G_BR:
986 return selectBranch(I);
987 case TargetOpcode::G_BRCOND:
988 return selectBranchCond(I);
989
990 case TargetOpcode::G_PHI:
991 return selectPhi(ResVReg, I);
992
993 case TargetOpcode::G_FPTOSI:
994 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
995 case TargetOpcode::G_FPTOUI:
996 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
997
998 case TargetOpcode::G_FPTOSI_SAT:
999 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
1000 case TargetOpcode::G_FPTOUI_SAT:
1001 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
1002
1003 case TargetOpcode::G_SITOFP:
1004 return selectIToF(ResVReg, ResType, I, true, SPIRV::OpConvertSToF);
1005 case TargetOpcode::G_UITOFP:
1006 return selectIToF(ResVReg, ResType, I, false, SPIRV::OpConvertUToF);
1007
1008 case TargetOpcode::G_CTPOP:
1009 return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitCount);
1010 case TargetOpcode::G_SMIN:
1011 return selectExtInst(ResVReg, ResType, I, CL::s_min, GL::SMin);
1012 case TargetOpcode::G_UMIN:
1013 return selectExtInst(ResVReg, ResType, I, CL::u_min, GL::UMin);
1014
1015 case TargetOpcode::G_SMAX:
1016 return selectExtInst(ResVReg, ResType, I, CL::s_max, GL::SMax);
1017 case TargetOpcode::G_UMAX:
1018 return selectExtInst(ResVReg, ResType, I, CL::u_max, GL::UMax);
1019
1020 case TargetOpcode::G_SCMP:
1021 return selectSUCmp(ResVReg, ResType, I, true);
1022 case TargetOpcode::G_UCMP:
1023 return selectSUCmp(ResVReg, ResType, I, false);
1024 case TargetOpcode::G_LROUND:
1025 case TargetOpcode::G_LLROUND: {
1026 Register regForLround =
1027 MRI->createVirtualRegister(MRI->getRegClass(ResVReg), "lround");
1028 MRI->setRegClass(regForLround, &SPIRV::iIDRegClass);
1029 GR.assignSPIRVTypeToVReg(GR.getSPIRVTypeForVReg(I.getOperand(1).getReg()),
1030 regForLround, *(I.getParent()->getParent()));
1031 selectExtInst(regForLround, GR.getSPIRVTypeForVReg(regForLround), I,
1032 CL::round, GL::Round, /* setMIFlags */ false);
1033 MachineBasicBlock &BB = *I.getParent();
1034 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConvertFToS))
1035 .addDef(ResVReg)
1036 .addUse(GR.getSPIRVTypeID(ResType))
1037 .addUse(regForLround);
1038 MIB.constrainAllUses(TII, TRI, RBI);
1039 return true;
1040 }
1041 case TargetOpcode::G_STRICT_FMA:
1042 case TargetOpcode::G_FMA: {
1043 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_fma)) {
1044 MachineBasicBlock &BB = *I.getParent();
1045 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpFmaKHR))
1046 .addDef(ResVReg)
1047 .addUse(GR.getSPIRVTypeID(ResType))
1048 .addUse(I.getOperand(1).getReg())
1049 .addUse(I.getOperand(2).getReg())
1050 .addUse(I.getOperand(3).getReg())
1051 .setMIFlags(I.getFlags());
1052 MIB.constrainAllUses(TII, TRI, RBI);
1053 return true;
1054 }
1055 return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
1056 }
1057
1058 case TargetOpcode::G_STRICT_FLDEXP:
1059 return selectExtInst(ResVReg, ResType, I, CL::ldexp);
1060
1061 case TargetOpcode::G_FPOW:
1062 return selectExtInst(ResVReg, ResType, I, CL::pow, GL::Pow);
1063 case TargetOpcode::G_FPOWI:
1064 return selectFpowi(ResVReg, ResType, I);
1065
1066 case TargetOpcode::G_FEXP:
1067 return selectExtInst(ResVReg, ResType, I, CL::exp, GL::Exp);
1068 case TargetOpcode::G_FEXP2:
1069 return selectExtInst(ResVReg, ResType, I, CL::exp2, GL::Exp2);
1070 case TargetOpcode::G_FEXP10:
1071 return selectExp10(ResVReg, ResType, I);
1072
1073 case TargetOpcode::G_FMODF:
1074 return selectModf(ResVReg, ResType, I);
1075 case TargetOpcode::G_FSINCOS:
1076 return selectSincos(ResVReg, ResType, I);
1077
1078 case TargetOpcode::G_FLOG:
1079 return selectExtInst(ResVReg, ResType, I, CL::log, GL::Log);
1080 case TargetOpcode::G_FLOG2:
1081 return selectExtInst(ResVReg, ResType, I, CL::log2, GL::Log2);
1082 case TargetOpcode::G_FLOG10:
1083 return selectLog10(ResVReg, ResType, I);
1084
1085 case TargetOpcode::G_FABS:
1086 return selectExtInst(ResVReg, ResType, I, CL::fabs, GL::FAbs);
1087 case TargetOpcode::G_ABS:
1088 return selectExtInst(ResVReg, ResType, I, CL::s_abs, GL::SAbs);
1089
1090 case TargetOpcode::G_FMINNUM:
1091 case TargetOpcode::G_FMINIMUM:
1092 return selectExtInst(ResVReg, ResType, I, CL::fmin, GL::NMin);
1093 case TargetOpcode::G_FMAXNUM:
1094 case TargetOpcode::G_FMAXIMUM:
1095 return selectExtInst(ResVReg, ResType, I, CL::fmax, GL::NMax);
1096
1097 case TargetOpcode::G_FCOPYSIGN:
1098 return selectExtInst(ResVReg, ResType, I, CL::copysign);
1099
1100 case TargetOpcode::G_FCEIL:
1101 return selectExtInst(ResVReg, ResType, I, CL::ceil, GL::Ceil);
1102 case TargetOpcode::G_FFLOOR:
1103 return selectExtInst(ResVReg, ResType, I, CL::floor, GL::Floor);
1104
1105 case TargetOpcode::G_FCOS:
1106 return selectExtInst(ResVReg, ResType, I, CL::cos, GL::Cos);
1107 case TargetOpcode::G_FSIN:
1108 return selectExtInst(ResVReg, ResType, I, CL::sin, GL::Sin);
1109 case TargetOpcode::G_FTAN:
1110 return selectExtInst(ResVReg, ResType, I, CL::tan, GL::Tan);
1111 case TargetOpcode::G_FACOS:
1112 return selectExtInst(ResVReg, ResType, I, CL::acos, GL::Acos);
1113 case TargetOpcode::G_FASIN:
1114 return selectExtInst(ResVReg, ResType, I, CL::asin, GL::Asin);
1115 case TargetOpcode::G_FATAN:
1116 return selectExtInst(ResVReg, ResType, I, CL::atan, GL::Atan);
1117 case TargetOpcode::G_FATAN2:
1118 return selectExtInst(ResVReg, ResType, I, CL::atan2, GL::Atan2);
1119 case TargetOpcode::G_FCOSH:
1120 return selectExtInst(ResVReg, ResType, I, CL::cosh, GL::Cosh);
1121 case TargetOpcode::G_FSINH:
1122 return selectExtInst(ResVReg, ResType, I, CL::sinh, GL::Sinh);
1123 case TargetOpcode::G_FTANH:
1124 return selectExtInst(ResVReg, ResType, I, CL::tanh, GL::Tanh);
1125
1126 case TargetOpcode::G_STRICT_FSQRT:
1127 case TargetOpcode::G_FSQRT:
1128 return selectExtInst(ResVReg, ResType, I, CL::sqrt, GL::Sqrt);
1129
1130 case TargetOpcode::G_CTTZ:
1131 case TargetOpcode::G_CTTZ_ZERO_UNDEF:
1132 return selectExtInst(ResVReg, ResType, I, CL::ctz);
1133 case TargetOpcode::G_CTLZ:
1134 case TargetOpcode::G_CTLZ_ZERO_UNDEF:
1135 return selectExtInst(ResVReg, ResType, I, CL::clz);
1136
1137 case TargetOpcode::G_INTRINSIC_ROUND:
1138 return selectExtInst(ResVReg, ResType, I, CL::round, GL::Round);
1139 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1140 return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven);
1141 case TargetOpcode::G_INTRINSIC_TRUNC:
1142 return selectExtInst(ResVReg, ResType, I, CL::trunc, GL::Trunc);
1143 case TargetOpcode::G_FRINT:
1144 case TargetOpcode::G_FNEARBYINT:
1145 return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven);
1146
1147 case TargetOpcode::G_SMULH:
1148 return selectExtInst(ResVReg, ResType, I, CL::s_mul_hi);
1149 case TargetOpcode::G_UMULH:
1150 return selectExtInst(ResVReg, ResType, I, CL::u_mul_hi);
1151
1152 case TargetOpcode::G_SADDSAT:
1153 return selectExtInst(ResVReg, ResType, I, CL::s_add_sat);
1154 case TargetOpcode::G_UADDSAT:
1155 return selectExtInst(ResVReg, ResType, I, CL::u_add_sat);
1156 case TargetOpcode::G_SSUBSAT:
1157 return selectExtInst(ResVReg, ResType, I, CL::s_sub_sat);
1158 case TargetOpcode::G_USUBSAT:
1159 return selectExtInst(ResVReg, ResType, I, CL::u_sub_sat);
1160
1161 case TargetOpcode::G_FFREXP:
1162 return selectFrexp(ResVReg, ResType, I);
1163
1164 case TargetOpcode::G_UADDO:
1165 return selectOverflowArith(ResVReg, ResType, I,
1166 ResType->getOpcode() == SPIRV::OpTypeVector
1167 ? SPIRV::OpIAddCarryV
1168 : SPIRV::OpIAddCarryS);
1169 case TargetOpcode::G_USUBO:
1170 return selectOverflowArith(ResVReg, ResType, I,
1171 ResType->getOpcode() == SPIRV::OpTypeVector
1172 ? SPIRV::OpISubBorrowV
1173 : SPIRV::OpISubBorrowS);
1174 case TargetOpcode::G_UMULO:
1175 return selectOverflowArith(ResVReg, ResType, I, SPIRV::OpUMulExtended);
1176 case TargetOpcode::G_SMULO:
1177 return selectOverflowArith(ResVReg, ResType, I, SPIRV::OpSMulExtended);
1178
1179 case TargetOpcode::G_SEXT:
1180 return selectExt(ResVReg, ResType, I, true);
1181 case TargetOpcode::G_ANYEXT:
1182 case TargetOpcode::G_ZEXT:
1183 return selectExt(ResVReg, ResType, I, false);
1184 case TargetOpcode::G_TRUNC:
1185 return selectTrunc(ResVReg, ResType, I);
1186 case TargetOpcode::G_FPTRUNC:
1187 case TargetOpcode::G_FPEXT:
1188 return selectUnOp(ResVReg, ResType, I, SPIRV::OpFConvert);
1189
1190 case TargetOpcode::G_PTRTOINT:
1191 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertPtrToU);
1192 case TargetOpcode::G_INTTOPTR:
1193 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertUToPtr);
1194 case TargetOpcode::G_BITCAST:
1195 return selectBitcast(ResVReg, ResType, I);
1196 case TargetOpcode::G_ADDRSPACE_CAST:
1197 return selectAddrSpaceCast(ResVReg, ResType, I);
1198 case TargetOpcode::G_PTR_ADD: {
1199 // Currently, we get G_PTR_ADD only applied to global variables.
1200 assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
1201 Register GV = I.getOperand(1).getReg();
1203 (void)II;
1204 assert(((*II).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
1205 (*II).getOpcode() == TargetOpcode::COPY ||
1206 (*II).getOpcode() == SPIRV::OpVariable) &&
1207 getImm(I.getOperand(2), MRI));
1208 // It may be the initialization of a global variable.
1209 bool IsGVInit = false;
1211 UseIt = MRI->use_instr_begin(I.getOperand(0).getReg()),
1212 UseEnd = MRI->use_instr_end();
1213 UseIt != UseEnd; UseIt = std::next(UseIt)) {
1214 if ((*UseIt).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
1215 (*UseIt).getOpcode() == SPIRV::OpSpecConstantOp ||
1216 (*UseIt).getOpcode() == SPIRV::OpVariable) {
1217 IsGVInit = true;
1218 break;
1219 }
1220 }
1221 MachineBasicBlock &BB = *I.getParent();
1222 if (!IsGVInit) {
1223 SPIRVTypeInst GVType = GR.getSPIRVTypeForVReg(GV);
1224 SPIRVTypeInst GVPointeeType = GR.getPointeeType(GVType);
1225 SPIRVTypeInst ResPointeeType = GR.getPointeeType(ResType);
1226 if (GVPointeeType && ResPointeeType && GVPointeeType != ResPointeeType) {
1227 // Build a new virtual register that is associated with the required
1228 // data type.
1229 Register NewVReg = MRI->createGenericVirtualRegister(MRI->getType(GV));
1230 MRI->setRegClass(NewVReg, MRI->getRegClass(GV));
1231 // Having a correctly typed base we are ready to build the actually
1232 // required GEP. It may not be a constant though, because all Operands
1233 // of OpSpecConstantOp is to originate from other const instructions,
1234 // and only the AccessChain named opcodes accept a global OpVariable
1235 // instruction. We can't use an AccessChain opcode because of the type
1236 // mismatch between result and base types.
1237 if (!GR.isBitcastCompatible(ResType, GVType))
1239 "incompatible result and operand types in a bitcast");
1240 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
1241 MachineInstrBuilder MIB =
1242 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitcast))
1243 .addDef(NewVReg)
1244 .addUse(ResTypeReg)
1245 .addUse(GV);
1246 MIB.constrainAllUses(TII, TRI, RBI);
1247 BuildMI(BB, I, I.getDebugLoc(),
1248 TII.get(STI.isLogicalSPIRV() ? SPIRV::OpInBoundsAccessChain
1249 : SPIRV::OpInBoundsPtrAccessChain))
1250 .addDef(ResVReg)
1251 .addUse(ResTypeReg)
1252 .addUse(NewVReg)
1253 .addUse(I.getOperand(2).getReg())
1254 .constrainAllUses(TII, TRI, RBI);
1255 } else {
1256 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
1257 .addDef(ResVReg)
1258 .addUse(GR.getSPIRVTypeID(ResType))
1259 .addImm(
1260 static_cast<uint32_t>(SPIRV::Opcode::InBoundsPtrAccessChain))
1261 .addUse(GV)
1262 .addUse(I.getOperand(2).getReg())
1263 .constrainAllUses(TII, TRI, RBI);
1264 }
1265 return true;
1266 }
1267 // It's possible to translate G_PTR_ADD to OpSpecConstantOp: either to
1268 // initialize a global variable with a constant expression (e.g., the test
1269 // case opencl/basic/progvar_prog_scope_init.ll), or for another use case
1270 Register Idx = buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I);
1271 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
1272 .addDef(ResVReg)
1273 .addUse(GR.getSPIRVTypeID(ResType))
1274 .addImm(static_cast<uint32_t>(
1275 SPIRV::Opcode::InBoundsPtrAccessChain))
1276 .addUse(GV)
1277 .addUse(Idx)
1278 .addUse(I.getOperand(2).getReg());
1279 MIB.constrainAllUses(TII, TRI, RBI);
1280 return true;
1281 }
1282
1283 case TargetOpcode::G_ATOMICRMW_OR:
1284 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicOr);
1285 case TargetOpcode::G_ATOMICRMW_ADD:
1286 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicIAdd);
1287 case TargetOpcode::G_ATOMICRMW_AND:
1288 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicAnd);
1289 case TargetOpcode::G_ATOMICRMW_MAX:
1290 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMax);
1291 case TargetOpcode::G_ATOMICRMW_MIN:
1292 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMin);
1293 case TargetOpcode::G_ATOMICRMW_SUB:
1294 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicISub);
1295 case TargetOpcode::G_ATOMICRMW_XOR:
1296 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicXor);
1297 case TargetOpcode::G_ATOMICRMW_UMAX:
1298 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMax);
1299 case TargetOpcode::G_ATOMICRMW_UMIN:
1300 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMin);
1301 case TargetOpcode::G_ATOMICRMW_XCHG:
1302 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicExchange);
1303 case TargetOpcode::G_ATOMIC_CMPXCHG:
1304 return selectAtomicCmpXchg(ResVReg, ResType, I);
1305
1306 case TargetOpcode::G_ATOMICRMW_FADD:
1307 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFAddEXT);
1308 case TargetOpcode::G_ATOMICRMW_FSUB:
1309 // Translate G_ATOMICRMW_FSUB to OpAtomicFAddEXT with negative value operand
1310 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFAddEXT,
1311 ResType->getOpcode() == SPIRV::OpTypeVector
1312 ? SPIRV::OpFNegateV
1313 : SPIRV::OpFNegate);
1314 case TargetOpcode::G_ATOMICRMW_FMIN:
1315 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFMinEXT);
1316 case TargetOpcode::G_ATOMICRMW_FMAX:
1317 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFMaxEXT);
1318
1319 case TargetOpcode::G_FENCE:
1320 return selectFence(I);
1321
1322 case TargetOpcode::G_STACKSAVE:
1323 return selectStackSave(ResVReg, ResType, I);
1324 case TargetOpcode::G_STACKRESTORE:
1325 return selectStackRestore(I);
1326
1327 case TargetOpcode::G_UNMERGE_VALUES:
1328 return selectUnmergeValues(I);
1329
1330 // Discard gen opcodes for intrinsics which we do not expect to actually
1331 // represent code after lowering or intrinsics which are not implemented but
1332 // should not crash when found in a customer's LLVM IR input.
1333 case TargetOpcode::G_TRAP:
1334 case TargetOpcode::G_UBSANTRAP:
1335 case TargetOpcode::DBG_LABEL:
1336 return true;
1337 case TargetOpcode::G_DEBUGTRAP:
1338 return selectDebugTrap(ResVReg, ResType, I);
1339
1340 default:
1341 return false;
1342 }
1343}
1344
1345bool SPIRVInstructionSelector::selectDebugTrap(Register ResVReg,
1346 SPIRVTypeInst ResType,
1347 MachineInstr &I) const {
1348 unsigned Opcode = SPIRV::OpNop;
1349 MachineBasicBlock &BB = *I.getParent();
1350 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
1351 .constrainAllUses(TII, TRI, RBI);
1352 return true;
1353}
1354
1355bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
1356 SPIRVTypeInst ResType,
1357 MachineInstr &I,
1358 GL::GLSLExtInst GLInst,
1359 bool setMIFlags, bool useMISrc,
1360 ArrayRef<Register> SrcRegs) const {
1361 if (!STI.canUseExtInstSet(
1362 SPIRV::InstructionSet::InstructionSet::GLSL_std_450)) {
1363 std::string DiagMsg;
1364 raw_string_ostream OS(DiagMsg);
1365 I.print(OS, true, false, false, false);
1366 DiagMsg += " is only supported with the GLSL extended instruction set.\n";
1367 report_fatal_error(DiagMsg.c_str(), false);
1368 }
1369 return selectExtInst(ResVReg, ResType, I,
1370 {{SPIRV::InstructionSet::GLSL_std_450, GLInst}},
1371 setMIFlags, useMISrc, SrcRegs);
1372}
1373
1374bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
1375 SPIRVTypeInst ResType,
1376 MachineInstr &I,
1377 CL::OpenCLExtInst CLInst,
1378 bool setMIFlags, bool useMISrc,
1379 ArrayRef<Register> SrcRegs) const {
1380 return selectExtInst(ResVReg, ResType, I,
1381 {{SPIRV::InstructionSet::OpenCL_std, CLInst}},
1382 setMIFlags, useMISrc, SrcRegs);
1383}
1384
1385bool SPIRVInstructionSelector::selectExtInst(
1386 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
1387 CL::OpenCLExtInst CLInst, GL::GLSLExtInst GLInst, bool setMIFlags,
1388 bool useMISrc, ArrayRef<Register> SrcRegs) const {
1389 ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst},
1390 {SPIRV::InstructionSet::GLSL_std_450, GLInst}};
1391 return selectExtInst(ResVReg, ResType, I, ExtInsts, setMIFlags, useMISrc,
1392 SrcRegs);
1393}
1394
1395bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
1396 SPIRVTypeInst ResType,
1397 MachineInstr &I,
1398 const ExtInstList &Insts,
1399 bool setMIFlags, bool useMISrc,
1400 ArrayRef<Register> SrcRegs) const {
1401
1402 for (const auto &[InstructionSet, Opcode] : Insts) {
1403 if (!STI.canUseExtInstSet(InstructionSet))
1404 continue;
1405 MachineBasicBlock &BB = *I.getParent();
1406 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1407 .addDef(ResVReg)
1408 .addUse(GR.getSPIRVTypeID(ResType))
1409 .addImm(static_cast<uint32_t>(InstructionSet))
1410 .addImm(Opcode);
1411 if (setMIFlags)
1412 MIB.setMIFlags(I.getFlags());
1413 if (useMISrc) {
1414 const unsigned NumOps = I.getNumOperands();
1415 unsigned Index = 1;
1416 if (Index < NumOps &&
1417 I.getOperand(Index).getType() ==
1418 MachineOperand::MachineOperandType::MO_IntrinsicID)
1419 Index = 2;
1420 for (; Index < NumOps; ++Index)
1421 MIB.add(I.getOperand(Index));
1422 } else {
1423 for (Register SReg : SrcRegs) {
1424 MIB.addUse(SReg);
1425 }
1426 }
1427 MIB.constrainAllUses(TII, TRI, RBI);
1428 return true;
1429 }
1430 return false;
1431}
1432
1433bool SPIRVInstructionSelector::selectFrexp(Register ResVReg,
1434 SPIRVTypeInst ResType,
1435 MachineInstr &I) const {
1436 ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CL::frexp},
1437 {SPIRV::InstructionSet::GLSL_std_450, GL::Frexp}};
1438 for (const auto &Ex : ExtInsts) {
1439 SPIRV::InstructionSet::InstructionSet Set = Ex.first;
1440 uint32_t Opcode = Ex.second;
1441 if (!STI.canUseExtInstSet(Set))
1442 continue;
1443
1444 MachineIRBuilder MIRBuilder(I);
1445 SPIRVTypeInst PointeeTy = GR.getSPIRVTypeForVReg(I.getOperand(1).getReg());
1446 const SPIRVTypeInst PointerType = GR.getOrCreateSPIRVPointerType(
1447 PointeeTy, MIRBuilder, SPIRV::StorageClass::Function);
1448 Register PointerVReg =
1449 createVirtualRegister(PointerType, &GR, MRI, MRI->getMF());
1450
1451 auto It = getOpVariableMBBIt(I);
1452 BuildMI(*It->getParent(), It, It->getDebugLoc(), TII.get(SPIRV::OpVariable))
1453 .addDef(PointerVReg)
1454 .addUse(GR.getSPIRVTypeID(PointerType))
1455 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
1456 .constrainAllUses(TII, TRI, RBI);
1457
1458 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1459 .addDef(ResVReg)
1460 .addUse(GR.getSPIRVTypeID(ResType))
1461 .addImm(static_cast<uint32_t>(Ex.first))
1462 .addImm(Opcode)
1463 .add(I.getOperand(2))
1464 .addUse(PointerVReg)
1465 .constrainAllUses(TII, TRI, RBI);
1466
1467 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
1468 .addDef(I.getOperand(1).getReg())
1469 .addUse(GR.getSPIRVTypeID(PointeeTy))
1470 .addUse(PointerVReg)
1471 .constrainAllUses(TII, TRI, RBI);
1472 return true;
1473 }
1474 return false;
1475}
1476
1477bool SPIRVInstructionSelector::selectSincos(Register ResVReg,
1478 SPIRVTypeInst ResType,
1479 MachineInstr &I) const {
1480 Register CosResVReg = I.getOperand(1).getReg();
1481 unsigned SrcIdx = I.getNumExplicitDefs();
1482 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
1483
1484 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
1485 // OpenCL.std sincos(x, cosval*) -> returns sin(x), writes cos(x) to ptr.
1486 MachineIRBuilder MIRBuilder(I);
1487 const SPIRVTypeInst PointerType = GR.getOrCreateSPIRVPointerType(
1488 ResType, MIRBuilder, SPIRV::StorageClass::Function);
1489 Register PointerVReg =
1490 createVirtualRegister(PointerType, &GR, MRI, MRI->getMF());
1491
1492 auto It = getOpVariableMBBIt(I);
1493 BuildMI(*It->getParent(), It, It->getDebugLoc(), TII.get(SPIRV::OpVariable))
1494 .addDef(PointerVReg)
1495 .addUse(GR.getSPIRVTypeID(PointerType))
1496 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
1497 .constrainAllUses(TII, TRI, RBI);
1498 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1499 .addDef(ResVReg)
1500 .addUse(ResTypeReg)
1501 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
1502 .addImm(CL::sincos)
1503 .add(I.getOperand(SrcIdx))
1504 .addUse(PointerVReg)
1505 .constrainAllUses(TII, TRI, RBI);
1506 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
1507 .addDef(CosResVReg)
1508 .addUse(ResTypeReg)
1509 .addUse(PointerVReg)
1510 .constrainAllUses(TII, TRI, RBI);
1511 return true;
1512 } else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
1513 // GLSL.std.450 has no combined sincos; emit separate Sin and Cos.
1514 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1515 .addDef(ResVReg)
1516 .addUse(ResTypeReg)
1517 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1518 .addImm(GL::Sin)
1519 .add(I.getOperand(SrcIdx))
1520 .constrainAllUses(TII, TRI, RBI);
1521 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1522 .addDef(CosResVReg)
1523 .addUse(ResTypeReg)
1524 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1525 .addImm(GL::Cos)
1526 .add(I.getOperand(SrcIdx))
1527 .constrainAllUses(TII, TRI, RBI);
1528 return true;
1529 }
1530 return false;
1531}
1532
1533bool SPIRVInstructionSelector::selectOpWithSrcs(Register ResVReg,
1534 SPIRVTypeInst ResType,
1535 MachineInstr &I,
1536 std::vector<Register> Srcs,
1537 unsigned Opcode) const {
1538 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
1539 .addDef(ResVReg)
1540 .addUse(GR.getSPIRVTypeID(ResType));
1541 for (Register SReg : Srcs) {
1542 MIB.addUse(SReg);
1543 }
1544 MIB.constrainAllUses(TII, TRI, RBI);
1545 return true;
1546}
1547
1548bool SPIRVInstructionSelector::selectUnOp(Register ResVReg,
1549 SPIRVTypeInst ResType,
1550 MachineInstr &I,
1551 unsigned Opcode) const {
1552 if (STI.isPhysicalSPIRV() && I.getOperand(1).isReg()) {
1553 Register SrcReg = I.getOperand(1).getReg();
1554 bool IsGV = false;
1556 MRI->def_instr_begin(SrcReg);
1557 DefIt != MRI->def_instr_end(); DefIt = std::next(DefIt)) {
1558 unsigned DefOpCode = DefIt->getOpcode();
1559 if (DefOpCode == SPIRV::ASSIGN_TYPE || DefOpCode == TargetOpcode::COPY) {
1560 // We need special handling to look through the type assignment or the
1561 // COPY pseudo-op and see if this is a constant or a global.
1562 if (auto *VRD = getVRegDef(*MRI, DefIt->getOperand(1).getReg()))
1563 DefOpCode = VRD->getOpcode();
1564 }
1565 if (DefOpCode == TargetOpcode::G_GLOBAL_VALUE ||
1566 DefOpCode == TargetOpcode::G_CONSTANT ||
1567 DefOpCode == SPIRV::OpVariable || DefOpCode == SPIRV::OpConstantI) {
1568 IsGV = true;
1569 break;
1570 }
1571 }
1572 if (IsGV) {
1573 uint32_t SpecOpcode = 0;
1574 switch (Opcode) {
1575 case SPIRV::OpConvertPtrToU:
1576 SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertPtrToU);
1577 break;
1578 case SPIRV::OpConvertUToPtr:
1579 SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertUToPtr);
1580 break;
1581 }
1582 if (SpecOpcode) {
1583 BuildMI(*I.getParent(), I, I.getDebugLoc(),
1584 TII.get(SPIRV::OpSpecConstantOp))
1585 .addDef(ResVReg)
1586 .addUse(GR.getSPIRVTypeID(ResType))
1587 .addImm(SpecOpcode)
1588 .addUse(SrcReg)
1589 .constrainAllUses(TII, TRI, RBI);
1590 return true;
1591 }
1592 }
1593 }
1594 return selectOpWithSrcs(ResVReg, ResType, I, {I.getOperand(1).getReg()},
1595 Opcode);
1596}
1597
1598bool SPIRVInstructionSelector::selectBitcast(Register ResVReg,
1599 SPIRVTypeInst ResType,
1600 MachineInstr &I) const {
1601 Register OpReg = I.getOperand(1).getReg();
1602 SPIRVTypeInst OpType =
1603 OpReg.isValid() ? GR.getSPIRVTypeForVReg(OpReg) : nullptr;
1604 if (!GR.isBitcastCompatible(ResType, OpType))
1605 report_fatal_error("incompatible result and operand types in a bitcast");
1606 return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast);
1607}
1608
1611 MachineIRBuilder &MIRBuilder,
1612 SPIRVGlobalRegistry &GR) {
1613 const SPIRVSubtarget *ST =
1614 static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget());
1615 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
1616 if (MemOp->isVolatile())
1617 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
1618 if (MemOp->isNonTemporal())
1619 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
1620 // Aligned memory operand requires the Kernel capability.
1621 if (!ST->isShader() && MemOp->getAlign().value())
1622 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned);
1623
1624 [[maybe_unused]] MachineInstr *AliasList = nullptr;
1625 [[maybe_unused]] MachineInstr *NoAliasList = nullptr;
1626 if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing)) {
1627 if (auto *MD = MemOp->getAAInfo().Scope) {
1628 AliasList = GR.getOrAddMemAliasingINTELInst(MIRBuilder, MD);
1629 if (AliasList)
1630 SpvMemOp |=
1631 static_cast<uint32_t>(SPIRV::MemoryOperand::AliasScopeINTELMask);
1632 }
1633 if (auto *MD = MemOp->getAAInfo().NoAlias) {
1634 NoAliasList = GR.getOrAddMemAliasingINTELInst(MIRBuilder, MD);
1635 if (NoAliasList)
1636 SpvMemOp |=
1637 static_cast<uint32_t>(SPIRV::MemoryOperand::NoAliasINTELMask);
1638 }
1639 }
1640
1641 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) {
1642 MIB.addImm(SpvMemOp);
1643 if (SpvMemOp & static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned))
1644 MIB.addImm(MemOp->getAlign().value());
1645 if (AliasList)
1646 MIB.addUse(AliasList->getOperand(0).getReg());
1647 if (NoAliasList)
1648 MIB.addUse(NoAliasList->getOperand(0).getReg());
1649 }
1650}
1651
1653 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
1655 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
1657 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
1658
1659 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None))
1660 MIB.addImm(SpvMemOp);
1661}
1662
1663bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
1664 SPIRVTypeInst ResType,
1665 MachineInstr &I) const {
1666 unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0;
1667 Register Ptr = I.getOperand(1 + OpOffset).getReg();
1668
1669 auto *PtrDef = getVRegDef(*MRI, Ptr);
1670 auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef);
1671 if (IntPtrDef &&
1672 IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1673 Register HandleReg = IntPtrDef->getOperand(2).getReg();
1674 SPIRVTypeInst HandleType = GR.getSPIRVTypeForVReg(HandleReg);
1675 if (HandleType->getOpcode() == SPIRV::OpTypeImage) {
1676 Register NewHandleReg =
1677 MRI->createVirtualRegister(MRI->getRegClass(HandleReg));
1678 auto *HandleDef = cast<GIntrinsic>(getVRegDef(*MRI, HandleReg));
1679 if (!loadHandleBeforePosition(NewHandleReg, HandleType, *HandleDef, I)) {
1680 return false;
1681 }
1682
1683 Register IdxReg = IntPtrDef->getOperand(3).getReg();
1684 return generateImageReadOrFetch(ResVReg, ResType, NewHandleReg, IdxReg,
1685 I.getDebugLoc(), I);
1686 }
1687 }
1688
1689 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
1690 .addDef(ResVReg)
1691 .addUse(GR.getSPIRVTypeID(ResType))
1692 .addUse(Ptr);
1693 if (!I.getNumMemOperands()) {
1694 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
1695 I.getOpcode() ==
1696 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
1697 addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
1698 } else {
1699 MachineIRBuilder MIRBuilder(I);
1700 addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR);
1701 }
1702 MIB.constrainAllUses(TII, TRI, RBI);
1703 return true;
1704}
1705
1706bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
1707 unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0;
1708 Register StoreVal = I.getOperand(0 + OpOffset).getReg();
1709 Register Ptr = I.getOperand(1 + OpOffset).getReg();
1710
1711 auto *PtrDef = getVRegDef(*MRI, Ptr);
1712 auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef);
1713 if (IntPtrDef &&
1714 IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1715 Register HandleReg = IntPtrDef->getOperand(2).getReg();
1716 Register NewHandleReg =
1717 MRI->createVirtualRegister(MRI->getRegClass(HandleReg));
1718 auto *HandleDef = cast<GIntrinsic>(getVRegDef(*MRI, HandleReg));
1719 SPIRVTypeInst HandleType = GR.getSPIRVTypeForVReg(HandleReg);
1720 if (!loadHandleBeforePosition(NewHandleReg, HandleType, *HandleDef, I)) {
1721 return false;
1722 }
1723
1724 Register IdxReg = IntPtrDef->getOperand(3).getReg();
1725 if (HandleType->getOpcode() == SPIRV::OpTypeImage) {
1726 auto BMI = BuildMI(*I.getParent(), I, I.getDebugLoc(),
1727 TII.get(SPIRV::OpImageWrite))
1728 .addUse(NewHandleReg)
1729 .addUse(IdxReg)
1730 .addUse(StoreVal);
1731
1732 const llvm::Type *LLVMHandleType = GR.getTypeForSPIRVType(HandleType);
1733 if (sampledTypeIsSignedInteger(LLVMHandleType))
1734 BMI.addImm(0x1000); // SignExtend
1735
1736 BMI.constrainAllUses(TII, TRI, RBI);
1737 return true;
1738 }
1739 }
1740
1741 MachineBasicBlock &BB = *I.getParent();
1742 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpStore))
1743 .addUse(Ptr)
1744 .addUse(StoreVal);
1745 if (!I.getNumMemOperands()) {
1746 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
1747 I.getOpcode() ==
1748 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
1749 addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
1750 } else {
1751 MachineIRBuilder MIRBuilder(I);
1752 addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR);
1753 }
1754 MIB.constrainAllUses(TII, TRI, RBI);
1755 return true;
1756}
1757
1758bool SPIRVInstructionSelector::selectMaskedGather(Register ResVReg,
1759 SPIRVTypeInst ResType,
1760 MachineInstr &I) const {
1761 assert(I.getNumExplicitDefs() == 1 && "Expected single def for gather");
1762 // Operand indices:
1763 // 0: result (def)
1764 // 1: intrinsic ID
1765 // 2: vector of pointers
1766 // 3: alignment (i32 immediate)
1767 // 4: mask (vector of i1)
1768 // 5: passthru/fill value
1769 const Register PtrsReg = I.getOperand(2).getReg();
1770 const uint32_t Alignment = I.getOperand(3).getImm();
1771 const Register MaskReg = I.getOperand(4).getReg();
1772 const Register PassthruReg = I.getOperand(5).getReg();
1773 const Register AlignmentReg = buildI32Constant(Alignment, I);
1774
1775 MachineBasicBlock &BB = *I.getParent();
1776 auto MIB =
1777 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMaskedGatherINTEL))
1778 .addDef(ResVReg)
1779 .addUse(GR.getSPIRVTypeID(ResType))
1780 .addUse(PtrsReg)
1781 .addUse(AlignmentReg)
1782 .addUse(MaskReg)
1783 .addUse(PassthruReg);
1784 MIB.constrainAllUses(TII, TRI, RBI);
1785 return true;
1786}
1787
1788bool SPIRVInstructionSelector::selectMaskedScatter(MachineInstr &I) const {
1789 assert(I.getNumExplicitDefs() == 0 && "Expected no defs for scatter");
1790 // Operand indices (no explicit defs):
1791 // 0: intrinsic ID
1792 // 1: value vector
1793 // 2: vector of pointers
1794 // 3: alignment (i32 immediate)
1795 // 4: mask (vector of i1)
1796 const Register ValuesReg = I.getOperand(1).getReg();
1797 const Register PtrsReg = I.getOperand(2).getReg();
1798 const uint32_t Alignment = I.getOperand(3).getImm();
1799 const Register MaskReg = I.getOperand(4).getReg();
1800 const Register AlignmentReg = buildI32Constant(Alignment, I);
1801 MachineBasicBlock &BB = *I.getParent();
1802
1803 auto MIB =
1804 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMaskedScatterINTEL))
1805 .addUse(PtrsReg)
1806 .addUse(AlignmentReg)
1807 .addUse(MaskReg)
1808 .addUse(ValuesReg);
1809 MIB.constrainAllUses(TII, TRI, RBI);
1810 return true;
1811}
1812
1813bool SPIRVInstructionSelector::diagnoseUnsupported(const MachineInstr &I,
1814 const Twine &Msg) const {
1815 const Function &F = I.getMF()->getFunction();
1816 F.getContext().diagnose(
1817 DiagnosticInfoUnsupported(F, Msg, I.getDebugLoc(), DS_Error));
1818 return false;
1819}
1820
1821bool SPIRVInstructionSelector::selectStackSave(Register ResVReg,
1822 SPIRVTypeInst ResType,
1823 MachineInstr &I) const {
1824 if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array))
1826 "llvm.stacksave intrinsic: this instruction requires the following "
1827 "SPIR-V extension: SPV_INTEL_variable_length_array",
1828 false);
1829 MachineBasicBlock &BB = *I.getParent();
1830 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSaveMemoryINTEL))
1831 .addDef(ResVReg)
1832 .addUse(GR.getSPIRVTypeID(ResType))
1833 .constrainAllUses(TII, TRI, RBI);
1834 return true;
1835}
1836
1837bool SPIRVInstructionSelector::selectStackRestore(MachineInstr &I) const {
1838 if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array))
1840 "llvm.stackrestore intrinsic: this instruction requires the following "
1841 "SPIR-V extension: SPV_INTEL_variable_length_array",
1842 false);
1843 if (!I.getOperand(0).isReg())
1844 return false;
1845 MachineBasicBlock &BB = *I.getParent();
1846 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpRestoreMemoryINTEL))
1847 .addUse(I.getOperand(0).getReg())
1848 .constrainAllUses(TII, TRI, RBI);
1849 return true;
1850}
1851
1853SPIRVInstructionSelector::getOrCreateMemSetGlobal(MachineInstr &I) const {
1854 MachineIRBuilder MIRBuilder(I);
1855 assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
1856
1857 // TODO: check if we have such GV, add init, use buildGlobalVariable.
1858 unsigned Num = getIConstVal(I.getOperand(2).getReg(), MRI);
1859 Function &CurFunction = GR.CurMF->getFunction();
1860 Type *LLVMArrTy =
1861 ArrayType::get(IntegerType::get(CurFunction.getContext(), 8), Num);
1862 GlobalVariable *GV = new GlobalVariable(*CurFunction.getParent(), LLVMArrTy,
1864 Constant::getNullValue(LLVMArrTy));
1865
1866 Type *ValTy = Type::getInt8Ty(I.getMF()->getFunction().getContext());
1867 Type *ArrTy = ArrayType::get(ValTy, Num);
1868 SPIRVTypeInst VarTy = GR.getOrCreateSPIRVPointerType(
1869 ArrTy, MIRBuilder, SPIRV::StorageClass::UniformConstant);
1870
1871 SPIRVTypeInst SpvArrTy = GR.getOrCreateSPIRVType(
1872 ArrTy, MIRBuilder, SPIRV::AccessQualifier::None, false);
1873
1874 unsigned Val = getIConstVal(I.getOperand(1).getReg(), MRI);
1875 Register Const = GR.getOrCreateConstIntArray(Val, Num, I, SpvArrTy, TII);
1876
1878 auto MIBVar =
1879 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
1880 .addDef(VarReg)
1881 .addUse(GR.getSPIRVTypeID(VarTy))
1882 .addImm(SPIRV::StorageClass::UniformConstant)
1883 .addUse(Const);
1884 MIBVar.constrainAllUses(TII, TRI, RBI);
1885
1886 GR.add(GV, MIBVar);
1887 GR.addGlobalObject(GV, GR.CurMF, VarReg);
1888
1889 buildOpDecorate(VarReg, I, TII, SPIRV::Decoration::Constant, {});
1890 return VarReg;
1891}
1892
1893bool SPIRVInstructionSelector::selectCopyMemory(MachineInstr &I,
1894 Register SrcReg) const {
1895 MachineBasicBlock &BB = *I.getParent();
1896 Register DstReg = I.getOperand(0).getReg();
1897 SPIRVTypeInst DstTy = GR.getSPIRVTypeForVReg(DstReg);
1898 SPIRVTypeInst SrcTy = GR.getSPIRVTypeForVReg(SrcReg);
1899 if (GR.getPointeeType(DstTy) != GR.getPointeeType(SrcTy))
1900 report_fatal_error("OpCopyMemory requires operands to have the same type");
1901 uint64_t CopySize = getIConstVal(I.getOperand(2).getReg(), MRI);
1902 SPIRVTypeInst PointeeTy = GR.getPointeeType(DstTy);
1903 const Type *LLVMPointeeTy = GR.getTypeForSPIRVType(PointeeTy);
1904 if (!LLVMPointeeTy)
1906 "Unable to determine pointee type size for OpCopyMemory");
1907 const DataLayout &DL = I.getMF()->getFunction().getDataLayout();
1908 if (CopySize != DL.getTypeStoreSize(const_cast<Type *>(LLVMPointeeTy)))
1910 "OpCopyMemory requires the size to match the pointee type size");
1911 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemory))
1912 .addUse(DstReg)
1913 .addUse(SrcReg);
1914 if (I.getNumMemOperands()) {
1915 MachineIRBuilder MIRBuilder(I);
1916 addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR);
1917 }
1918 MIB.constrainAllUses(TII, TRI, RBI);
1919 return true;
1920}
1921
1922bool SPIRVInstructionSelector::selectCopyMemorySized(MachineInstr &I,
1923 Register SrcReg) const {
1924 MachineBasicBlock &BB = *I.getParent();
1925 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemorySized))
1926 .addUse(I.getOperand(0).getReg())
1927 .addUse(SrcReg)
1928 .addUse(I.getOperand(2).getReg());
1929 if (I.getNumMemOperands()) {
1930 MachineIRBuilder MIRBuilder(I);
1931 addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR);
1932 }
1933 MIB.constrainAllUses(TII, TRI, RBI);
1934 return true;
1935}
1936
1937bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg,
1938 MachineInstr &I) const {
1939 Register SrcReg = I.getOperand(1).getReg();
1940 if (I.getOpcode() == TargetOpcode::G_MEMSET) {
1941 Register VarReg = getOrCreateMemSetGlobal(I);
1942 if (!VarReg.isValid())
1943 return false;
1944 Type *ValTy = Type::getInt8Ty(I.getMF()->getFunction().getContext());
1945 SPIRVTypeInst SourceTy = GR.getOrCreateSPIRVPointerType(
1946 ValTy, I, SPIRV::StorageClass::UniformConstant);
1947 SrcReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
1948 if (!selectOpWithSrcs(SrcReg, SourceTy, I, {VarReg}, SPIRV::OpBitcast))
1949 return false;
1950 }
1951 if (STI.isLogicalSPIRV()) {
1952 if (!selectCopyMemory(I, SrcReg))
1953 return false;
1954 } else {
1955 if (!selectCopyMemorySized(I, SrcReg))
1956 return false;
1957 }
1958 if (ResVReg.isValid() && ResVReg != I.getOperand(0).getReg())
1959 if (!BuildCOPY(ResVReg, I.getOperand(0).getReg(), I))
1960 return false;
1961 return true;
1962}
1963
1964bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg,
1965 SPIRVTypeInst ResType,
1966 MachineInstr &I,
1967 unsigned NewOpcode,
1968 unsigned NegateOpcode) const {
1969 assert(I.hasOneMemOperand());
1970 const MachineMemOperand *MemOp = *I.memoperands_begin();
1971 uint32_t Scope = static_cast<uint32_t>(getMemScope(
1972 GR.CurMF->getFunction().getContext(), MemOp->getSyncScopeID()));
1973 Register ScopeReg = buildI32Constant(Scope, I);
1974
1975 Register Ptr = I.getOperand(1).getReg();
1976 // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll
1977 // auto ScSem =
1978 // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr));
1979 AtomicOrdering AO = MemOp->getSuccessOrdering();
1980 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
1981 Register MemSemReg = buildI32Constant(MemSem /*| ScSem*/, I);
1982
1983 Register ValueReg = I.getOperand(2).getReg();
1984 if (NegateOpcode != 0) {
1985 // Translation with negative value operand is requested
1986 Register TmpReg = createVirtualRegister(ResType, &GR, MRI, MRI->getMF());
1987 if (!selectOpWithSrcs(TmpReg, ResType, I, {ValueReg}, NegateOpcode))
1988 return false;
1989 ValueReg = TmpReg;
1990 }
1991
1992 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode))
1993 .addDef(ResVReg)
1994 .addUse(GR.getSPIRVTypeID(ResType))
1995 .addUse(Ptr)
1996 .addUse(ScopeReg)
1997 .addUse(MemSemReg)
1998 .addUse(ValueReg)
1999 .constrainAllUses(TII, TRI, RBI);
2000 return true;
2001}
2002
2003bool SPIRVInstructionSelector::selectUnmergeValues(MachineInstr &I) const {
2004 unsigned ArgI = I.getNumOperands() - 1;
2005 Register SrcReg =
2006 I.getOperand(ArgI).isReg() ? I.getOperand(ArgI).getReg() : Register(0);
2007 SPIRVTypeInst SrcType =
2008 SrcReg.isValid() ? GR.getSPIRVTypeForVReg(SrcReg) : nullptr;
2009 if (!SrcType || SrcType->getOpcode() != SPIRV::OpTypeVector)
2011 "cannot select G_UNMERGE_VALUES with a non-vector argument");
2012
2013 SPIRVTypeInst ScalarType =
2014 GR.getSPIRVTypeForVReg(SrcType->getOperand(1).getReg());
2015 MachineBasicBlock &BB = *I.getParent();
2016 unsigned CurrentIndex = 0;
2017 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
2018 Register ResVReg = I.getOperand(i).getReg();
2019 SPIRVTypeInst ResType = GR.getSPIRVTypeForVReg(ResVReg);
2020 if (!ResType) {
2021 LLT ResLLT = MRI->getType(ResVReg);
2022 assert(ResLLT.isValid());
2023 if (ResLLT.isVector()) {
2024 ResType = GR.getOrCreateSPIRVVectorType(
2025 ScalarType, ResLLT.getNumElements(), I, TII);
2026 } else {
2027 ResType = ScalarType;
2028 }
2029 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
2030 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF);
2031 }
2032
2033 if (ResType->getOpcode() == SPIRV::OpTypeVector) {
2034 Register UndefReg = GR.getOrCreateUndef(I, SrcType, TII);
2035 auto MIB =
2036 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle))
2037 .addDef(ResVReg)
2038 .addUse(GR.getSPIRVTypeID(ResType))
2039 .addUse(SrcReg)
2040 .addUse(UndefReg);
2041 unsigned NumElements = GR.getScalarOrVectorComponentCount(ResType);
2042 for (unsigned j = 0; j < NumElements; ++j) {
2043 MIB.addImm(CurrentIndex + j);
2044 }
2045 CurrentIndex += NumElements;
2046 MIB.constrainAllUses(TII, TRI, RBI);
2047 } else {
2048 auto MIB =
2049 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
2050 .addDef(ResVReg)
2051 .addUse(GR.getSPIRVTypeID(ResType))
2052 .addUse(SrcReg)
2053 .addImm(CurrentIndex);
2054 CurrentIndex++;
2055 MIB.constrainAllUses(TII, TRI, RBI);
2056 }
2057 }
2058 return true;
2059}
2060
2061bool SPIRVInstructionSelector::selectFence(MachineInstr &I) const {
2062 AtomicOrdering AO = AtomicOrdering(I.getOperand(0).getImm());
2063 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
2064 Register MemSemReg = buildI32Constant(MemSem, I);
2065 SyncScope::ID Ord = SyncScope::ID(I.getOperand(1).getImm());
2066 uint32_t Scope = static_cast<uint32_t>(
2067 getMemScope(GR.CurMF->getFunction().getContext(), Ord));
2068 Register ScopeReg = buildI32Constant(Scope, I);
2069 MachineBasicBlock &BB = *I.getParent();
2070 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMemoryBarrier))
2071 .addUse(ScopeReg)
2072 .addUse(MemSemReg)
2073 .constrainAllUses(TII, TRI, RBI);
2074 return true;
2075}
2076
2077bool SPIRVInstructionSelector::selectOverflowArith(Register ResVReg,
2078 SPIRVTypeInst ResType,
2079 MachineInstr &I,
2080 unsigned Opcode) const {
2081 Type *ResTy = nullptr;
2082 StringRef ResName;
2083 if (!GR.findValueAttrs(&I, ResTy, ResName))
2085 "Not enough info to select the arithmetic with overflow instruction");
2086 if (!ResTy || !ResTy->isStructTy())
2087 report_fatal_error("Expect struct type result for the arithmetic "
2088 "with overflow instruction");
2089 // "Result Type must be from OpTypeStruct. The struct must have two members,
2090 // and the two members must be the same type."
2091 Type *ResElemTy = cast<StructType>(ResTy)->getElementType(0);
2092 ResTy = StructType::get(ResElemTy, ResElemTy);
2093 // Build SPIR-V types and constant(s) if needed.
2094 MachineIRBuilder MIRBuilder(I);
2095 SPIRVTypeInst StructType = GR.getOrCreateSPIRVType(
2096 ResTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false);
2097 assert(I.getNumDefs() > 1 && "Not enought operands");
2098 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
2099 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
2100 if (N > 1)
2101 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, N, I, TII);
2102 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
2103 Register ZeroReg = buildZerosVal(ResType, I);
2104 // A new virtual register to store the result struct.
2105 Register StructVReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
2106 MRI->setRegClass(StructVReg, &SPIRV::IDRegClass);
2107 // Build the result name if needed.
2108 if (ResName.size() > 0)
2109 buildOpName(StructVReg, ResName, MIRBuilder);
2110 // Build the arithmetic with overflow instruction.
2111 MachineBasicBlock &BB = *I.getParent();
2112 auto MIB =
2113 BuildMI(BB, MIRBuilder.getInsertPt(), I.getDebugLoc(), TII.get(Opcode))
2114 .addDef(StructVReg)
2115 .addUse(GR.getSPIRVTypeID(StructType));
2116 for (unsigned i = I.getNumDefs(); i < I.getNumOperands(); ++i)
2117 MIB.addUse(I.getOperand(i).getReg());
2118 MIB.constrainAllUses(TII, TRI, RBI);
2119 // Build instructions to extract fields of the instruction's result.
2120 // A new virtual register to store the higher part of the result struct.
2121 Register HigherVReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
2122 MRI->setRegClass(HigherVReg, &SPIRV::iIDRegClass);
2123 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
2124 auto MIB =
2125 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
2126 .addDef(i == 1 ? HigherVReg : I.getOperand(i).getReg())
2127 .addUse(GR.getSPIRVTypeID(ResType))
2128 .addUse(StructVReg)
2129 .addImm(i);
2130 MIB.constrainAllUses(TII, TRI, RBI);
2131 }
2132 // Build boolean value from the higher part.
2133 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
2134 .addDef(I.getOperand(1).getReg())
2135 .addUse(BoolTypeReg)
2136 .addUse(HigherVReg)
2137 .addUse(ZeroReg)
2138 .constrainAllUses(TII, TRI, RBI);
2139 return true;
2140}
2141
2142bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg,
2143 SPIRVTypeInst ResType,
2144 MachineInstr &I) const {
2145 Register ScopeReg;
2146 Register MemSemEqReg;
2147 Register MemSemNeqReg;
2148 Register Ptr = I.getOperand(2).getReg();
2149 if (!isa<GIntrinsic>(I)) {
2150 assert(I.hasOneMemOperand());
2151 const MachineMemOperand *MemOp = *I.memoperands_begin();
2152 unsigned Scope = static_cast<uint32_t>(getMemScope(
2153 GR.CurMF->getFunction().getContext(), MemOp->getSyncScopeID()));
2154 ScopeReg = buildI32Constant(Scope, I);
2155
2156 unsigned ScSem = static_cast<uint32_t>(
2158 AtomicOrdering AO = MemOp->getSuccessOrdering();
2159 unsigned MemSemEq = static_cast<uint32_t>(getMemSemantics(AO)) | ScSem;
2160 Register MemSemEqReg = buildI32Constant(MemSemEq, I);
2161 AtomicOrdering FO = MemOp->getFailureOrdering();
2162 unsigned MemSemNeq = static_cast<uint32_t>(getMemSemantics(FO)) | ScSem;
2163 if (MemSemEq == MemSemNeq)
2164 MemSemNeqReg = MemSemEqReg;
2165 else {
2166 MemSemNeqReg = buildI32Constant(MemSemEq, I);
2167 }
2168 } else {
2169 ScopeReg = I.getOperand(5).getReg();
2170 MemSemEqReg = I.getOperand(6).getReg();
2171 MemSemNeqReg = I.getOperand(7).getReg();
2172 }
2173
2174 Register Cmp = I.getOperand(3).getReg();
2175 Register Val = I.getOperand(4).getReg();
2176 SPIRVTypeInst SpvValTy = GR.getSPIRVTypeForVReg(Val);
2177 Register ACmpRes = createVirtualRegister(SpvValTy, &GR, MRI, *I.getMF());
2178 const DebugLoc &DL = I.getDebugLoc();
2179 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpAtomicCompareExchange))
2180 .addDef(ACmpRes)
2181 .addUse(GR.getSPIRVTypeID(SpvValTy))
2182 .addUse(Ptr)
2183 .addUse(ScopeReg)
2184 .addUse(MemSemEqReg)
2185 .addUse(MemSemNeqReg)
2186 .addUse(Val)
2187 .addUse(Cmp)
2188 .constrainAllUses(TII, TRI, RBI);
2189 SPIRVTypeInst BoolTy = GR.getOrCreateSPIRVBoolType(I, TII);
2190 Register CmpSuccReg = createVirtualRegister(BoolTy, &GR, MRI, *I.getMF());
2191 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpIEqual))
2192 .addDef(CmpSuccReg)
2193 .addUse(GR.getSPIRVTypeID(BoolTy))
2194 .addUse(ACmpRes)
2195 .addUse(Cmp)
2196 .constrainAllUses(TII, TRI, RBI);
2197 Register TmpReg = createVirtualRegister(ResType, &GR, MRI, *I.getMF());
2198 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
2199 .addDef(TmpReg)
2200 .addUse(GR.getSPIRVTypeID(ResType))
2201 .addUse(ACmpRes)
2202 .addUse(GR.getOrCreateUndef(I, ResType, TII))
2203 .addImm(0)
2204 .constrainAllUses(TII, TRI, RBI);
2205 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
2206 .addDef(ResVReg)
2207 .addUse(GR.getSPIRVTypeID(ResType))
2208 .addUse(CmpSuccReg)
2209 .addUse(TmpReg)
2210 .addImm(1)
2211 .constrainAllUses(TII, TRI, RBI);
2212 return true;
2213}
2214
2215static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) {
2216 switch (SC) {
2217 case SPIRV::StorageClass::DeviceOnlyINTEL:
2218 case SPIRV::StorageClass::HostOnlyINTEL:
2219 return true;
2220 default:
2221 return false;
2222 }
2223}
2224
2225// Returns true ResVReg is referred only from global vars and OpName's.
2226static bool isASCastInGVar(MachineRegisterInfo *MRI, Register ResVReg) {
2227 bool IsGRef = false;
2228 bool IsAllowedRefs =
2229 llvm::all_of(MRI->use_instructions(ResVReg), [&IsGRef](auto const &It) {
2230 unsigned Opcode = It.getOpcode();
2231 if (Opcode == SPIRV::OpConstantComposite ||
2232 Opcode == SPIRV::OpVariable ||
2233 isSpvIntrinsic(It, Intrinsic::spv_init_global))
2234 return IsGRef = true;
2235 return Opcode == SPIRV::OpName;
2236 });
2237 return IsAllowedRefs && IsGRef;
2238}
2239
2240Register SPIRVInstructionSelector::getUcharPtrTypeReg(
2241 MachineInstr &I, SPIRV::StorageClass::StorageClass SC) const {
2243 Type::getInt8Ty(I.getMF()->getFunction().getContext()), I, SC));
2244}
2245
2246MachineInstrBuilder
2247SPIRVInstructionSelector::buildSpecConstantOp(MachineInstr &I, Register Dest,
2248 Register Src, Register DestType,
2249 uint32_t Opcode) const {
2250 return BuildMI(*I.getParent(), I, I.getDebugLoc(),
2251 TII.get(SPIRV::OpSpecConstantOp))
2252 .addDef(Dest)
2253 .addUse(DestType)
2254 .addImm(Opcode)
2255 .addUse(Src);
2256}
2257
2258MachineInstrBuilder
2259SPIRVInstructionSelector::buildConstGenericPtr(MachineInstr &I, Register SrcPtr,
2260 SPIRVTypeInst SrcPtrTy) const {
2261 SPIRVTypeInst GenericPtrTy =
2262 GR.changePointerStorageClass(SrcPtrTy, SPIRV::StorageClass::Generic, I);
2263 Register Tmp = MRI->createVirtualRegister(&SPIRV::pIDRegClass);
2265 SPIRV::StorageClass::Generic),
2266 GR.getPointerSize()));
2267 MachineFunction *MF = I.getParent()->getParent();
2268 GR.assignSPIRVTypeToVReg(GenericPtrTy, Tmp, *MF);
2269 MachineInstrBuilder MIB = buildSpecConstantOp(
2270 I, Tmp, SrcPtr, GR.getSPIRVTypeID(GenericPtrTy),
2271 static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric));
2272 GR.add(MIB.getInstr(), MIB);
2273 return MIB;
2274}
2275
2276// In SPIR-V address space casting can only happen to and from the Generic
2277// storage class. We can also only cast Workgroup, CrossWorkgroup, or Function
2278// pointers to and from Generic pointers. As such, we can convert e.g. from
2279// Workgroup to Function by going via a Generic pointer as an intermediary. All
2280// other combinations can only be done by a bitcast, and are probably not safe.
2281bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
2282 SPIRVTypeInst ResType,
2283 MachineInstr &I) const {
2284 MachineBasicBlock &BB = *I.getParent();
2285 const DebugLoc &DL = I.getDebugLoc();
2286
2287 Register SrcPtr = I.getOperand(1).getReg();
2288 SPIRVTypeInst SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
2289
2290 // don't generate a cast for a null that may be represented by OpTypeInt
2291 if (SrcPtrTy->getOpcode() != SPIRV::OpTypePointer ||
2292 ResType->getOpcode() != SPIRV::OpTypePointer)
2293 return BuildCOPY(ResVReg, SrcPtr, I);
2294
2295 SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtrTy);
2296 SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResType);
2297
2298 if (isASCastInGVar(MRI, ResVReg)) {
2299 // AddrSpaceCast uses within OpVariable and OpConstantComposite instructions
2300 // are expressed by OpSpecConstantOp with an Opcode.
2301 // TODO: maybe insert a check whether the Kernel capability was declared and
2302 // so PtrCastToGeneric/GenericCastToPtr are available.
2303 unsigned SpecOpcode =
2304 DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC)
2305 ? static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric)
2306 : (SrcSC == SPIRV::StorageClass::Generic &&
2308 ? static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr)
2309 : 0);
2310 // TODO: OpConstantComposite expects i8*, so we are forced to forget a
2311 // correct value of ResType and use general i8* instead. Maybe this should
2312 // be addressed in the emit-intrinsic step to infer a correct
2313 // OpConstantComposite type.
2314 if (SpecOpcode) {
2315 buildSpecConstantOp(I, ResVReg, SrcPtr, getUcharPtrTypeReg(I, DstSC),
2316 SpecOpcode)
2317 .constrainAllUses(TII, TRI, RBI);
2318 } else if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
2319 MachineInstrBuilder MIB = buildConstGenericPtr(I, SrcPtr, SrcPtrTy);
2320 MIB.constrainAllUses(TII, TRI, RBI);
2321 buildSpecConstantOp(
2322 I, ResVReg, MIB->getOperand(0).getReg(), getUcharPtrTypeReg(I, DstSC),
2323 static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr))
2324 .constrainAllUses(TII, TRI, RBI);
2325 }
2326 return true;
2327 }
2328
2329 // don't generate a cast between identical storage classes
2330 if (SrcSC == DstSC)
2331 return BuildCOPY(ResVReg, SrcPtr, I);
2332
2333 if ((SrcSC == SPIRV::StorageClass::Function &&
2334 DstSC == SPIRV::StorageClass::Private) ||
2335 (DstSC == SPIRV::StorageClass::Function &&
2336 SrcSC == SPIRV::StorageClass::Private))
2337 return BuildCOPY(ResVReg, SrcPtr, I);
2338
2339 // Casting from an eligible pointer to Generic.
2340 if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC))
2341 return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
2342 // Casting from Generic to an eligible pointer.
2343 if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC))
2344 return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
2345 // Casting between 2 eligible pointers using Generic as an intermediary.
2346 if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
2347 SPIRVTypeInst GenericPtrTy =
2348 GR.changePointerStorageClass(SrcPtrTy, SPIRV::StorageClass::Generic, I);
2349 Register Tmp = createVirtualRegister(GenericPtrTy, &GR, MRI, MRI->getMF());
2350 BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric))
2351 .addDef(Tmp)
2352 .addUse(GR.getSPIRVTypeID(GenericPtrTy))
2353 .addUse(SrcPtr)
2354 .constrainAllUses(TII, TRI, RBI);
2355 BuildMI(BB, I, DL, TII.get(SPIRV::OpGenericCastToPtr))
2356 .addDef(ResVReg)
2357 .addUse(GR.getSPIRVTypeID(ResType))
2358 .addUse(Tmp)
2359 .constrainAllUses(TII, TRI, RBI);
2360 return true;
2361 }
2362
2363 // Check if instructions from the SPV_INTEL_usm_storage_classes extension may
2364 // be applied
2365 if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::CrossWorkgroup)
2366 return selectUnOp(ResVReg, ResType, I,
2367 SPIRV::OpPtrCastToCrossWorkgroupINTEL);
2368 if (SrcSC == SPIRV::StorageClass::CrossWorkgroup && isUSMStorageClass(DstSC))
2369 return selectUnOp(ResVReg, ResType, I,
2370 SPIRV::OpCrossWorkgroupCastToPtrINTEL);
2371 if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::Generic)
2372 return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
2373 if (SrcSC == SPIRV::StorageClass::Generic && isUSMStorageClass(DstSC))
2374 return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
2375
2376 // Bitcast for pointers requires that the address spaces must match
2377 return false;
2378}
2379
2380static unsigned getFCmpOpcode(unsigned PredNum) {
2381 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
2382 switch (Pred) {
2383 case CmpInst::FCMP_OEQ:
2384 return SPIRV::OpFOrdEqual;
2385 case CmpInst::FCMP_OGE:
2386 return SPIRV::OpFOrdGreaterThanEqual;
2387 case CmpInst::FCMP_OGT:
2388 return SPIRV::OpFOrdGreaterThan;
2389 case CmpInst::FCMP_OLE:
2390 return SPIRV::OpFOrdLessThanEqual;
2391 case CmpInst::FCMP_OLT:
2392 return SPIRV::OpFOrdLessThan;
2393 case CmpInst::FCMP_ONE:
2394 return SPIRV::OpFOrdNotEqual;
2395 case CmpInst::FCMP_ORD:
2396 return SPIRV::OpOrdered;
2397 case CmpInst::FCMP_UEQ:
2398 return SPIRV::OpFUnordEqual;
2399 case CmpInst::FCMP_UGE:
2400 return SPIRV::OpFUnordGreaterThanEqual;
2401 case CmpInst::FCMP_UGT:
2402 return SPIRV::OpFUnordGreaterThan;
2403 case CmpInst::FCMP_ULE:
2404 return SPIRV::OpFUnordLessThanEqual;
2405 case CmpInst::FCMP_ULT:
2406 return SPIRV::OpFUnordLessThan;
2407 case CmpInst::FCMP_UNE:
2408 return SPIRV::OpFUnordNotEqual;
2409 case CmpInst::FCMP_UNO:
2410 return SPIRV::OpUnordered;
2411 default:
2412 llvm_unreachable("Unknown predicate type for FCmp");
2413 }
2414}
2415
2416static unsigned getICmpOpcode(unsigned PredNum) {
2417 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
2418 switch (Pred) {
2419 case CmpInst::ICMP_EQ:
2420 return SPIRV::OpIEqual;
2421 case CmpInst::ICMP_NE:
2422 return SPIRV::OpINotEqual;
2423 case CmpInst::ICMP_SGE:
2424 return SPIRV::OpSGreaterThanEqual;
2425 case CmpInst::ICMP_SGT:
2426 return SPIRV::OpSGreaterThan;
2427 case CmpInst::ICMP_SLE:
2428 return SPIRV::OpSLessThanEqual;
2429 case CmpInst::ICMP_SLT:
2430 return SPIRV::OpSLessThan;
2431 case CmpInst::ICMP_UGE:
2432 return SPIRV::OpUGreaterThanEqual;
2433 case CmpInst::ICMP_UGT:
2434 return SPIRV::OpUGreaterThan;
2435 case CmpInst::ICMP_ULE:
2436 return SPIRV::OpULessThanEqual;
2437 case CmpInst::ICMP_ULT:
2438 return SPIRV::OpULessThan;
2439 default:
2440 llvm_unreachable("Unknown predicate type for ICmp");
2441 }
2442}
2443
2444static unsigned getPtrCmpOpcode(unsigned Pred) {
2445 switch (static_cast<CmpInst::Predicate>(Pred)) {
2446 case CmpInst::ICMP_EQ:
2447 return SPIRV::OpPtrEqual;
2448 case CmpInst::ICMP_NE:
2449 return SPIRV::OpPtrNotEqual;
2450 default:
2451 llvm_unreachable("Unknown predicate type for pointer comparison");
2452 }
2453}
2454
2455// Return the logical operation, or abort if none exists.
2456static unsigned getBoolCmpOpcode(unsigned PredNum) {
2457 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
2458 switch (Pred) {
2459 case CmpInst::ICMP_EQ:
2460 return SPIRV::OpLogicalEqual;
2461 case CmpInst::ICMP_NE:
2462 return SPIRV::OpLogicalNotEqual;
2463 default:
2464 llvm_unreachable("Unknown predicate type for Bool comparison");
2465 }
2466}
2467
2468static APFloat getZeroFP(const Type *LLVMFloatTy) {
2469 if (!LLVMFloatTy)
2471 switch (LLVMFloatTy->getScalarType()->getTypeID()) {
2472 case Type::HalfTyID:
2474 default:
2475 case Type::FloatTyID:
2477 case Type::DoubleTyID:
2479 }
2480}
2481
2482static APFloat getOneFP(const Type *LLVMFloatTy) {
2483 if (!LLVMFloatTy)
2485 switch (LLVMFloatTy->getScalarType()->getTypeID()) {
2486 case Type::HalfTyID:
2488 default:
2489 case Type::FloatTyID:
2491 case Type::DoubleTyID:
2493 }
2494}
2495
2496bool SPIRVInstructionSelector::selectAnyOrAll(Register ResVReg,
2497 SPIRVTypeInst ResType,
2498 MachineInstr &I,
2499 unsigned OpAnyOrAll) const {
2500 assert(I.getNumOperands() == 3);
2501 assert(I.getOperand(2).isReg());
2502 MachineBasicBlock &BB = *I.getParent();
2503 Register InputRegister = I.getOperand(2).getReg();
2504 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
2505
2506 assert(InputType && "VReg has no type assigned");
2507
2508 bool IsBoolTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeBool);
2509 bool IsVectorTy = InputType->getOpcode() == SPIRV::OpTypeVector;
2510 if (IsBoolTy && !IsVectorTy) {
2511 assert(ResVReg == I.getOperand(0).getReg());
2512 return BuildCOPY(ResVReg, InputRegister, I);
2513 }
2514
2515 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
2516 unsigned SpirvNotEqualId =
2517 IsFloatTy ? SPIRV::OpFOrdNotEqual : SPIRV::OpINotEqual;
2518 SPIRVTypeInst SpvBoolScalarTy = GR.getOrCreateSPIRVBoolType(I, TII);
2519 SPIRVTypeInst SpvBoolTy = SpvBoolScalarTy;
2520 Register NotEqualReg = ResVReg;
2521
2522 if (IsVectorTy) {
2523 NotEqualReg =
2524 IsBoolTy ? InputRegister
2525 : createVirtualRegister(SpvBoolTy, &GR, MRI, MRI->getMF());
2526 const unsigned NumElts = InputType->getOperand(2).getImm();
2527 SpvBoolTy = GR.getOrCreateSPIRVVectorType(SpvBoolTy, NumElts, I, TII);
2528 }
2529
2530 if (!IsBoolTy) {
2531 Register ConstZeroReg =
2532 IsFloatTy ? buildZerosValF(InputType, I) : buildZerosVal(InputType, I);
2533
2534 BuildMI(BB, I, I.getDebugLoc(), TII.get(SpirvNotEqualId))
2535 .addDef(NotEqualReg)
2536 .addUse(GR.getSPIRVTypeID(SpvBoolTy))
2537 .addUse(InputRegister)
2538 .addUse(ConstZeroReg)
2539 .constrainAllUses(TII, TRI, RBI);
2540 }
2541
2542 if (IsVectorTy)
2543 BuildMI(BB, I, I.getDebugLoc(), TII.get(OpAnyOrAll))
2544 .addDef(ResVReg)
2545 .addUse(GR.getSPIRVTypeID(SpvBoolScalarTy))
2546 .addUse(NotEqualReg)
2547 .constrainAllUses(TII, TRI, RBI);
2548 return true;
2549}
2550
2551bool SPIRVInstructionSelector::selectAll(Register ResVReg,
2552 SPIRVTypeInst ResType,
2553 MachineInstr &I) const {
2554 return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAll);
2555}
2556
2557bool SPIRVInstructionSelector::selectAny(Register ResVReg,
2558 SPIRVTypeInst ResType,
2559 MachineInstr &I) const {
2560 return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAny);
2561}
2562
2563// Select the OpDot instruction for the given float dot
2564bool SPIRVInstructionSelector::selectFloatDot(Register ResVReg,
2565 SPIRVTypeInst ResType,
2566 MachineInstr &I) const {
2567 assert(I.getNumOperands() == 4);
2568 assert(I.getOperand(2).isReg());
2569 assert(I.getOperand(3).isReg());
2570
2571 [[maybe_unused]] SPIRVTypeInst VecType =
2572 GR.getSPIRVTypeForVReg(I.getOperand(2).getReg());
2573
2574 assert(VecType->getOpcode() == SPIRV::OpTypeVector &&
2575 GR.getScalarOrVectorComponentCount(VecType) > 1 &&
2576 "dot product requires a vector of at least 2 components");
2577
2578 [[maybe_unused]] SPIRVTypeInst EltType =
2579 GR.getSPIRVTypeForVReg(VecType->getOperand(1).getReg());
2580
2581 assert(EltType->getOpcode() == SPIRV::OpTypeFloat);
2582
2583 MachineBasicBlock &BB = *I.getParent();
2584 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpDot))
2585 .addDef(ResVReg)
2586 .addUse(GR.getSPIRVTypeID(ResType))
2587 .addUse(I.getOperand(2).getReg())
2588 .addUse(I.getOperand(3).getReg())
2589 .constrainAllUses(TII, TRI, RBI);
2590 return true;
2591}
2592
2593bool SPIRVInstructionSelector::selectIntegerDot(Register ResVReg,
2594 SPIRVTypeInst ResType,
2595 MachineInstr &I,
2596 bool Signed) const {
2597 assert(I.getNumOperands() == 4);
2598 assert(I.getOperand(2).isReg());
2599 assert(I.getOperand(3).isReg());
2600 MachineBasicBlock &BB = *I.getParent();
2601
2602 auto DotOp = Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
2603 BuildMI(BB, I, I.getDebugLoc(), TII.get(DotOp))
2604 .addDef(ResVReg)
2605 .addUse(GR.getSPIRVTypeID(ResType))
2606 .addUse(I.getOperand(2).getReg())
2607 .addUse(I.getOperand(3).getReg())
2608 .constrainAllUses(TII, TRI, RBI);
2609 return true;
2610}
2611
2612// Since pre-1.6 SPIRV has no integer dot implementation,
2613// expand by piecewise multiplying and adding the results
2614bool SPIRVInstructionSelector::selectIntegerDotExpansion(
2615 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
2616 assert(I.getNumOperands() == 4);
2617 assert(I.getOperand(2).isReg());
2618 assert(I.getOperand(3).isReg());
2619 MachineBasicBlock &BB = *I.getParent();
2620
2621 // Multiply the vectors, then sum the results
2622 Register Vec0 = I.getOperand(2).getReg();
2623 Register Vec1 = I.getOperand(3).getReg();
2624 Register TmpVec = MRI->createVirtualRegister(GR.getRegClass(ResType));
2625 SPIRVTypeInst VecType = GR.getSPIRVTypeForVReg(Vec0);
2626
2627 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIMulV))
2628 .addDef(TmpVec)
2629 .addUse(GR.getSPIRVTypeID(VecType))
2630 .addUse(Vec0)
2631 .addUse(Vec1)
2632 .constrainAllUses(TII, TRI, RBI);
2633
2634 assert(VecType->getOpcode() == SPIRV::OpTypeVector &&
2635 GR.getScalarOrVectorComponentCount(VecType) > 1 &&
2636 "dot product requires a vector of at least 2 components");
2637
2638 Register Res = MRI->createVirtualRegister(GR.getRegClass(ResType));
2639 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
2640 .addDef(Res)
2641 .addUse(GR.getSPIRVTypeID(ResType))
2642 .addUse(TmpVec)
2643 .addImm(0)
2644 .constrainAllUses(TII, TRI, RBI);
2645
2646 for (unsigned i = 1; i < GR.getScalarOrVectorComponentCount(VecType); i++) {
2647 Register Elt = MRI->createVirtualRegister(GR.getRegClass(ResType));
2648
2649 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
2650 .addDef(Elt)
2651 .addUse(GR.getSPIRVTypeID(ResType))
2652 .addUse(TmpVec)
2653 .addImm(i)
2654 .constrainAllUses(TII, TRI, RBI);
2655
2656 Register Sum = i < GR.getScalarOrVectorComponentCount(VecType) - 1
2657 ? MRI->createVirtualRegister(GR.getRegClass(ResType))
2658 : ResVReg;
2659
2660 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
2661 .addDef(Sum)
2662 .addUse(GR.getSPIRVTypeID(ResType))
2663 .addUse(Res)
2664 .addUse(Elt)
2665 .constrainAllUses(TII, TRI, RBI);
2666 Res = Sum;
2667 }
2668
2669 return true;
2670}
2671
2672bool SPIRVInstructionSelector::selectOpIsInf(Register ResVReg,
2673 SPIRVTypeInst ResType,
2674 MachineInstr &I) const {
2675 MachineBasicBlock &BB = *I.getParent();
2676 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsInf))
2677 .addDef(ResVReg)
2678 .addUse(GR.getSPIRVTypeID(ResType))
2679 .addUse(I.getOperand(2).getReg())
2680 .constrainAllUses(TII, TRI, RBI);
2681 return true;
2682}
2683
2684bool SPIRVInstructionSelector::selectOpIsNan(Register ResVReg,
2685 SPIRVTypeInst ResType,
2686 MachineInstr &I) const {
2687 MachineBasicBlock &BB = *I.getParent();
2688 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsNan))
2689 .addDef(ResVReg)
2690 .addUse(GR.getSPIRVTypeID(ResType))
2691 .addUse(I.getOperand(2).getReg())
2692 .constrainAllUses(TII, TRI, RBI);
2693 return true;
2694}
2695
2696template <bool Signed>
2697bool SPIRVInstructionSelector::selectDot4AddPacked(Register ResVReg,
2698 SPIRVTypeInst ResType,
2699 MachineInstr &I) const {
2700 assert(I.getNumOperands() == 5);
2701 assert(I.getOperand(2).isReg());
2702 assert(I.getOperand(3).isReg());
2703 assert(I.getOperand(4).isReg());
2704 MachineBasicBlock &BB = *I.getParent();
2705
2706 Register Acc = I.getOperand(2).getReg();
2707 Register X = I.getOperand(3).getReg();
2708 Register Y = I.getOperand(4).getReg();
2709
2710 auto DotOp = Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
2711 Register Dot = MRI->createVirtualRegister(GR.getRegClass(ResType));
2712 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(DotOp))
2713 .addDef(Dot)
2714 .addUse(GR.getSPIRVTypeID(ResType))
2715 .addUse(X)
2716 .addUse(Y);
2717 MIB.addImm(SPIRV::BuiltIn::PackedVectorFormat4x8Bit);
2718 MIB.constrainAllUses(TII, TRI, RBI);
2719
2720 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
2721 .addDef(ResVReg)
2722 .addUse(GR.getSPIRVTypeID(ResType))
2723 .addUse(Dot)
2724 .addUse(Acc)
2725 .constrainAllUses(TII, TRI, RBI);
2726 return true;
2727}
2728
2729// Since pre-1.6 SPIRV has no DotProductInput4x8BitPacked implementation,
2730// extract the elements of the packed inputs, multiply them and add the result
2731// to the accumulator.
2732template <bool Signed>
2733bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
2734 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
2735 assert(I.getNumOperands() == 5);
2736 assert(I.getOperand(2).isReg());
2737 assert(I.getOperand(3).isReg());
2738 assert(I.getOperand(4).isReg());
2739 MachineBasicBlock &BB = *I.getParent();
2740
2741 Register Acc = I.getOperand(2).getReg();
2742 Register X = I.getOperand(3).getReg();
2743 Register Y = I.getOperand(4).getReg();
2744
2745 SPIRVTypeInst EltType = GR.getOrCreateSPIRVIntegerType(8, I, TII);
2746 auto ExtractOp =
2747 Signed ? SPIRV::OpBitFieldSExtract : SPIRV::OpBitFieldUExtract;
2748
2749 bool ZeroAsNull = !STI.isShader();
2750 // Extract the i8 element, multiply and add it to the accumulator
2751 for (unsigned i = 0; i < 4; i++) {
2752 // A[i]
2753 Register AElt = MRI->createVirtualRegister(&SPIRV::IDRegClass);
2754 BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
2755 .addDef(AElt)
2756 .addUse(GR.getSPIRVTypeID(ResType))
2757 .addUse(X)
2758 .addUse(GR.getOrCreateConstInt(i * 8, I, EltType, TII, ZeroAsNull))
2759 .addUse(GR.getOrCreateConstInt(8, I, EltType, TII, ZeroAsNull))
2760 .constrainAllUses(TII, TRI, RBI);
2761
2762 // B[i]
2763 Register BElt = MRI->createVirtualRegister(&SPIRV::IDRegClass);
2764 BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
2765 .addDef(BElt)
2766 .addUse(GR.getSPIRVTypeID(ResType))
2767 .addUse(Y)
2768 .addUse(GR.getOrCreateConstInt(i * 8, I, EltType, TII, ZeroAsNull))
2769 .addUse(GR.getOrCreateConstInt(8, I, EltType, TII, ZeroAsNull))
2770 .constrainAllUses(TII, TRI, RBI);
2771
2772 // A[i] * B[i]
2773 Register Mul = MRI->createVirtualRegister(&SPIRV::IDRegClass);
2774 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIMulS))
2775 .addDef(Mul)
2776 .addUse(GR.getSPIRVTypeID(ResType))
2777 .addUse(AElt)
2778 .addUse(BElt)
2779 .constrainAllUses(TII, TRI, RBI);
2780
2781 // Discard 24 highest-bits so that stored i32 register is i8 equivalent
2782 Register MaskMul = MRI->createVirtualRegister(&SPIRV::IDRegClass);
2783 BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
2784 .addDef(MaskMul)
2785 .addUse(GR.getSPIRVTypeID(ResType))
2786 .addUse(Mul)
2787 .addUse(GR.getOrCreateConstInt(0, I, EltType, TII, ZeroAsNull))
2788 .addUse(GR.getOrCreateConstInt(8, I, EltType, TII, ZeroAsNull))
2789 .constrainAllUses(TII, TRI, RBI);
2790
2791 // Acc = Acc + A[i] * B[i]
2792 Register Sum =
2793 i < 3 ? MRI->createVirtualRegister(&SPIRV::IDRegClass) : ResVReg;
2794 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
2795 .addDef(Sum)
2796 .addUse(GR.getSPIRVTypeID(ResType))
2797 .addUse(Acc)
2798 .addUse(MaskMul)
2799 .constrainAllUses(TII, TRI, RBI);
2800
2801 Acc = Sum;
2802 }
2803
2804 return true;
2805}
2806
2807/// Transform saturate(x) to clamp(x, 0.0f, 1.0f) as SPIRV
2808/// does not have a saturate builtin.
2809bool SPIRVInstructionSelector::selectSaturate(Register ResVReg,
2810 SPIRVTypeInst ResType,
2811 MachineInstr &I) const {
2812 assert(I.getNumOperands() == 3);
2813 assert(I.getOperand(2).isReg());
2814 MachineBasicBlock &BB = *I.getParent();
2815 Register VZero = buildZerosValF(ResType, I);
2816 Register VOne = buildOnesValF(ResType, I);
2817
2818 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
2819 .addDef(ResVReg)
2820 .addUse(GR.getSPIRVTypeID(ResType))
2821 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
2822 .addImm(GL::FClamp)
2823 .addUse(I.getOperand(2).getReg())
2824 .addUse(VZero)
2825 .addUse(VOne)
2826 .constrainAllUses(TII, TRI, RBI);
2827 return true;
2828}
2829
2830bool SPIRVInstructionSelector::selectSign(Register ResVReg,
2831 SPIRVTypeInst ResType,
2832 MachineInstr &I) const {
2833 assert(I.getNumOperands() == 3);
2834 assert(I.getOperand(2).isReg());
2835 MachineBasicBlock &BB = *I.getParent();
2836 Register InputRegister = I.getOperand(2).getReg();
2837 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
2838 auto &DL = I.getDebugLoc();
2839
2840 if (!InputType)
2841 report_fatal_error("Input Type could not be determined.");
2842
2843 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
2844
2845 unsigned SignBitWidth = GR.getScalarOrVectorBitWidth(InputType);
2846 unsigned ResBitWidth = GR.getScalarOrVectorBitWidth(ResType);
2847
2848 bool NeedsConversion = IsFloatTy || SignBitWidth != ResBitWidth;
2849
2850 auto SignOpcode = IsFloatTy ? GL::FSign : GL::SSign;
2851 Register SignReg = NeedsConversion
2852 ? MRI->createVirtualRegister(&SPIRV::IDRegClass)
2853 : ResVReg;
2854
2855 BuildMI(BB, I, DL, TII.get(SPIRV::OpExtInst))
2856 .addDef(SignReg)
2857 .addUse(GR.getSPIRVTypeID(InputType))
2858 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
2859 .addImm(SignOpcode)
2860 .addUse(InputRegister)
2861 .constrainAllUses(TII, TRI, RBI);
2862
2863 if (NeedsConversion) {
2864 auto ConvertOpcode = IsFloatTy ? SPIRV::OpConvertFToS : SPIRV::OpSConvert;
2865 BuildMI(*I.getParent(), I, DL, TII.get(ConvertOpcode))
2866 .addDef(ResVReg)
2867 .addUse(GR.getSPIRVTypeID(ResType))
2868 .addUse(SignReg)
2869 .constrainAllUses(TII, TRI, RBI);
2870 }
2871
2872 return true;
2873}
2874
2875bool SPIRVInstructionSelector::selectWaveOpInst(Register ResVReg,
2876 SPIRVTypeInst ResType,
2877 MachineInstr &I,
2878 unsigned Opcode) const {
2879 MachineBasicBlock &BB = *I.getParent();
2880 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
2881
2882 auto BMI = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
2883 .addDef(ResVReg)
2884 .addUse(GR.getSPIRVTypeID(ResType))
2885 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I,
2886 IntTy, TII, !STI.isShader()));
2887
2888 for (unsigned J = 2; J < I.getNumOperands(); J++) {
2889 BMI.addUse(I.getOperand(J).getReg());
2890 }
2891
2892 BMI.constrainAllUses(TII, TRI, RBI);
2893 return true;
2894}
2895
2896bool SPIRVInstructionSelector::selectWaveActiveCountBits(
2897 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
2898
2899 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
2900 SPIRVTypeInst BallotType = GR.getOrCreateSPIRVVectorType(IntTy, 4, I, TII);
2901 Register BallotReg = MRI->createVirtualRegister(GR.getRegClass(BallotType));
2902 if (!selectWaveOpInst(BallotReg, BallotType, I,
2903 SPIRV::OpGroupNonUniformBallot))
2904 return false;
2905
2906 MachineBasicBlock &BB = *I.getParent();
2907 BuildMI(BB, I, I.getDebugLoc(),
2908 TII.get(SPIRV::OpGroupNonUniformBallotBitCount))
2909 .addDef(ResVReg)
2910 .addUse(GR.getSPIRVTypeID(ResType))
2911 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
2912 !STI.isShader()))
2913 .addImm(SPIRV::GroupOperation::Reduce)
2914 .addUse(BallotReg)
2915 .constrainAllUses(TII, TRI, RBI);
2916
2917 return true;
2918}
2919
2921
2922 if (Type->getOpcode() != SPIRV::OpTypeVector)
2923 return 1;
2924
2925 // Operand(2) is the vector size
2926 return Type->getOperand(2).getImm();
2927}
2928
2929bool SPIRVInstructionSelector::selectWaveActiveAllEqual(Register ResVReg,
2930 SPIRVTypeInst ResType,
2931 MachineInstr &I) const {
2932 MachineBasicBlock &BB = *I.getParent();
2933 const DebugLoc &DL = I.getDebugLoc();
2934
2935 // Input to the intrinsic
2936 Register InputReg = I.getOperand(2).getReg();
2937 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputReg);
2938
2939 // Determine if input is vector
2940 unsigned NumElems = getVectorSizeOrOne(InputType);
2941 bool IsVector = NumElems > 1;
2942
2943 // Determine element types
2944 SPIRVTypeInst ElemInputType = InputType;
2945 SPIRVTypeInst ElemBoolType = ResType;
2946 if (IsVector) {
2947 ElemInputType = GR.getSPIRVTypeForVReg(InputType->getOperand(1).getReg());
2948 ElemBoolType = GR.getSPIRVTypeForVReg(ResType->getOperand(1).getReg());
2949 }
2950
2951 // Subgroup scope constant
2952 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
2953 Register ScopeConst = GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy,
2954 TII, !STI.isShader());
2955
2956 // Scalar case
2957 if (!IsVector) {
2958 return selectWaveOpInst(ResVReg, ElemBoolType, I,
2959 SPIRV::OpGroupNonUniformAllEqual);
2960 }
2961
2962 // Vector case
2963 SmallVector<Register, 4> ElementResults;
2964 ElementResults.reserve(NumElems);
2965
2966 for (unsigned Idx = 0; Idx < NumElems; ++Idx) {
2967 // Extract element
2968 Register ElemInput = InputReg;
2969 Register Extracted =
2970 MRI->createVirtualRegister(GR.getRegClass(ElemInputType));
2971
2972 BuildMI(BB, I, DL, TII.get(SPIRV::OpCompositeExtract))
2973 .addDef(Extracted)
2974 .addUse(GR.getSPIRVTypeID(ElemInputType))
2975 .addUse(InputReg)
2976 .addImm(Idx)
2977 .constrainAllUses(TII, TRI, RBI);
2978
2979 ElemInput = Extracted;
2980
2981 // Emit per-element AllEqual
2982 Register ElemResult =
2983 MRI->createVirtualRegister(GR.getRegClass(ElemBoolType));
2984
2985 BuildMI(BB, I, DL, TII.get(SPIRV::OpGroupNonUniformAllEqual))
2986 .addDef(ElemResult)
2987 .addUse(GR.getSPIRVTypeID(ElemBoolType))
2988 .addUse(ScopeConst)
2989 .addUse(ElemInput)
2990 .constrainAllUses(TII, TRI, RBI);
2991
2992 ElementResults.push_back(ElemResult);
2993 }
2994
2995 // Reconstruct vector<bool>
2996 auto MIB = BuildMI(BB, I, DL, TII.get(SPIRV::OpCompositeConstruct))
2997 .addDef(ResVReg)
2998 .addUse(GR.getSPIRVTypeID(ResType));
2999 for (Register R : ElementResults)
3000 MIB.addUse(R);
3001
3002 MIB.constrainAllUses(TII, TRI, RBI);
3003
3004 return true;
3005}
3006
3007bool SPIRVInstructionSelector::selectWavePrefixBitCount(Register ResVReg,
3008 SPIRVTypeInst ResType,
3009 MachineInstr &I) const {
3010
3011 assert(I.getNumOperands() == 3);
3012
3013 auto Op = I.getOperand(2);
3014 assert(Op.isReg());
3015
3016 MachineBasicBlock &BB = *I.getParent();
3017 DebugLoc DL = I.getDebugLoc();
3018
3019 Register InputRegister = Op.getReg();
3020 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
3021
3022 if (!InputType)
3023 report_fatal_error("Input Type could not be determined.");
3024
3025 if (InputType->getOpcode() != SPIRV::OpTypeBool)
3026 report_fatal_error("WavePrefixBitCount requires boolean input");
3027
3028 // Types
3029 SPIRVTypeInst Int32Ty = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3030
3031 // Ballot result type: vector<uint32>
3032 // Match DXC: %v4uint for Subgroup size
3033 SPIRVTypeInst BallotTy = GR.getOrCreateSPIRVVectorType(Int32Ty, 4, I, TII);
3034
3035 // Create a vreg for the ballot result
3036 Register BallotVReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
3037
3038 // 1. OpGroupNonUniformBallot
3039 BuildMI(BB, I, DL, TII.get(SPIRV::OpGroupNonUniformBallot))
3040 .addDef(BallotVReg)
3041 .addUse(GR.getSPIRVTypeID(BallotTy))
3042 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, Int32Ty, TII))
3043 .addUse(InputRegister)
3044 .constrainAllUses(TII, TRI, RBI);
3045
3046 // 2. OpGroupNonUniformBallotBitCount
3047 BuildMI(BB, I, DL, TII.get(SPIRV::OpGroupNonUniformBallotBitCount))
3048 .addDef(ResVReg)
3049 .addUse(GR.getSPIRVTypeID(ResType))
3050 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, Int32Ty, TII))
3051 .addImm(SPIRV::GroupOperation::ExclusiveScan)
3052 .addUse(BallotVReg)
3053 .constrainAllUses(TII, TRI, RBI);
3054
3055 return true;
3056}
3057
3058bool SPIRVInstructionSelector::selectWaveReduceMax(Register ResVReg,
3059 SPIRVTypeInst ResType,
3060 MachineInstr &I,
3061 bool IsUnsigned) const {
3062 return selectWaveReduce(
3063 ResVReg, ResType, I, IsUnsigned,
3064 [&](Register InputRegister, bool IsUnsigned) {
3065 const bool IsFloatTy =
3066 GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
3067 const auto IntOp = IsUnsigned ? SPIRV::OpGroupNonUniformUMax
3068 : SPIRV::OpGroupNonUniformSMax;
3069 return IsFloatTy ? SPIRV::OpGroupNonUniformFMax : IntOp;
3070 });
3071}
3072
3073bool SPIRVInstructionSelector::selectWaveReduceMin(Register ResVReg,
3074 SPIRVTypeInst ResType,
3075 MachineInstr &I,
3076 bool IsUnsigned) const {
3077 return selectWaveReduce(
3078 ResVReg, ResType, I, IsUnsigned,
3079 [&](Register InputRegister, bool IsUnsigned) {
3080 const bool IsFloatTy =
3081 GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
3082 const auto IntOp = IsUnsigned ? SPIRV::OpGroupNonUniformUMin
3083 : SPIRV::OpGroupNonUniformSMin;
3084 return IsFloatTy ? SPIRV::OpGroupNonUniformFMin : IntOp;
3085 });
3086}
3087
3088bool SPIRVInstructionSelector::selectWaveReduceSum(Register ResVReg,
3089 SPIRVTypeInst ResType,
3090 MachineInstr &I) const {
3091 return selectWaveReduce(ResVReg, ResType, I, /*IsUnsigned*/ false,
3092 [&](Register InputRegister, bool IsUnsigned) {
3093 bool IsFloatTy = GR.isScalarOrVectorOfType(
3094 InputRegister, SPIRV::OpTypeFloat);
3095 return IsFloatTy ? SPIRV::OpGroupNonUniformFAdd
3096 : SPIRV::OpGroupNonUniformIAdd;
3097 });
3098}
3099
3100bool SPIRVInstructionSelector::selectWaveReduceProduct(Register ResVReg,
3101 SPIRVTypeInst ResType,
3102 MachineInstr &I) const {
3103 return selectWaveReduce(ResVReg, ResType, I, /*IsUnsigned*/ false,
3104 [&](Register InputRegister, bool IsUnsigned) {
3105 bool IsFloatTy = GR.isScalarOrVectorOfType(
3106 InputRegister, SPIRV::OpTypeFloat);
3107 return IsFloatTy ? SPIRV::OpGroupNonUniformFMul
3108 : SPIRV::OpGroupNonUniformIMul;
3109 });
3110}
3111
3112template <typename PickOpcodeFn>
3113bool SPIRVInstructionSelector::selectWaveReduce(
3114 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, bool IsUnsigned,
3115 PickOpcodeFn &&PickOpcode) const {
3116 assert(I.getNumOperands() == 3);
3117 assert(I.getOperand(2).isReg());
3118 MachineBasicBlock &BB = *I.getParent();
3119 Register InputRegister = I.getOperand(2).getReg();
3120 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
3121
3122 if (!InputType)
3123 report_fatal_error("Input Type could not be determined.");
3124
3125 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3126 const unsigned Opcode = PickOpcode(InputRegister, IsUnsigned);
3127 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3128 .addDef(ResVReg)
3129 .addUse(GR.getSPIRVTypeID(ResType))
3130 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
3131 !STI.isShader()))
3132 .addImm(SPIRV::GroupOperation::Reduce)
3133 .addUse(I.getOperand(2).getReg())
3134 .constrainAllUses(TII, TRI, RBI);
3135 return true;
3136}
3137
3138bool SPIRVInstructionSelector::selectWaveReduceOp(Register ResVReg,
3139 SPIRVTypeInst ResType,
3140 MachineInstr &I,
3141 unsigned Opcode) const {
3142 return selectWaveReduce(
3143 ResVReg, ResType, I, false,
3144 [&](Register InputRegister, bool IsUnsigned) { return Opcode; });
3145}
3146
3147bool SPIRVInstructionSelector::selectWaveExclusiveScanSum(
3148 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3149 return selectWaveExclusiveScan(ResVReg, ResType, I, /*IsUnsigned*/ false,
3150 [&](Register InputRegister, bool IsUnsigned) {
3151 bool IsFloatTy = GR.isScalarOrVectorOfType(
3152 InputRegister, SPIRV::OpTypeFloat);
3153 return IsFloatTy
3154 ? SPIRV::OpGroupNonUniformFAdd
3155 : SPIRV::OpGroupNonUniformIAdd;
3156 });
3157}
3158
3159bool SPIRVInstructionSelector::selectWaveExclusiveScanProduct(
3160 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3161 return selectWaveExclusiveScan(ResVReg, ResType, I, /*IsUnsigned*/ false,
3162 [&](Register InputRegister, bool IsUnsigned) {
3163 bool IsFloatTy = GR.isScalarOrVectorOfType(
3164 InputRegister, SPIRV::OpTypeFloat);
3165 return IsFloatTy
3166 ? SPIRV::OpGroupNonUniformFMul
3167 : SPIRV::OpGroupNonUniformIMul;
3168 });
3169}
3170
3171template <typename PickOpcodeFn>
3172bool SPIRVInstructionSelector::selectWaveExclusiveScan(
3173 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, bool IsUnsigned,
3174 PickOpcodeFn &&PickOpcode) const {
3175 assert(I.getNumOperands() == 3);
3176 assert(I.getOperand(2).isReg());
3177 MachineBasicBlock &BB = *I.getParent();
3178 Register InputRegister = I.getOperand(2).getReg();
3179 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
3180
3181 if (!InputType)
3182 report_fatal_error("Input Type could not be determined.");
3183
3184 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3185 const unsigned Opcode = PickOpcode(InputRegister, IsUnsigned);
3186 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3187 .addDef(ResVReg)
3188 .addUse(GR.getSPIRVTypeID(ResType))
3189 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
3190 !STI.isShader()))
3191 .addImm(SPIRV::GroupOperation::ExclusiveScan)
3192 .addUse(I.getOperand(2).getReg())
3193 .constrainAllUses(TII, TRI, RBI);
3194 return true;
3195}
3196
3197bool SPIRVInstructionSelector::selectQuadSwap(Register ResVReg,
3198 SPIRVTypeInst ResType,
3199 MachineInstr &I,
3200 unsigned Direction) const {
3201 assert(I.getNumOperands() == 3);
3202 assert(I.getOperand(2).isReg());
3203 MachineBasicBlock &BB = *I.getParent();
3204 Register InputRegister = I.getOperand(2).getReg();
3205
3206 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3207 bool ZeroAsNull = !STI.isShader();
3208 Register DirectionReg =
3209 GR.getOrCreateConstInt(Direction, I, IntTy, TII, ZeroAsNull);
3210 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpGroupNonUniformQuadSwap))
3211 .addDef(ResVReg)
3212 .addUse(GR.getSPIRVTypeID(ResType))
3213 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
3214 ZeroAsNull))
3215 .addUse(InputRegister)
3216 .addUse(DirectionReg)
3217 .constrainAllUses(TII, TRI, RBI);
3218 return true;
3219}
3220
3221bool SPIRVInstructionSelector::selectBitreverse16(Register ResVReg,
3222 SPIRVTypeInst ResType,
3223 MachineInstr &I,
3224 Register Op) const {
3225 SPIRVTypeInst Int32Type = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3226 Register ShiftConst = GR.getOrCreateConstInt(16, I, Int32Type, TII);
3227 unsigned ShiftOp = SPIRV::OpShiftRightLogicalS;
3228
3229 const unsigned N = GR.getScalarOrVectorComponentCount(ResType);
3230 const unsigned ExtendOpcode = GR.isScalarOrVectorSigned(ResType)
3231 ? SPIRV::OpSConvert
3232 : SPIRV::OpUConvert;
3233
3234 if (N > 1) {
3235 Int32Type = GR.getOrCreateSPIRVVectorType(Int32Type, N, I, TII);
3236 ShiftOp = SPIRV::OpShiftRightLogicalV;
3237
3238 // Vector shifts require a composite constant
3239 const Register CompositeReg =
3240 MRI->createVirtualRegister(GR.getRegClass(Int32Type));
3241 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
3242 TII.get(SPIRV::OpConstantComposite))
3243 .addDef(CompositeReg)
3244 .addUse(GR.getSPIRVTypeID(Int32Type));
3245 for (unsigned It = 0; It < N; ++It)
3246 MIB.addUse(ShiftConst);
3247 MIB.constrainAllUses(TII, TRI, RBI);
3248
3249 ShiftConst = CompositeReg;
3250 }
3251
3252 // Converts the i16 input to i32 (or vector of i32)
3253 Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
3254 if (!selectOpWithSrcs(ExtReg, Int32Type, I, {Op}, ExtendOpcode))
3255 return false;
3256
3257 // Perform bitreverse on the i32 value
3258 Register BitrevReg = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
3259 if (!selectBitreverse32(BitrevReg, Int32Type, I, ExtReg))
3260 return false;
3261
3262 // Shift the bit-reversed value to get the final result.
3263 Register ShiftReg = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
3264 if (!selectOpWithSrcs(ShiftReg, Int32Type, I, {BitrevReg, ShiftConst},
3265 ShiftOp))
3266 return false;
3267
3268 // Finally, convert the result back to i16 (or vector of i16).
3269 return selectOpWithSrcs(ResVReg, ResType, I, {ShiftReg}, ExtendOpcode);
3270}
3271
3272bool SPIRVInstructionSelector::selectBitreverse32(Register ResVReg,
3273 SPIRVTypeInst ResType,
3274 MachineInstr &I,
3275 Register Op) const {
3276 MachineBasicBlock &BB = *I.getParent();
3277 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse))
3278 .addDef(ResVReg)
3279 .addUse(GR.getSPIRVTypeID(ResType))
3280 .addUse(Op)
3281 .constrainAllUses(TII, TRI, RBI);
3282 return true;
3283}
3284
3285bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
3286 SPIRVTypeInst ResType,
3287 MachineInstr &I) const {
3288 Register OpReg = I.getOperand(1).getReg();
3289 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
3290 switch (GR.getScalarOrVectorBitWidth(OpType)) {
3291 case 16:
3292 return selectBitreverse16(ResVReg, ResType, I, OpReg);
3293 default:
3294 return selectBitreverse32(ResVReg, ResType, I, OpReg);
3295 }
3296}
3297
3298bool SPIRVInstructionSelector::selectFreeze(Register ResVReg,
3299 SPIRVTypeInst ResType,
3300 MachineInstr &I) const {
3301 // There is no way to implement `freeze` correctly without support on SPIR-V
3302 // standard side, but we may at least address a simple (static) case when
3303 // undef/poison value presence is obvious. The main benefit of even
3304 // incomplete `freeze` support is preventing of translation from crashing due
3305 // to lack of support on legalization and instruction selection steps.
3306 if (!I.getOperand(0).isReg() || !I.getOperand(1).isReg())
3307 return false;
3308 Register OpReg = I.getOperand(1).getReg();
3309 if (MachineInstr *Def = MRI->getVRegDef(OpReg)) {
3310 if (Def->getOpcode() == TargetOpcode::COPY)
3311 Def = MRI->getVRegDef(Def->getOperand(1).getReg());
3312 Register Reg;
3313 switch (Def->getOpcode()) {
3314 case SPIRV::ASSIGN_TYPE:
3315 if (MachineInstr *AssignToDef =
3316 MRI->getVRegDef(Def->getOperand(1).getReg())) {
3317 if (AssignToDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
3318 Reg = Def->getOperand(2).getReg();
3319 }
3320 break;
3321 case SPIRV::OpUndef:
3322 Reg = Def->getOperand(1).getReg();
3323 break;
3324 }
3325 unsigned DestOpCode;
3326 if (Reg.isValid()) {
3327 DestOpCode = SPIRV::OpConstantNull;
3328 } else {
3329 DestOpCode = TargetOpcode::COPY;
3330 Reg = OpReg;
3331 }
3332 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DestOpCode))
3333 .addDef(I.getOperand(0).getReg())
3334 .addUse(Reg)
3335 .constrainAllUses(TII, TRI, RBI);
3336 return true;
3337 }
3338 return false;
3339}
3340
3341bool SPIRVInstructionSelector::selectBuildVector(Register ResVReg,
3342 SPIRVTypeInst ResType,
3343 MachineInstr &I) const {
3344 unsigned N = 0;
3345 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3346 N = GR.getScalarOrVectorComponentCount(ResType);
3347 else if (ResType->getOpcode() == SPIRV::OpTypeArray)
3348 N = getArrayComponentCount(MRI, ResType);
3349 else
3350 report_fatal_error("Cannot select G_BUILD_VECTOR with a non-vector result");
3351 if (I.getNumExplicitOperands() - I.getNumExplicitDefs() != N)
3352 report_fatal_error("G_BUILD_VECTOR and the result type are inconsistent");
3353
3354 // check if we may construct a constant vector
3355 bool IsConst = true;
3356 for (unsigned i = I.getNumExplicitDefs();
3357 i < I.getNumExplicitOperands() && IsConst; ++i)
3358 if (!isConstReg(MRI, I.getOperand(i).getReg()))
3359 IsConst = false;
3360
3361 if (!IsConst && N < 2)
3363 "There must be at least two constituent operands in a vector");
3364
3365 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
3366 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
3367 TII.get(IsConst ? SPIRV::OpConstantComposite
3368 : SPIRV::OpCompositeConstruct))
3369 .addDef(ResVReg)
3370 .addUse(GR.getSPIRVTypeID(ResType));
3371 for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i)
3372 MIB.addUse(I.getOperand(i).getReg());
3373 MIB.constrainAllUses(TII, TRI, RBI);
3374 return true;
3375}
3376
3377bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg,
3378 SPIRVTypeInst ResType,
3379 MachineInstr &I) const {
3380 unsigned N = 0;
3381 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3382 N = GR.getScalarOrVectorComponentCount(ResType);
3383 else if (ResType->getOpcode() == SPIRV::OpTypeArray)
3384 N = getArrayComponentCount(MRI, ResType);
3385 else
3386 report_fatal_error("Cannot select G_SPLAT_VECTOR with a non-vector result");
3387
3388 unsigned OpIdx = I.getNumExplicitDefs();
3389 if (!I.getOperand(OpIdx).isReg())
3390 report_fatal_error("Unexpected argument in G_SPLAT_VECTOR");
3391
3392 // check if we may construct a constant vector
3393 Register OpReg = I.getOperand(OpIdx).getReg();
3394 bool IsConst = isConstReg(MRI, OpReg);
3395
3396 if (!IsConst && N < 2)
3398 "There must be at least two constituent operands in a vector");
3399
3400 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
3401 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
3402 TII.get(IsConst ? SPIRV::OpConstantComposite
3403 : SPIRV::OpCompositeConstruct))
3404 .addDef(ResVReg)
3405 .addUse(GR.getSPIRVTypeID(ResType));
3406 for (unsigned i = 0; i < N; ++i)
3407 MIB.addUse(OpReg);
3408 MIB.constrainAllUses(TII, TRI, RBI);
3409 return true;
3410}
3411
3412bool SPIRVInstructionSelector::selectDiscard(Register ResVReg,
3413 SPIRVTypeInst ResType,
3414 MachineInstr &I) const {
3415
3416 unsigned Opcode;
3417
3418 if (STI.canUseExtension(
3419 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation) ||
3420 STI.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6))) {
3421 Opcode = SPIRV::OpDemoteToHelperInvocation;
3422 } else {
3423 Opcode = SPIRV::OpKill;
3424 // OpKill must be the last operation of any basic block.
3425 if (MachineInstr *NextI = I.getNextNode()) {
3426 GR.invalidateMachineInstr(NextI);
3427 NextI->eraseFromParent();
3428 }
3429 }
3430
3431 MachineBasicBlock &BB = *I.getParent();
3432 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3433 .constrainAllUses(TII, TRI, RBI);
3434 return true;
3435}
3436
3437bool SPIRVInstructionSelector::selectCmp(Register ResVReg,
3438 SPIRVTypeInst ResType, unsigned CmpOpc,
3439 MachineInstr &I) const {
3440 Register Cmp0 = I.getOperand(2).getReg();
3441 Register Cmp1 = I.getOperand(3).getReg();
3442 assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() ==
3443 GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() &&
3444 "CMP operands should have the same type");
3445 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(CmpOpc))
3446 .addDef(ResVReg)
3447 .addUse(GR.getSPIRVTypeID(ResType))
3448 .addUse(Cmp0)
3449 .addUse(Cmp1)
3450 .setMIFlags(I.getFlags())
3451 .constrainAllUses(TII, TRI, RBI);
3452 return true;
3453}
3454
3455bool SPIRVInstructionSelector::selectICmp(Register ResVReg,
3456 SPIRVTypeInst ResType,
3457 MachineInstr &I) const {
3458 auto Pred = I.getOperand(1).getPredicate();
3459 unsigned CmpOpc;
3460
3461 Register CmpOperand = I.getOperand(2).getReg();
3462 if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer))
3463 CmpOpc = getPtrCmpOpcode(Pred);
3464 else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool))
3465 CmpOpc = getBoolCmpOpcode(Pred);
3466 else
3467 CmpOpc = getICmpOpcode(Pred);
3468 return selectCmp(ResVReg, ResType, CmpOpc, I);
3469}
3470
3472SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I,
3473 SPIRVTypeInst ResType) const {
3474 Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32);
3475 SPIRVTypeInst SpvI32Ty =
3476 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII);
3477 // Find a constant in DT or build a new one.
3478 auto ConstInt = ConstantInt::get(LLVMTy, Val);
3479 Register NewReg = GR.find(ConstInt, GR.CurMF);
3480 if (!NewReg.isValid()) {
3481 NewReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
3482 MachineBasicBlock &BB = *I.getParent();
3483 MachineInstr *MI =
3484 Val == 0
3485 ? BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
3486 .addDef(NewReg)
3487 .addUse(GR.getSPIRVTypeID(SpvI32Ty))
3488 : BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
3489 .addDef(NewReg)
3490 .addUse(GR.getSPIRVTypeID(SpvI32Ty))
3491 .addImm(APInt(32, Val).getZExtValue());
3493 GR.add(ConstInt, MI);
3494 }
3495 return NewReg;
3496}
3497
3498bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
3499 SPIRVTypeInst ResType,
3500 MachineInstr &I) const {
3501 unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate());
3502 return selectCmp(ResVReg, ResType, CmpOp, I);
3503}
3504
3505bool SPIRVInstructionSelector::selectExp10(Register ResVReg,
3506 SPIRVTypeInst ResType,
3507 MachineInstr &I) const {
3508 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
3509 return selectExtInst(ResVReg, ResType, I, CL::exp10);
3510 }
3511
3512 if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
3513 /// There is no exp10 in GLSL. Use exp10(x) = exp2(x * log2(10)) instead
3514 /// log2(10) ~= 3.3219280948874l
3515
3516 if (ResType->getOpcode() != SPIRV::OpTypeVector &&
3517 ResType->getOpcode() != SPIRV::OpTypeFloat)
3518 return false;
3519
3520 MachineIRBuilder MIRBuilder(I);
3521
3522 SPIRVTypeInst SpirvScalarType = ResType->getOpcode() == SPIRV::OpTypeVector
3523 ? SPIRVTypeInst(GR.getSPIRVTypeForVReg(
3524 ResType->getOperand(1).getReg()))
3525 : ResType;
3526
3527 assert(SpirvScalarType->getOperand(1).getImm() == 32 &&
3528 "only float operands supported by GLSL extended math");
3529
3530 Register ConstReg = GR.buildConstantFP(APFloat(3.3219280948874f),
3531 MIRBuilder, SpirvScalarType);
3532 Register ArgReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
3533 auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector
3534 ? SPIRV::OpVectorTimesScalar
3535 : SPIRV::OpFMulS;
3536
3537 if (!selectOpWithSrcs(ArgReg, ResType, I,
3538 {I.getOperand(1).getReg(), ConstReg}, Opcode))
3539 return false;
3540 if (!selectExtInst(ResVReg, ResType, I,
3541 {{SPIRV::InstructionSet::GLSL_std_450, GL::Exp2}}, false,
3542 false, {ArgReg}))
3543 return false;
3544
3545 return true;
3546 }
3547
3548 return false;
3549}
3550
3551Register SPIRVInstructionSelector::buildZerosVal(SPIRVTypeInst ResType,
3552 MachineInstr &I) const {
3553 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
3554 bool ZeroAsNull = !STI.isShader();
3555 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3556 return GR.getOrCreateConstVector(0UL, I, ResType, TII, ZeroAsNull);
3557 return GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
3558}
3559
3560bool SPIRVInstructionSelector::isScalarOrVectorIntConstantZero(
3561 Register Reg) const {
3562 SPIRVTypeInst Type = GR.getSPIRVTypeForVReg(Reg);
3563 if (!Type)
3564 return false;
3565 SPIRVTypeInst CompType = GR.getScalarOrVectorComponentType(Type);
3566 if (!CompType || CompType->getOpcode() != SPIRV::OpTypeInt)
3567 return false;
3568
3569 auto IsZero = [this](Register Reg) {
3570 MachineInstr *Def = getDefInstrMaybeConstant(Reg, MRI);
3571 if (!Def)
3572 return false;
3573
3574 if (Def->getOpcode() == SPIRV::OpConstantNull)
3575 return true;
3576
3577 if (Def->getOpcode() == TargetOpcode::G_CONSTANT ||
3578 Def->getOpcode() == SPIRV::OpConstantI)
3579 return getIConstVal(Reg, MRI) == 0;
3580
3581 return false;
3582 };
3583
3584 if (IsZero(Reg))
3585 return true;
3586
3587 MachineInstr *Def = MRI->getVRegDef(Reg);
3588 if (!Def)
3589 return false;
3590
3591 if (Def->getOpcode() == TargetOpcode::G_BUILD_VECTOR ||
3592 (Def->getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS &&
3593 cast<GIntrinsic>(Def)->getIntrinsicID() ==
3594 Intrinsic::spv_const_composite)) {
3595 unsigned StartOp = Def->getOpcode() == TargetOpcode::G_BUILD_VECTOR ? 1 : 2;
3596 for (unsigned i = StartOp; i < Def->getNumOperands(); ++i) {
3597 if (!IsZero(Def->getOperand(i).getReg()))
3598 return false;
3599 }
3600 return true;
3601 }
3602
3603 return false;
3604}
3605
3606Register SPIRVInstructionSelector::buildZerosValF(SPIRVTypeInst ResType,
3607 MachineInstr &I) const {
3608 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
3609 bool ZeroAsNull = !STI.isShader();
3610 APFloat VZero = getZeroFP(GR.getTypeForSPIRVType(ResType));
3611 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3612 return GR.getOrCreateConstVector(VZero, I, ResType, TII, ZeroAsNull);
3613 return GR.getOrCreateConstFP(VZero, I, ResType, TII, ZeroAsNull);
3614}
3615
3616Register SPIRVInstructionSelector::buildOnesValF(SPIRVTypeInst ResType,
3617 MachineInstr &I) const {
3618 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
3619 bool ZeroAsNull = !STI.isShader();
3620 APFloat VOne = getOneFP(GR.getTypeForSPIRVType(ResType));
3621 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3622 return GR.getOrCreateConstVector(VOne, I, ResType, TII, ZeroAsNull);
3623 return GR.getOrCreateConstFP(VOne, I, ResType, TII, ZeroAsNull);
3624}
3625
3626Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
3627 SPIRVTypeInst ResType,
3628 MachineInstr &I) const {
3629 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
3630 APInt One =
3631 AllOnes ? APInt::getAllOnes(BitWidth) : APInt::getOneBitSet(BitWidth, 0);
3632 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3633 return GR.getOrCreateConstVector(One, I, ResType, TII);
3634 return GR.getOrCreateConstInt(One, I, ResType, TII);
3635}
3636
3637bool SPIRVInstructionSelector::selectSelect(Register ResVReg,
3638 SPIRVTypeInst ResType,
3639 MachineInstr &I) const {
3640 Register SelectFirstArg = I.getOperand(2).getReg();
3641 Register SelectSecondArg = I.getOperand(3).getReg();
3642 assert(ResType == GR.getSPIRVTypeForVReg(SelectFirstArg) &&
3643 ResType == GR.getSPIRVTypeForVReg(SelectSecondArg));
3644
3645 bool IsFloatTy =
3646 GR.isScalarOrVectorOfType(SelectFirstArg, SPIRV::OpTypeFloat);
3647 bool IsPtrTy =
3648 GR.isScalarOrVectorOfType(SelectFirstArg, SPIRV::OpTypePointer);
3649 bool IsVectorTy = GR.getSPIRVTypeForVReg(SelectFirstArg)->getOpcode() ==
3650 SPIRV::OpTypeVector;
3651
3652 bool IsScalarBool =
3653 GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool);
3654 unsigned Opcode;
3655 if (IsVectorTy) {
3656 if (IsFloatTy) {
3657 Opcode = IsScalarBool ? SPIRV::OpSelectVFSCond : SPIRV::OpSelectVFVCond;
3658 } else if (IsPtrTy) {
3659 Opcode = IsScalarBool ? SPIRV::OpSelectVPSCond : SPIRV::OpSelectVPVCond;
3660 } else {
3661 Opcode = IsScalarBool ? SPIRV::OpSelectVISCond : SPIRV::OpSelectVIVCond;
3662 }
3663 } else {
3664 if (IsFloatTy) {
3665 Opcode = IsScalarBool ? SPIRV::OpSelectSFSCond : SPIRV::OpSelectVFVCond;
3666 } else if (IsPtrTy) {
3667 Opcode = IsScalarBool ? SPIRV::OpSelectSPSCond : SPIRV::OpSelectVPVCond;
3668 } else {
3669 Opcode = IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond;
3670 }
3671 }
3672 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
3673 .addDef(ResVReg)
3674 .addUse(GR.getSPIRVTypeID(ResType))
3675 .addUse(I.getOperand(1).getReg())
3676 .addUse(SelectFirstArg)
3677 .addUse(SelectSecondArg)
3678 .constrainAllUses(TII, TRI, RBI);
3679 return true;
3680}
3681
3682// This function is used to extend a bool or a vector of bools into an integer
3683// or vector of integers.
3684bool SPIRVInstructionSelector::selectBoolToInt(Register ResVReg,
3685 SPIRVTypeInst ResType,
3686 Register BooleanVReg,
3687 MachineInstr &InsertAt,
3688 bool IsSigned) const {
3689 // To extend a bool, we need to use OpSelect between constants.
3690 Register ZeroReg = buildZerosVal(ResType, InsertAt);
3691 Register OneReg = buildOnesVal(IsSigned, ResType, InsertAt);
3692 bool IsScalarBool = GR.isScalarOfType(BooleanVReg, SPIRV::OpTypeBool);
3693 unsigned Opcode =
3694 IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond;
3695 BuildMI(*InsertAt.getParent(), InsertAt, InsertAt.getDebugLoc(),
3696 TII.get(Opcode))
3697 .addDef(ResVReg)
3698 .addUse(GR.getSPIRVTypeID(ResType))
3699 .addUse(BooleanVReg)
3700 .addUse(OneReg)
3701 .addUse(ZeroReg)
3702 .constrainAllUses(TII, TRI, RBI);
3703 return true;
3704}
3705
3706bool SPIRVInstructionSelector::selectIToF(Register ResVReg,
3707 SPIRVTypeInst ResType,
3708 MachineInstr &I, bool IsSigned,
3709 unsigned Opcode) const {
3710 Register SrcReg = I.getOperand(1).getReg();
3711 // We can convert bool value directly to float type without OpConvert*ToF,
3712 // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
3713 if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) {
3714 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
3715 SPIRVTypeInst TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII);
3716 if (ResType->getOpcode() == SPIRV::OpTypeVector) {
3717 const unsigned NumElts = ResType->getOperand(2).getImm();
3718 TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII);
3719 }
3720 SrcReg = createVirtualRegister(TmpType, &GR, MRI, MRI->getMF());
3721 selectBoolToInt(SrcReg, TmpType, I.getOperand(1).getReg(), I, false);
3722 }
3723 return selectOpWithSrcs(ResVReg, ResType, I, {SrcReg}, Opcode);
3724}
3725
3726bool SPIRVInstructionSelector::selectExt(Register ResVReg,
3727 SPIRVTypeInst ResType, MachineInstr &I,
3728 bool IsSigned) const {
3729 Register SrcReg = I.getOperand(1).getReg();
3730 if (GR.isScalarOrVectorOfType(SrcReg, SPIRV::OpTypeBool))
3731 return selectBoolToInt(ResVReg, ResType, I.getOperand(1).getReg(), I,
3732 IsSigned);
3733
3734 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(SrcReg);
3735 if (ResType == SrcType)
3736 return BuildCOPY(ResVReg, SrcReg, I);
3737
3738 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
3739 return selectUnOp(ResVReg, ResType, I, Opcode);
3740}
3741
3742bool SPIRVInstructionSelector::selectSUCmp(Register ResVReg,
3743 SPIRVTypeInst ResType,
3744 MachineInstr &I,
3745 bool IsSigned) const {
3746 MachineIRBuilder MIRBuilder(I);
3747 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
3748 MachineBasicBlock &BB = *I.getParent();
3749 // Ensure we have bool.
3750 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
3751 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
3752 if (N > 1)
3753 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, N, I, TII);
3754 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
3755 // Build less-than-equal and less-than.
3756 // TODO: replace with one-liner createVirtualRegister() from
3757 // llvm/lib/Target/SPIRV/SPIRVUtils.cpp when PR #116609 is merged.
3758 Register IsLessEqReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
3759 MRI->setType(IsLessEqReg, LLT::scalar(64));
3760 GR.assignSPIRVTypeToVReg(ResType, IsLessEqReg, MIRBuilder.getMF());
3761 BuildMI(BB, I, I.getDebugLoc(),
3762 TII.get(IsSigned ? SPIRV::OpSLessThanEqual : SPIRV::OpULessThanEqual))
3763 .addDef(IsLessEqReg)
3764 .addUse(BoolTypeReg)
3765 .addUse(I.getOperand(1).getReg())
3766 .addUse(I.getOperand(2).getReg())
3767 .constrainAllUses(TII, TRI, RBI);
3768 Register IsLessReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
3769 MRI->setType(IsLessReg, LLT::scalar(64));
3770 GR.assignSPIRVTypeToVReg(ResType, IsLessReg, MIRBuilder.getMF());
3771 BuildMI(BB, I, I.getDebugLoc(),
3772 TII.get(IsSigned ? SPIRV::OpSLessThan : SPIRV::OpULessThan))
3773 .addDef(IsLessReg)
3774 .addUse(BoolTypeReg)
3775 .addUse(I.getOperand(1).getReg())
3776 .addUse(I.getOperand(2).getReg())
3777 .constrainAllUses(TII, TRI, RBI);
3778 // Build selects.
3779 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
3780 Register NegOneOrZeroReg =
3781 MRI->createVirtualRegister(GR.getRegClass(ResType));
3782 MRI->setType(NegOneOrZeroReg, LLT::scalar(64));
3783 GR.assignSPIRVTypeToVReg(ResType, NegOneOrZeroReg, MIRBuilder.getMF());
3784 unsigned SelectOpcode =
3785 N > 1 ? SPIRV::OpSelectVIVCond : SPIRV::OpSelectSISCond;
3786 BuildMI(BB, I, I.getDebugLoc(), TII.get(SelectOpcode))
3787 .addDef(NegOneOrZeroReg)
3788 .addUse(ResTypeReg)
3789 .addUse(IsLessReg)
3790 .addUse(buildOnesVal(true, ResType, I)) // -1
3791 .addUse(buildZerosVal(ResType, I))
3792 .constrainAllUses(TII, TRI, RBI);
3793 BuildMI(BB, I, I.getDebugLoc(), TII.get(SelectOpcode))
3794 .addDef(ResVReg)
3795 .addUse(ResTypeReg)
3796 .addUse(IsLessEqReg)
3797 .addUse(NegOneOrZeroReg) // -1 or 0
3798 .addUse(buildOnesVal(false, ResType, I))
3799 .constrainAllUses(TII, TRI, RBI);
3800 return true;
3801}
3802
3803bool SPIRVInstructionSelector::selectIntToBool(Register IntReg,
3804 Register ResVReg,
3805 MachineInstr &I,
3806 SPIRVTypeInst IntTy,
3807 SPIRVTypeInst BoolTy) const {
3808 // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
3809 Register BitIntReg = createVirtualRegister(IntTy, &GR, MRI, MRI->getMF());
3810 bool IsVectorTy = IntTy->getOpcode() == SPIRV::OpTypeVector;
3811 unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
3812 Register Zero = buildZerosVal(IntTy, I);
3813 Register One = buildOnesVal(false, IntTy, I);
3814 MachineBasicBlock &BB = *I.getParent();
3815 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3816 .addDef(BitIntReg)
3817 .addUse(GR.getSPIRVTypeID(IntTy))
3818 .addUse(IntReg)
3819 .addUse(One)
3820 .constrainAllUses(TII, TRI, RBI);
3821 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
3822 .addDef(ResVReg)
3823 .addUse(GR.getSPIRVTypeID(BoolTy))
3824 .addUse(BitIntReg)
3825 .addUse(Zero)
3826 .constrainAllUses(TII, TRI, RBI);
3827 return true;
3828}
3829
3830bool SPIRVInstructionSelector::selectTrunc(Register ResVReg,
3831 SPIRVTypeInst ResType,
3832 MachineInstr &I) const {
3833 Register IntReg = I.getOperand(1).getReg();
3834 const SPIRVTypeInst ArgType = GR.getSPIRVTypeForVReg(IntReg);
3835 if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool))
3836 return selectIntToBool(IntReg, ResVReg, I, ArgType, ResType);
3837 if (ArgType == ResType)
3838 return BuildCOPY(ResVReg, IntReg, I);
3839 bool IsSigned = GR.isScalarOrVectorSigned(ResType);
3840 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
3841 return selectUnOp(ResVReg, ResType, I, Opcode);
3842}
3843
3844bool SPIRVInstructionSelector::selectConst(Register ResVReg,
3845 SPIRVTypeInst ResType,
3846 MachineInstr &I) const {
3847 unsigned Opcode = I.getOpcode();
3848 unsigned TpOpcode = ResType->getOpcode();
3849 Register Reg;
3850 if (TpOpcode == SPIRV::OpTypePointer || TpOpcode == SPIRV::OpTypeEvent) {
3851 assert(Opcode == TargetOpcode::G_CONSTANT &&
3852 I.getOperand(1).getCImm()->isZero());
3853 MachineBasicBlock &DepMBB = I.getMF()->front();
3854 MachineIRBuilder MIRBuilder(DepMBB, DepMBB.getFirstNonPHI());
3855 Reg = GR.getOrCreateConstNullPtr(MIRBuilder, ResType);
3856 } else if (Opcode == TargetOpcode::G_FCONSTANT) {
3857 Reg = GR.getOrCreateConstFP(I.getOperand(1).getFPImm()->getValue(), I,
3858 ResType, TII, !STI.isShader());
3859 } else {
3860 Reg = GR.getOrCreateConstInt(I.getOperand(1).getCImm()->getValue(), I,
3861 ResType, TII, !STI.isShader());
3862 }
3863 return Reg == ResVReg ? true : BuildCOPY(ResVReg, Reg, I);
3864}
3865
3866bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg,
3867 SPIRVTypeInst ResType,
3868 MachineInstr &I) const {
3869 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
3870 .addDef(ResVReg)
3871 .addUse(GR.getSPIRVTypeID(ResType))
3872 .constrainAllUses(TII, TRI, RBI);
3873 return true;
3874}
3875
3876bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg,
3877 SPIRVTypeInst ResType,
3878 MachineInstr &I) const {
3879 MachineBasicBlock &BB = *I.getParent();
3880 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeInsert))
3881 .addDef(ResVReg)
3882 .addUse(GR.getSPIRVTypeID(ResType))
3883 // object to insert
3884 .addUse(I.getOperand(3).getReg())
3885 // composite to insert into
3886 .addUse(I.getOperand(2).getReg());
3887 for (unsigned i = 4; i < I.getNumOperands(); i++)
3888 MIB.addImm(foldImm(I.getOperand(i), MRI));
3889 MIB.constrainAllUses(TII, TRI, RBI);
3890 return true;
3891}
3892
3893bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg,
3894 SPIRVTypeInst ResType,
3895 MachineInstr &I) const {
3896 Type *MaybeResTy = nullptr;
3897 StringRef ResName;
3898 if (GR.findValueAttrs(&I, MaybeResTy, ResName) &&
3899 MaybeResTy != GR.getTypeForSPIRVType(ResType)) {
3900 assert((!MaybeResTy || MaybeResTy->isAggregateType()) &&
3901 "Expected aggregate type for extractv instruction");
3902 ResType = GR.getOrCreateSPIRVType(MaybeResTy, I,
3903 SPIRV::AccessQualifier::ReadWrite, false);
3904 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *I.getMF());
3905 }
3906 MachineBasicBlock &BB = *I.getParent();
3907 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
3908 .addDef(ResVReg)
3909 .addUse(GR.getSPIRVTypeID(ResType))
3910 .addUse(I.getOperand(2).getReg());
3911 for (unsigned i = 3; i < I.getNumOperands(); i++)
3912 MIB.addImm(foldImm(I.getOperand(i), MRI));
3913 MIB.constrainAllUses(TII, TRI, RBI);
3914 return true;
3915}
3916
3917bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg,
3918 SPIRVTypeInst ResType,
3919 MachineInstr &I) const {
3920 if (getImm(I.getOperand(4), MRI))
3921 return selectInsertVal(ResVReg, ResType, I);
3922 MachineBasicBlock &BB = *I.getParent();
3923 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorInsertDynamic))
3924 .addDef(ResVReg)
3925 .addUse(GR.getSPIRVTypeID(ResType))
3926 .addUse(I.getOperand(2).getReg())
3927 .addUse(I.getOperand(3).getReg())
3928 .addUse(I.getOperand(4).getReg())
3929 .constrainAllUses(TII, TRI, RBI);
3930 return true;
3931}
3932
3933bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg,
3934 SPIRVTypeInst ResType,
3935 MachineInstr &I) const {
3936 if (getImm(I.getOperand(3), MRI))
3937 return selectExtractVal(ResVReg, ResType, I);
3938 MachineBasicBlock &BB = *I.getParent();
3939 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorExtractDynamic))
3940 .addDef(ResVReg)
3941 .addUse(GR.getSPIRVTypeID(ResType))
3942 .addUse(I.getOperand(2).getReg())
3943 .addUse(I.getOperand(3).getReg())
3944 .constrainAllUses(TII, TRI, RBI);
3945 return true;
3946}
3947
3948bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
3949 SPIRVTypeInst ResType,
3950 MachineInstr &I) const {
3951 const bool IsGEPInBounds = I.getOperand(2).getImm();
3952
3953 // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator only
3954 // relies on PtrAccessChain, so we'll try not to deviate. For Vulkan however,
3955 // we have to use Op[InBounds]AccessChain.
3956 const unsigned Opcode = STI.isLogicalSPIRV()
3957 ? (IsGEPInBounds ? SPIRV::OpInBoundsAccessChain
3958 : SPIRV::OpAccessChain)
3959 : (IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
3960 : SPIRV::OpPtrAccessChain);
3961
3962 auto Res = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
3963 .addDef(ResVReg)
3964 .addUse(GR.getSPIRVTypeID(ResType))
3965 // Object to get a pointer to.
3966 .addUse(I.getOperand(3).getReg());
3967 assert(
3968 (Opcode == SPIRV::OpPtrAccessChain ||
3969 Opcode == SPIRV::OpInBoundsPtrAccessChain ||
3970 (getImm(I.getOperand(4), MRI) && foldImm(I.getOperand(4), MRI) == 0)) &&
3971 "Cannot translate GEP to OpAccessChain. First index must be 0.");
3972
3973 // Adding indices.
3974 const unsigned StartingIndex =
3975 (Opcode == SPIRV::OpAccessChain || Opcode == SPIRV::OpInBoundsAccessChain)
3976 ? 5
3977 : 4;
3978 for (unsigned i = StartingIndex; i < I.getNumExplicitOperands(); ++i)
3979 Res.addUse(I.getOperand(i).getReg());
3980 Res.constrainAllUses(TII, TRI, RBI);
3981 return true;
3982}
3983
3984// Maybe wrap a value into OpSpecConstantOp
3985bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
3986 MachineInstr &I, SmallVector<Register> &CompositeArgs) const {
3987 unsigned Lim = I.getNumExplicitOperands();
3988 for (unsigned i = I.getNumExplicitDefs() + 1; i < Lim; ++i) {
3989 Register OpReg = I.getOperand(i).getReg();
3990 MachineInstr *OpDefine = MRI->getVRegDef(OpReg);
3991 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
3992 if (!OpDefine || !OpType || isConstReg(MRI, OpDefine) ||
3993 OpDefine->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
3994 OpDefine->getOpcode() == TargetOpcode::G_INTTOPTR ||
3995 GR.isAggregateType(OpType)) {
3996 // The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed
3997 // by selectAddrSpaceCast(), and G_INTTOPTR is processed by selectUnOp()
3998 CompositeArgs.push_back(OpReg);
3999 continue;
4000 }
4001 MachineFunction *MF = I.getMF();
4002 Register WrapReg = GR.find(OpDefine, MF);
4003 if (WrapReg.isValid()) {
4004 CompositeArgs.push_back(WrapReg);
4005 continue;
4006 }
4007 // Create a new register for the wrapper
4008 WrapReg = MRI->createVirtualRegister(GR.getRegClass(OpType));
4009 CompositeArgs.push_back(WrapReg);
4010 // Decorate the wrapper register and generate a new instruction
4011 MRI->setType(WrapReg, LLT::pointer(0, 64));
4012 GR.assignSPIRVTypeToVReg(OpType, WrapReg, *MF);
4013 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
4014 TII.get(SPIRV::OpSpecConstantOp))
4015 .addDef(WrapReg)
4016 .addUse(GR.getSPIRVTypeID(OpType))
4017 .addImm(static_cast<uint32_t>(SPIRV::Opcode::Bitcast))
4018 .addUse(OpReg);
4019 GR.add(OpDefine, MIB);
4020 MIB.constrainAllUses(TII, TRI, RBI);
4021 }
4022 return true;
4023}
4024
4025bool SPIRVInstructionSelector::selectDerivativeInst(
4026 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
4027 const unsigned DPdOpCode) const {
4028 // TODO: This should check specifically for Fragment Execution Model, but STI
4029 // doesn't provide that information yet. See #167562
4030 errorIfInstrOutsideShader(I);
4031
4032 // If the arg/result types are half then we need to wrap the instr in
4033 // conversions to float
4034 // This case occurs because a half arg/result is legal in HLSL but not spirv.
4035 Register SrcReg = I.getOperand(2).getReg();
4036 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(SrcReg);
4037 unsigned BitWidth = std::min(GR.getScalarOrVectorBitWidth(SrcType),
4038 GR.getScalarOrVectorBitWidth(ResType));
4039 if (BitWidth == 32)
4040 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DPdOpCode))
4041 .addDef(ResVReg)
4042 .addUse(GR.getSPIRVTypeID(ResType))
4043 .addUse(I.getOperand(2).getReg());
4044
4045 MachineIRBuilder MIRBuilder(I);
4046 unsigned componentCount = GR.getScalarOrVectorComponentCount(SrcType);
4047 SPIRVTypeInst F32ConvertTy = GR.getOrCreateSPIRVFloatType(32, I, TII);
4048 if (componentCount != 1)
4049 F32ConvertTy = GR.getOrCreateSPIRVVectorType(F32ConvertTy, componentCount,
4050 MIRBuilder, false);
4051
4052 const TargetRegisterClass *RegClass = GR.getRegClass(SrcType);
4053 Register ConvertToVReg = MRI->createVirtualRegister(RegClass);
4054 Register DpdOpVReg = MRI->createVirtualRegister(RegClass);
4055
4056 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFConvert))
4057 .addDef(ConvertToVReg)
4058 .addUse(GR.getSPIRVTypeID(F32ConvertTy))
4059 .addUse(SrcReg)
4060 .constrainAllUses(TII, TRI, RBI);
4061 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DPdOpCode))
4062 .addDef(DpdOpVReg)
4063 .addUse(GR.getSPIRVTypeID(F32ConvertTy))
4064 .addUse(ConvertToVReg)
4065 .constrainAllUses(TII, TRI, RBI);
4066 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFConvert))
4067 .addDef(ResVReg)
4068 .addUse(GR.getSPIRVTypeID(ResType))
4069 .addUse(DpdOpVReg)
4070 .constrainAllUses(TII, TRI, RBI);
4071 return true;
4072}
4073
4074bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
4075 SPIRVTypeInst ResType,
4076 MachineInstr &I) const {
4077 MachineBasicBlock &BB = *I.getParent();
4078 Intrinsic::ID IID = cast<GIntrinsic>(I).getIntrinsicID();
4079 switch (IID) {
4080 case Intrinsic::spv_load:
4081 return selectLoad(ResVReg, ResType, I);
4082 case Intrinsic::spv_store:
4083 return selectStore(I);
4084 case Intrinsic::spv_extractv:
4085 return selectExtractVal(ResVReg, ResType, I);
4086 case Intrinsic::spv_insertv:
4087 return selectInsertVal(ResVReg, ResType, I);
4088 case Intrinsic::spv_extractelt:
4089 return selectExtractElt(ResVReg, ResType, I);
4090 case Intrinsic::spv_insertelt:
4091 return selectInsertElt(ResVReg, ResType, I);
4092 case Intrinsic::spv_gep:
4093 return selectGEP(ResVReg, ResType, I);
4094 case Intrinsic::spv_bitcast: {
4095 Register OpReg = I.getOperand(2).getReg();
4096 SPIRVTypeInst OpType =
4097 OpReg.isValid() ? GR.getSPIRVTypeForVReg(OpReg) : nullptr;
4098 if (!GR.isBitcastCompatible(ResType, OpType))
4099 report_fatal_error("incompatible result and operand types in a bitcast");
4100 return selectOpWithSrcs(ResVReg, ResType, I, {OpReg}, SPIRV::OpBitcast);
4101 }
4102 case Intrinsic::spv_unref_global:
4103 case Intrinsic::spv_init_global: {
4104 MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());
4105 MachineInstr *Init = I.getNumExplicitOperands() > 2
4106 ? MRI->getVRegDef(I.getOperand(2).getReg())
4107 : nullptr;
4108 assert(MI);
4109 Register GVarVReg = MI->getOperand(0).getReg();
4110 if (!selectGlobalValue(GVarVReg, *MI, Init))
4111 return false;
4112 // We violate SSA form by inserting OpVariable and still having a gMIR
4113 // instruction %vreg = G_GLOBAL_VALUE @gvar. We need to fix this by erasing
4114 // the duplicated definition.
4115 if (MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
4117 MI->eraseFromParent();
4118 }
4119 return true;
4120 }
4121 case Intrinsic::spv_undef: {
4122 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
4123 .addDef(ResVReg)
4124 .addUse(GR.getSPIRVTypeID(ResType));
4125 MIB.constrainAllUses(TII, TRI, RBI);
4126 return true;
4127 }
4128 case Intrinsic::spv_named_boolean_spec_constant: {
4129 auto Opcode = I.getOperand(3).getImm() ? SPIRV::OpSpecConstantTrue
4130 : SPIRV::OpSpecConstantFalse;
4131
4132 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
4133 .addDef(I.getOperand(0).getReg())
4134 .addUse(GR.getSPIRVTypeID(ResType));
4135 MIB.constrainAllUses(TII, TRI, RBI);
4136 unsigned SpecId = I.getOperand(2).getImm();
4137 buildOpDecorate(I.getOperand(0).getReg(), *MIB.getInstr(), TII,
4138 SPIRV::Decoration::SpecId, {SpecId});
4139
4140 return true;
4141 }
4142 case Intrinsic::spv_const_composite: {
4143 // If no values are attached, the composite is null constant.
4144 bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
4145 SmallVector<Register> CompositeArgs;
4146 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
4147
4148 // skip type MD node we already used when generated assign.type for this
4149 if (!IsNull) {
4150 if (!wrapIntoSpecConstantOp(I, CompositeArgs))
4151 return false;
4152 MachineIRBuilder MIR(I);
4153 SmallVector<MachineInstr *, 4> Instructions = createContinuedInstructions(
4154 MIR, SPIRV::OpConstantComposite, 3,
4155 SPIRV::OpConstantCompositeContinuedINTEL, CompositeArgs, ResVReg,
4156 GR.getSPIRVTypeID(ResType));
4157 for (auto *Instr : Instructions) {
4158 Instr->setDebugLoc(I.getDebugLoc());
4160 }
4161 return true;
4162 } else {
4163 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
4164 .addDef(ResVReg)
4165 .addUse(GR.getSPIRVTypeID(ResType));
4166 MIB.constrainAllUses(TII, TRI, RBI);
4167 return true;
4168 }
4169 }
4170 case Intrinsic::spv_assign_name: {
4171 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName));
4172 MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg());
4173 for (unsigned i = I.getNumExplicitDefs() + 2;
4174 i < I.getNumExplicitOperands(); ++i) {
4175 MIB.addImm(I.getOperand(i).getImm());
4176 }
4177 MIB.constrainAllUses(TII, TRI, RBI);
4178 return true;
4179 }
4180 case Intrinsic::spv_switch: {
4181 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch));
4182 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
4183 if (I.getOperand(i).isReg())
4184 MIB.addReg(I.getOperand(i).getReg());
4185 else if (I.getOperand(i).isCImm())
4186 addNumImm(I.getOperand(i).getCImm()->getValue(), MIB);
4187 else if (I.getOperand(i).isMBB())
4188 MIB.addMBB(I.getOperand(i).getMBB());
4189 else
4190 llvm_unreachable("Unexpected OpSwitch operand");
4191 }
4192 MIB.constrainAllUses(TII, TRI, RBI);
4193 return true;
4194 }
4195 case Intrinsic::spv_loop_merge: {
4196 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopMerge));
4197 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
4198 if (I.getOperand(i).isMBB())
4199 MIB.addMBB(I.getOperand(i).getMBB());
4200 else
4201 MIB.addImm(foldImm(I.getOperand(i), MRI));
4202 }
4203 MIB.constrainAllUses(TII, TRI, RBI);
4204 return true;
4205 }
4206 case Intrinsic::spv_loop_control_intel: {
4207 auto MIB =
4208 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopControlINTEL));
4209 for (unsigned J = 1; J < I.getNumExplicitOperands(); ++J)
4210 MIB.addImm(foldImm(I.getOperand(J), MRI));
4211 MIB.constrainAllUses(TII, TRI, RBI);
4212 return true;
4213 }
4214 case Intrinsic::spv_selection_merge: {
4215 auto MIB =
4216 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSelectionMerge));
4217 assert(I.getOperand(1).isMBB() &&
4218 "operand 1 to spv_selection_merge must be a basic block");
4219 MIB.addMBB(I.getOperand(1).getMBB());
4220 MIB.addImm(getSelectionOperandForImm(I.getOperand(2).getImm()));
4221 MIB.constrainAllUses(TII, TRI, RBI);
4222 return true;
4223 }
4224 case Intrinsic::spv_cmpxchg:
4225 return selectAtomicCmpXchg(ResVReg, ResType, I);
4226 case Intrinsic::spv_unreachable:
4227 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUnreachable))
4228 .constrainAllUses(TII, TRI, RBI);
4229 return true;
4230 case Intrinsic::spv_alloca:
4231 return selectFrameIndex(ResVReg, ResType, I);
4232 case Intrinsic::spv_alloca_array:
4233 return selectAllocaArray(ResVReg, ResType, I);
4234 case Intrinsic::spv_assume:
4235 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
4236 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAssumeTrueKHR))
4237 .addUse(I.getOperand(1).getReg())
4238 .constrainAllUses(TII, TRI, RBI);
4239 return true;
4240 }
4241 break;
4242 case Intrinsic::spv_expect:
4243 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
4244 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExpectKHR))
4245 .addDef(ResVReg)
4246 .addUse(GR.getSPIRVTypeID(ResType))
4247 .addUse(I.getOperand(2).getReg())
4248 .addUse(I.getOperand(3).getReg())
4249 .constrainAllUses(TII, TRI, RBI);
4250 return true;
4251 }
4252 break;
4253 case Intrinsic::arithmetic_fence:
4254 if (STI.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence)) {
4255 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpArithmeticFenceEXT))
4256 .addDef(ResVReg)
4257 .addUse(GR.getSPIRVTypeID(ResType))
4258 .addUse(I.getOperand(2).getReg())
4259 .constrainAllUses(TII, TRI, RBI);
4260 return true;
4261 } else
4262 return BuildCOPY(ResVReg, I.getOperand(2).getReg(), I);
4263 break;
4264 case Intrinsic::spv_thread_id:
4265 // The HLSL SV_DispatchThreadID semantic is lowered to llvm.spv.thread.id
4266 // intrinsic in LLVM IR for SPIR-V backend.
4267 //
4268 // In SPIR-V backend, llvm.spv.thread.id is now correctly translated to a
4269 // `GlobalInvocationId` builtin variable
4270 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalInvocationId, ResVReg,
4271 ResType, I);
4272 case Intrinsic::spv_thread_id_in_group:
4273 // The HLSL SV_GroupThreadId semantic is lowered to
4274 // llvm.spv.thread.id.in.group intrinsic in LLVM IR for SPIR-V backend.
4275 //
4276 // In SPIR-V backend, llvm.spv.thread.id.in.group is now correctly
4277 // translated to a `LocalInvocationId` builtin variable
4278 return loadVec3BuiltinInputID(SPIRV::BuiltIn::LocalInvocationId, ResVReg,
4279 ResType, I);
4280 case Intrinsic::spv_group_id:
4281 // The HLSL SV_GroupId semantic is lowered to
4282 // llvm.spv.group.id intrinsic in LLVM IR for SPIR-V backend.
4283 //
4284 // In SPIR-V backend, llvm.spv.group.id is now translated to a `WorkgroupId`
4285 // builtin variable
4286 return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupId, ResVReg, ResType,
4287 I);
4288 case Intrinsic::spv_flattened_thread_id_in_group:
4289 // The HLSL SV_GroupIndex semantic is lowered to
4290 // llvm.spv.flattened.thread.id.in.group() intrinsic in LLVM IR for SPIR-V
4291 // backend.
4292 //
4293 // In SPIR-V backend, llvm.spv.flattened.thread.id.in.group is translated to
4294 // a `LocalInvocationIndex` builtin variable
4295 return loadBuiltinInputID(SPIRV::BuiltIn::LocalInvocationIndex, ResVReg,
4296 ResType, I);
4297 case Intrinsic::spv_workgroup_size:
4298 return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupSize, ResVReg,
4299 ResType, I);
4300 case Intrinsic::spv_global_size:
4301 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalSize, ResVReg, ResType,
4302 I);
4303 case Intrinsic::spv_global_offset:
4304 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalOffset, ResVReg,
4305 ResType, I);
4306 case Intrinsic::spv_num_workgroups:
4307 return loadVec3BuiltinInputID(SPIRV::BuiltIn::NumWorkgroups, ResVReg,
4308 ResType, I);
4309 case Intrinsic::spv_subgroup_size:
4310 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupSize, ResVReg, ResType,
4311 I);
4312 case Intrinsic::spv_num_subgroups:
4313 return loadBuiltinInputID(SPIRV::BuiltIn::NumSubgroups, ResVReg, ResType,
4314 I);
4315 case Intrinsic::spv_subgroup_id:
4316 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupId, ResVReg, ResType, I);
4317 case Intrinsic::spv_subgroup_local_invocation_id:
4318 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupLocalInvocationId,
4319 ResVReg, ResType, I);
4320 case Intrinsic::spv_subgroup_max_size:
4321 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupMaxSize, ResVReg, ResType,
4322 I);
4323 case Intrinsic::spv_fdot:
4324 return selectFloatDot(ResVReg, ResType, I);
4325 case Intrinsic::spv_udot:
4326 case Intrinsic::spv_sdot:
4327 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
4328 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
4329 return selectIntegerDot(ResVReg, ResType, I,
4330 /*Signed=*/IID == Intrinsic::spv_sdot);
4331 return selectIntegerDotExpansion(ResVReg, ResType, I);
4332 case Intrinsic::spv_dot4add_i8packed:
4333 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
4334 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
4335 return selectDot4AddPacked<true>(ResVReg, ResType, I);
4336 return selectDot4AddPackedExpansion<true>(ResVReg, ResType, I);
4337 case Intrinsic::spv_dot4add_u8packed:
4338 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
4339 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
4340 return selectDot4AddPacked<false>(ResVReg, ResType, I);
4341 return selectDot4AddPackedExpansion<false>(ResVReg, ResType, I);
4342 case Intrinsic::spv_all:
4343 return selectAll(ResVReg, ResType, I);
4344 case Intrinsic::spv_any:
4345 return selectAny(ResVReg, ResType, I);
4346 case Intrinsic::spv_cross:
4347 return selectExtInst(ResVReg, ResType, I, CL::cross, GL::Cross);
4348 case Intrinsic::spv_distance:
4349 return selectExtInst(ResVReg, ResType, I, CL::distance, GL::Distance);
4350 case Intrinsic::spv_lerp:
4351 return selectExtInst(ResVReg, ResType, I, CL::mix, GL::FMix);
4352 case Intrinsic::spv_length:
4353 return selectExtInst(ResVReg, ResType, I, CL::length, GL::Length);
4354 case Intrinsic::spv_degrees:
4355 return selectExtInst(ResVReg, ResType, I, CL::degrees, GL::Degrees);
4356 case Intrinsic::spv_faceforward:
4357 return selectExtInst(ResVReg, ResType, I, GL::FaceForward);
4358 case Intrinsic::spv_frac:
4359 return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
4360 case Intrinsic::spv_isinf:
4361 return selectOpIsInf(ResVReg, ResType, I);
4362 case Intrinsic::spv_isnan:
4363 return selectOpIsNan(ResVReg, ResType, I);
4364 case Intrinsic::spv_normalize:
4365 return selectExtInst(ResVReg, ResType, I, CL::normalize, GL::Normalize);
4366 case Intrinsic::spv_refract:
4367 return selectExtInst(ResVReg, ResType, I, GL::Refract);
4368 case Intrinsic::spv_reflect:
4369 return selectExtInst(ResVReg, ResType, I, GL::Reflect);
4370 case Intrinsic::spv_rsqrt:
4371 return selectExtInst(ResVReg, ResType, I, CL::rsqrt, GL::InverseSqrt);
4372 case Intrinsic::spv_sign:
4373 return selectSign(ResVReg, ResType, I);
4374 case Intrinsic::spv_smoothstep:
4375 return selectExtInst(ResVReg, ResType, I, CL::smoothstep, GL::SmoothStep);
4376 case Intrinsic::spv_firstbituhigh: // There is no CL equivalent of FindUMsb
4377 return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/false);
4378 case Intrinsic::spv_firstbitshigh: // There is no CL equivalent of FindSMsb
4379 return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/true);
4380 case Intrinsic::spv_firstbitlow: // There is no CL equivlent of FindILsb
4381 return selectFirstBitLow(ResVReg, ResType, I);
4382 case Intrinsic::spv_group_memory_barrier_with_group_sync: {
4383 Register MemSemReg =
4384 buildI32Constant(SPIRV::MemorySemantics::SequentiallyConsistent, I);
4385 Register ScopeReg = buildI32Constant(SPIRV::Scope::Workgroup, I);
4386 MachineBasicBlock &BB = *I.getParent();
4387 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpControlBarrier))
4388 .addUse(ScopeReg)
4389 .addUse(ScopeReg)
4390 .addUse(MemSemReg)
4391 .constrainAllUses(TII, TRI, RBI);
4392 return true;
4393 }
4394 case Intrinsic::spv_generic_cast_to_ptr_explicit: {
4395 Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 1).getReg();
4396 SPIRV::StorageClass::StorageClass ResSC =
4397 GR.getPointerStorageClass(ResType);
4398 if (!isGenericCastablePtr(ResSC))
4399 report_fatal_error("The target storage class is not castable from the "
4400 "Generic storage class");
4401 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpGenericCastToPtrExplicit))
4402 .addDef(ResVReg)
4403 .addUse(GR.getSPIRVTypeID(ResType))
4404 .addUse(PtrReg)
4405 .addImm(ResSC)
4406 .constrainAllUses(TII, TRI, RBI);
4407 return true;
4408 }
4409 case Intrinsic::spv_lifetime_start:
4410 case Intrinsic::spv_lifetime_end: {
4411 unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
4412 : SPIRV::OpLifetimeStop;
4413 int64_t Size = I.getOperand(I.getNumExplicitDefs() + 1).getImm();
4414 Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 2).getReg();
4415 if (Size == -1)
4416 Size = 0;
4417 BuildMI(BB, I, I.getDebugLoc(), TII.get(Op))
4418 .addUse(PtrReg)
4419 .addImm(Size)
4420 .constrainAllUses(TII, TRI, RBI);
4421 return true;
4422 }
4423 case Intrinsic::spv_saturate:
4424 return selectSaturate(ResVReg, ResType, I);
4425 case Intrinsic::spv_nclamp:
4426 return selectExtInst(ResVReg, ResType, I, CL::fclamp, GL::NClamp);
4427 case Intrinsic::spv_uclamp:
4428 return selectExtInst(ResVReg, ResType, I, CL::u_clamp, GL::UClamp);
4429 case Intrinsic::spv_sclamp:
4430 return selectExtInst(ResVReg, ResType, I, CL::s_clamp, GL::SClamp);
4431 case Intrinsic::spv_subgroup_prefix_bit_count:
4432 return selectWavePrefixBitCount(ResVReg, ResType, I);
4433 case Intrinsic::spv_wave_active_countbits:
4434 return selectWaveActiveCountBits(ResVReg, ResType, I);
4435 case Intrinsic::spv_wave_all_equal:
4436 return selectWaveActiveAllEqual(ResVReg, ResType, I);
4437 case Intrinsic::spv_wave_all:
4438 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAll);
4439 case Intrinsic::spv_wave_any:
4440 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAny);
4441 case Intrinsic::spv_subgroup_ballot:
4442 return selectWaveOpInst(ResVReg, ResType, I,
4443 SPIRV::OpGroupNonUniformBallot);
4444 case Intrinsic::spv_wave_is_first_lane:
4445 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformElect);
4446 case Intrinsic::spv_wave_reduce_or:
4447 return selectWaveReduceOp(ResVReg, ResType, I,
4448 SPIRV::OpGroupNonUniformBitwiseOr);
4449 case Intrinsic::spv_wave_reduce_xor:
4450 return selectWaveReduceOp(ResVReg, ResType, I,
4451 SPIRV::OpGroupNonUniformBitwiseXor);
4452 case Intrinsic::spv_wave_reduce_umax:
4453 return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ true);
4454 case Intrinsic::spv_wave_reduce_max:
4455 return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ false);
4456 case Intrinsic::spv_wave_reduce_umin:
4457 return selectWaveReduceMin(ResVReg, ResType, I, /*IsUnsigned*/ true);
4458 case Intrinsic::spv_wave_reduce_min:
4459 return selectWaveReduceMin(ResVReg, ResType, I, /*IsUnsigned*/ false);
4460 case Intrinsic::spv_wave_reduce_sum:
4461 return selectWaveReduceSum(ResVReg, ResType, I);
4462 case Intrinsic::spv_wave_product:
4463 return selectWaveReduceProduct(ResVReg, ResType, I);
4464 case Intrinsic::spv_wave_readlane:
4465 return selectWaveOpInst(ResVReg, ResType, I,
4466 SPIRV::OpGroupNonUniformShuffle);
4467 case Intrinsic::spv_wave_prefix_sum:
4468 return selectWaveExclusiveScanSum(ResVReg, ResType, I);
4469 case Intrinsic::spv_wave_prefix_product:
4470 return selectWaveExclusiveScanProduct(ResVReg, ResType, I);
4471 case Intrinsic::spv_quad_read_across_x: {
4472 return selectQuadSwap(ResVReg, ResType, I, /*Direction*/ 0);
4473 }
4474 case Intrinsic::spv_step:
4475 return selectExtInst(ResVReg, ResType, I, CL::step, GL::Step);
4476 case Intrinsic::spv_radians:
4477 return selectExtInst(ResVReg, ResType, I, CL::radians, GL::Radians);
4478 // Discard intrinsics which we do not expect to actually represent code after
4479 // lowering or intrinsics which are not implemented but should not crash when
4480 // found in a customer's LLVM IR input.
4481 case Intrinsic::instrprof_increment:
4482 case Intrinsic::instrprof_increment_step:
4483 case Intrinsic::instrprof_value_profile:
4484 break;
4485 // Discard internal intrinsics.
4486 case Intrinsic::spv_value_md:
4487 break;
4488 case Intrinsic::spv_resource_handlefrombinding: {
4489 return selectHandleFromBinding(ResVReg, ResType, I);
4490 }
4491 case Intrinsic::spv_resource_counterhandlefrombinding:
4492 return selectCounterHandleFromBinding(ResVReg, ResType, I);
4493 case Intrinsic::spv_resource_updatecounter:
4494 return selectUpdateCounter(ResVReg, ResType, I);
4495 case Intrinsic::spv_resource_store_typedbuffer: {
4496 return selectImageWriteIntrinsic(I);
4497 }
4498 case Intrinsic::spv_resource_load_typedbuffer: {
4499 return selectReadImageIntrinsic(ResVReg, ResType, I);
4500 }
4501 case Intrinsic::spv_resource_load_level: {
4502 return selectLoadLevelIntrinsic(ResVReg, ResType, I);
4503 }
4504 case Intrinsic::spv_resource_sample:
4505 case Intrinsic::spv_resource_sample_clamp:
4506 return selectSampleBasicIntrinsic(ResVReg, ResType, I);
4507 case Intrinsic::spv_resource_samplebias:
4508 case Intrinsic::spv_resource_samplebias_clamp:
4509 return selectSampleBiasIntrinsic(ResVReg, ResType, I);
4510 case Intrinsic::spv_resource_samplegrad:
4511 case Intrinsic::spv_resource_samplegrad_clamp:
4512 return selectSampleGradIntrinsic(ResVReg, ResType, I);
4513 case Intrinsic::spv_resource_samplelevel:
4514 return selectSampleLevelIntrinsic(ResVReg, ResType, I);
4515 case Intrinsic::spv_resource_samplecmp:
4516 case Intrinsic::spv_resource_samplecmp_clamp:
4517 return selectSampleCmpIntrinsic(ResVReg, ResType, I);
4518 case Intrinsic::spv_resource_samplecmplevelzero:
4519 return selectSampleCmpLevelZeroIntrinsic(ResVReg, ResType, I);
4520 case Intrinsic::spv_resource_gather:
4521 case Intrinsic::spv_resource_gather_cmp:
4522 return selectGatherIntrinsic(ResVReg, ResType, I);
4523 case Intrinsic::spv_resource_getpointer: {
4524 return selectResourceGetPointer(ResVReg, ResType, I);
4525 }
4526 case Intrinsic::spv_pushconstant_getpointer: {
4527 return selectPushConstantGetPointer(ResVReg, ResType, I);
4528 }
4529 case Intrinsic::spv_discard: {
4530 return selectDiscard(ResVReg, ResType, I);
4531 }
4532 case Intrinsic::spv_resource_nonuniformindex: {
4533 return selectResourceNonUniformIndex(ResVReg, ResType, I);
4534 }
4535 case Intrinsic::spv_unpackhalf2x16: {
4536 return selectExtInst(ResVReg, ResType, I, GL::UnpackHalf2x16);
4537 }
4538 case Intrinsic::spv_packhalf2x16: {
4539 return selectExtInst(ResVReg, ResType, I, GL::PackHalf2x16);
4540 }
4541 case Intrinsic::spv_ddx:
4542 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdx);
4543 case Intrinsic::spv_ddy:
4544 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdy);
4545 case Intrinsic::spv_ddx_coarse:
4546 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxCoarse);
4547 case Intrinsic::spv_ddy_coarse:
4548 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
4549 case Intrinsic::spv_ddx_fine:
4550 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxFine);
4551 case Intrinsic::spv_ddy_fine:
4552 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyFine);
4553 case Intrinsic::spv_fwidth:
4554 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpFwidth);
4555 case Intrinsic::spv_masked_gather:
4556 if (STI.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter))
4557 return selectMaskedGather(ResVReg, ResType, I);
4558 return diagnoseUnsupported(
4559 I, "llvm.masked.gather requires SPV_INTEL_masked_gather_scatter");
4560 case Intrinsic::spv_masked_scatter:
4561 if (STI.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter))
4562 return selectMaskedScatter(I);
4563 return diagnoseUnsupported(
4564 I, "llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter");
4565 default: {
4566 std::string DiagMsg;
4567 raw_string_ostream OS(DiagMsg);
4568 I.print(OS);
4569 DiagMsg = "Intrinsic selection not implemented: " + DiagMsg;
4570 report_fatal_error(DiagMsg.c_str(), false);
4571 }
4572 }
4573 return true;
4574}
4575
4576bool SPIRVInstructionSelector::selectHandleFromBinding(Register &ResVReg,
4577 SPIRVTypeInst ResType,
4578 MachineInstr &I) const {
4579 // The images need to be loaded in the same basic block as their use. We defer
4580 // loading the image to the intrinsic that uses it.
4581 if (ResType->getOpcode() == SPIRV::OpTypeImage)
4582 return true;
4583
4584 return loadHandleBeforePosition(ResVReg, GR.getSPIRVTypeForVReg(ResVReg),
4585 *cast<GIntrinsic>(&I), I);
4586}
4587
4588bool SPIRVInstructionSelector::selectCounterHandleFromBinding(
4589 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4590 auto &Intr = cast<GIntrinsic>(I);
4591 assert(Intr.getIntrinsicID() ==
4592 Intrinsic::spv_resource_counterhandlefrombinding);
4593
4594 // Extract information from the intrinsic call.
4595 Register MainHandleReg = Intr.getOperand(2).getReg();
4596 auto *MainHandleDef = cast<GIntrinsic>(getVRegDef(*MRI, MainHandleReg));
4597 assert(MainHandleDef->getIntrinsicID() ==
4598 Intrinsic::spv_resource_handlefrombinding);
4599
4600 uint32_t Set = getIConstVal(Intr.getOperand(4).getReg(), MRI);
4601 uint32_t Binding = getIConstVal(Intr.getOperand(3).getReg(), MRI);
4602 uint32_t ArraySize = getIConstVal(MainHandleDef->getOperand(4).getReg(), MRI);
4603 Register IndexReg = MainHandleDef->getOperand(5).getReg();
4604 std::string CounterName =
4605 getStringValueFromReg(MainHandleDef->getOperand(6).getReg(), *MRI) +
4606 ".counter";
4607
4608 // Create the counter variable.
4609 MachineIRBuilder MIRBuilder(I);
4610 Register CounterVarReg =
4611 buildPointerToResource(SPIRVTypeInst(GR.getPointeeType(ResType)),
4612 GR.getPointerStorageClass(ResType), Set, Binding,
4613 ArraySize, IndexReg, CounterName, MIRBuilder);
4614
4615 return BuildCOPY(ResVReg, CounterVarReg, I);
4616}
4617
4618bool SPIRVInstructionSelector::selectUpdateCounter(Register &ResVReg,
4619 SPIRVTypeInst ResType,
4620 MachineInstr &I) const {
4621 auto &Intr = cast<GIntrinsic>(I);
4622 assert(Intr.getIntrinsicID() == Intrinsic::spv_resource_updatecounter);
4623
4624 Register CounterHandleReg = Intr.getOperand(2).getReg();
4625 Register IncrReg = Intr.getOperand(3).getReg();
4626
4627 // The counter handle is a pointer to the counter variable (which is a struct
4628 // containing an i32). We need to get a pointer to that i32 member to do the
4629 // atomic operation.
4630#ifndef NDEBUG
4631 SPIRVTypeInst CounterVarType = GR.getSPIRVTypeForVReg(CounterHandleReg);
4632 SPIRVTypeInst CounterVarPointeeType = GR.getPointeeType(CounterVarType);
4633 assert(CounterVarPointeeType &&
4634 CounterVarPointeeType->getOpcode() == SPIRV::OpTypeStruct &&
4635 "Counter variable must be a struct");
4636 assert(GR.getPointerStorageClass(CounterVarType) ==
4637 SPIRV::StorageClass::StorageBuffer &&
4638 "Counter variable must be in the storage buffer storage class");
4639 assert(CounterVarPointeeType->getNumOperands() == 2 &&
4640 "Counter variable must have exactly 1 member in the struct");
4641 const SPIRVTypeInst MemberType =
4642 GR.getSPIRVTypeForVReg(CounterVarPointeeType->getOperand(1).getReg());
4643 assert(MemberType->getOpcode() == SPIRV::OpTypeInt &&
4644 "Counter variable struct must have a single i32 member");
4645#endif
4646
4647 // The struct has a single i32 member.
4648 MachineIRBuilder MIRBuilder(I);
4649 const Type *LLVMIntType =
4650 Type::getInt32Ty(I.getMF()->getFunction().getContext());
4651
4652 SPIRVTypeInst IntPtrType = GR.getOrCreateSPIRVPointerType(
4653 LLVMIntType, MIRBuilder, SPIRV::StorageClass::StorageBuffer);
4654
4655 Register Zero = buildI32Constant(0, I);
4656
4657 Register PtrToCounter =
4658 MRI->createVirtualRegister(GR.getRegClass(IntPtrType));
4659 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain))
4660 .addDef(PtrToCounter)
4661 .addUse(GR.getSPIRVTypeID(IntPtrType))
4662 .addUse(CounterHandleReg)
4663 .addUse(Zero)
4664 .constrainAllUses(TII, TRI, RBI);
4665
4666 // For UAV/SSBO counters, the scope is Device. The counter variable is not
4667 // used as a flag. So the memory semantics can be None.
4668 Register Scope = buildI32Constant(SPIRV::Scope::Device, I);
4669 Register Semantics = buildI32Constant(SPIRV::MemorySemantics::None, I);
4670
4671 int64_t IncrVal = getIConstValSext(IncrReg, MRI);
4672 Register Incr = buildI32Constant(static_cast<uint32_t>(IncrVal), I);
4673
4674 Register AtomicRes = MRI->createVirtualRegister(GR.getRegClass(ResType));
4675 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAtomicIAdd))
4676 .addDef(AtomicRes)
4677 .addUse(GR.getSPIRVTypeID(ResType))
4678 .addUse(PtrToCounter)
4679 .addUse(Scope)
4680 .addUse(Semantics)
4681 .addUse(Incr)
4682 .constrainAllUses(TII, TRI, RBI);
4683 if (IncrVal >= 0) {
4684 return BuildCOPY(ResVReg, AtomicRes, I);
4685 }
4686
4687 // In HLSL, IncrementCounter returns the value *before* the increment, while
4688 // DecrementCounter returns the value *after* the decrement. Both are lowered
4689 // to the same atomic intrinsic which returns the value *before* the
4690 // operation. So for decrements (negative IncrVal), we must subtract the
4691 // increment value from the result to get the post-decrement value.
4692 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
4693 .addDef(ResVReg)
4694 .addUse(GR.getSPIRVTypeID(ResType))
4695 .addUse(AtomicRes)
4696 .addUse(Incr)
4697 .constrainAllUses(TII, TRI, RBI);
4698 return true;
4699}
4700bool SPIRVInstructionSelector::selectReadImageIntrinsic(Register &ResVReg,
4701 SPIRVTypeInst ResType,
4702 MachineInstr &I) const {
4703
4704 // If the load of the image is in a different basic block, then
4705 // this will generate invalid code. A proper solution is to move
4706 // the OpLoad from selectHandleFromBinding here. However, to do
4707 // that we will need to change the return type of the intrinsic.
4708 // We will do that when we can, but for now trying to move forward with other
4709 // issues.
4710 Register ImageReg = I.getOperand(2).getReg();
4711 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
4712 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
4713 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
4714 *ImageDef, I)) {
4715 return false;
4716 }
4717
4718 Register IdxReg = I.getOperand(3).getReg();
4719 DebugLoc Loc = I.getDebugLoc();
4720 MachineInstr &Pos = I;
4721
4722 return generateImageReadOrFetch(ResVReg, ResType, NewImageReg, IdxReg, Loc,
4723 Pos);
4724}
4725
4726bool SPIRVInstructionSelector::generateSampleImage(
4727 Register ResVReg, SPIRVTypeInst ResType, Register ImageReg,
4728 Register SamplerReg, Register CoordinateReg, const ImageOperands &ImOps,
4729 DebugLoc Loc, MachineInstr &Pos) const {
4730 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
4731 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
4732 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
4733 *ImageDef, Pos)) {
4734 return false;
4735 }
4736
4737 auto *SamplerDef = cast<GIntrinsic>(getVRegDef(*MRI, SamplerReg));
4738 Register NewSamplerReg =
4739 MRI->createVirtualRegister(MRI->getRegClass(SamplerReg));
4740 if (!loadHandleBeforePosition(NewSamplerReg,
4741 GR.getSPIRVTypeForVReg(SamplerReg), *SamplerDef,
4742 Pos)) {
4743 return false;
4744 }
4745
4746 MachineIRBuilder MIRBuilder(Pos);
4747 SPIRVTypeInst SampledImageType = GR.getOrCreateOpTypeSampledImage(
4748 GR.getSPIRVTypeForVReg(ImageReg), MIRBuilder);
4749 Register SampledImageReg =
4750 MRI->createVirtualRegister(GR.getRegClass(SampledImageType));
4751
4752 BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpSampledImage))
4753 .addDef(SampledImageReg)
4754 .addUse(GR.getSPIRVTypeID(SampledImageType))
4755 .addUse(NewImageReg)
4756 .addUse(NewSamplerReg)
4757 .constrainAllUses(TII, TRI, RBI);
4758
4759 bool IsExplicitLod = ImOps.GradX.has_value() || ImOps.GradY.has_value() ||
4760 ImOps.Lod.has_value();
4761 unsigned Opcode = IsExplicitLod ? SPIRV::OpImageSampleExplicitLod
4762 : SPIRV::OpImageSampleImplicitLod;
4763 if (ImOps.Compare)
4764 Opcode = IsExplicitLod ? SPIRV::OpImageSampleDrefExplicitLod
4765 : SPIRV::OpImageSampleDrefImplicitLod;
4766
4767 auto MIB = BuildMI(*Pos.getParent(), Pos, Loc, TII.get(Opcode))
4768 .addDef(ResVReg)
4769 .addUse(GR.getSPIRVTypeID(ResType))
4770 .addUse(SampledImageReg)
4771 .addUse(CoordinateReg);
4772
4773 if (ImOps.Compare)
4774 MIB.addUse(*ImOps.Compare);
4775
4776 uint32_t ImageOperands = 0;
4777 if (ImOps.Bias)
4778 ImageOperands |= SPIRV::ImageOperand::Bias;
4779 if (ImOps.Lod)
4780 ImageOperands |= SPIRV::ImageOperand::Lod;
4781 if (ImOps.GradX && ImOps.GradY)
4782 ImageOperands |= SPIRV::ImageOperand::Grad;
4783 if (ImOps.Offset && !isScalarOrVectorIntConstantZero(*ImOps.Offset)) {
4784 if (isConstReg(MRI, *ImOps.Offset))
4785 ImageOperands |= SPIRV::ImageOperand::ConstOffset;
4786 else {
4787 Pos.emitGenericError(
4788 "Non-constant offsets are not supported in sample instructions.");
4789 }
4790 }
4791 if (ImOps.MinLod)
4792 ImageOperands |= SPIRV::ImageOperand::MinLod;
4793
4794 if (ImageOperands != 0) {
4795 MIB.addImm(ImageOperands);
4796 if (ImageOperands & SPIRV::ImageOperand::Bias)
4797 MIB.addUse(*ImOps.Bias);
4798 if (ImageOperands & SPIRV::ImageOperand::Lod)
4799 MIB.addUse(*ImOps.Lod);
4800 if (ImageOperands & SPIRV::ImageOperand::Grad) {
4801 MIB.addUse(*ImOps.GradX);
4802 MIB.addUse(*ImOps.GradY);
4803 }
4804 if (ImageOperands &
4805 (SPIRV::ImageOperand::ConstOffset | SPIRV::ImageOperand::Offset))
4806 MIB.addUse(*ImOps.Offset);
4807 if (ImageOperands & SPIRV::ImageOperand::MinLod)
4808 MIB.addUse(*ImOps.MinLod);
4809 }
4810
4811 MIB.constrainAllUses(TII, TRI, RBI);
4812 return true;
4813}
4814
4815bool SPIRVInstructionSelector::selectSampleBasicIntrinsic(
4816 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4817 Register ImageReg = I.getOperand(2).getReg();
4818 Register SamplerReg = I.getOperand(3).getReg();
4819 Register CoordinateReg = I.getOperand(4).getReg();
4820 ImageOperands ImOps;
4821 if (I.getNumOperands() > 5)
4822 ImOps.Offset = I.getOperand(5).getReg();
4823 if (I.getNumOperands() > 6)
4824 ImOps.MinLod = I.getOperand(6).getReg();
4825 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4826 CoordinateReg, ImOps, I.getDebugLoc(), I);
4827}
4828
4829bool SPIRVInstructionSelector::selectSampleBiasIntrinsic(
4830 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4831 Register ImageReg = I.getOperand(2).getReg();
4832 Register SamplerReg = I.getOperand(3).getReg();
4833 Register CoordinateReg = I.getOperand(4).getReg();
4834 ImageOperands ImOps;
4835 ImOps.Bias = I.getOperand(5).getReg();
4836 if (I.getNumOperands() > 6)
4837 ImOps.Offset = I.getOperand(6).getReg();
4838 if (I.getNumOperands() > 7)
4839 ImOps.MinLod = I.getOperand(7).getReg();
4840 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4841 CoordinateReg, ImOps, I.getDebugLoc(), I);
4842}
4843
4844bool SPIRVInstructionSelector::selectSampleGradIntrinsic(
4845 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4846 Register ImageReg = I.getOperand(2).getReg();
4847 Register SamplerReg = I.getOperand(3).getReg();
4848 Register CoordinateReg = I.getOperand(4).getReg();
4849 ImageOperands ImOps;
4850 ImOps.GradX = I.getOperand(5).getReg();
4851 ImOps.GradY = I.getOperand(6).getReg();
4852 if (I.getNumOperands() > 7)
4853 ImOps.Offset = I.getOperand(7).getReg();
4854 if (I.getNumOperands() > 8)
4855 ImOps.MinLod = I.getOperand(8).getReg();
4856 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4857 CoordinateReg, ImOps, I.getDebugLoc(), I);
4858}
4859
4860bool SPIRVInstructionSelector::selectSampleLevelIntrinsic(
4861 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4862 Register ImageReg = I.getOperand(2).getReg();
4863 Register SamplerReg = I.getOperand(3).getReg();
4864 Register CoordinateReg = I.getOperand(4).getReg();
4865 ImageOperands ImOps;
4866 ImOps.Lod = I.getOperand(5).getReg();
4867 if (I.getNumOperands() > 6)
4868 ImOps.Offset = I.getOperand(6).getReg();
4869 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4870 CoordinateReg, ImOps, I.getDebugLoc(), I);
4871}
4872
4873bool SPIRVInstructionSelector::selectSampleCmpIntrinsic(Register &ResVReg,
4874 SPIRVTypeInst ResType,
4875 MachineInstr &I) const {
4876 Register ImageReg = I.getOperand(2).getReg();
4877 Register SamplerReg = I.getOperand(3).getReg();
4878 Register CoordinateReg = I.getOperand(4).getReg();
4879 ImageOperands ImOps;
4880 ImOps.Compare = I.getOperand(5).getReg();
4881 if (I.getNumOperands() > 6)
4882 ImOps.Offset = I.getOperand(6).getReg();
4883 if (I.getNumOperands() > 7)
4884 ImOps.MinLod = I.getOperand(7).getReg();
4885 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4886 CoordinateReg, ImOps, I.getDebugLoc(), I);
4887}
4888
4889bool SPIRVInstructionSelector::selectLoadLevelIntrinsic(Register &ResVReg,
4890 SPIRVTypeInst ResType,
4891 MachineInstr &I) const {
4892 Register ImageReg = I.getOperand(2).getReg();
4893 Register CoordinateReg = I.getOperand(3).getReg();
4894 Register LodReg = I.getOperand(4).getReg();
4895
4896 ImageOperands ImOps;
4897 ImOps.Lod = LodReg;
4898 if (I.getNumOperands() > 5)
4899 ImOps.Offset = I.getOperand(5).getReg();
4900
4901 auto *ImageDef = dyn_cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
4902 if (!ImageDef)
4903 return false;
4904
4905 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
4906 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
4907 *ImageDef, I)) {
4908 return false;
4909 }
4910
4911 return generateImageReadOrFetch(ResVReg, ResType, NewImageReg, CoordinateReg,
4912 I.getDebugLoc(), I, &ImOps);
4913}
4914
4915bool SPIRVInstructionSelector::selectSampleCmpLevelZeroIntrinsic(
4916 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4917 Register ImageReg = I.getOperand(2).getReg();
4918 Register SamplerReg = I.getOperand(3).getReg();
4919 Register CoordinateReg = I.getOperand(4).getReg();
4920 ImageOperands ImOps;
4921 ImOps.Compare = I.getOperand(5).getReg();
4922 if (I.getNumOperands() > 6)
4923 ImOps.Offset = I.getOperand(6).getReg();
4924 SPIRVTypeInst FloatTy = GR.getOrCreateSPIRVFloatType(32, I, TII);
4925 ImOps.Lod = GR.getOrCreateConstFP(APFloat(0.0f), I, FloatTy, TII);
4926 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4927 CoordinateReg, ImOps, I.getDebugLoc(), I);
4928}
4929
4930bool SPIRVInstructionSelector::selectGatherIntrinsic(Register &ResVReg,
4931 SPIRVTypeInst ResType,
4932 MachineInstr &I) const {
4933 Register ImageReg = I.getOperand(2).getReg();
4934 Register SamplerReg = I.getOperand(3).getReg();
4935 Register CoordinateReg = I.getOperand(4).getReg();
4936 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(ImageReg);
4937 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
4938 "ImageReg is not an image type.");
4939
4940 Register ComponentOrCompareReg;
4941 Register OffsetReg;
4942
4943 ComponentOrCompareReg = I.getOperand(5).getReg();
4944 OffsetReg = I.getOperand(6).getReg();
4945 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
4946 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
4947 if (!loadHandleBeforePosition(NewImageReg, ImageType, *ImageDef, I)) {
4948 return false;
4949 }
4950
4951 auto Dim = static_cast<SPIRV::Dim::Dim>(ImageType->getOperand(2).getImm());
4952 if (Dim != SPIRV::Dim::DIM_2D && Dim != SPIRV::Dim::DIM_Cube &&
4953 Dim != SPIRV::Dim::DIM_Rect) {
4954 I.emitGenericError(
4955 "Gather operations are only supported for 2D, Cube, and Rect images.");
4956 return false;
4957 }
4958
4959 auto *SamplerDef = cast<GIntrinsic>(getVRegDef(*MRI, SamplerReg));
4960 Register NewSamplerReg =
4961 MRI->createVirtualRegister(MRI->getRegClass(SamplerReg));
4962 if (!loadHandleBeforePosition(
4963 NewSamplerReg, GR.getSPIRVTypeForVReg(SamplerReg), *SamplerDef, I)) {
4964 return false;
4965 }
4966
4967 MachineIRBuilder MIRBuilder(I);
4968 SPIRVTypeInst SampledImageType =
4969 GR.getOrCreateOpTypeSampledImage(ImageType, MIRBuilder);
4970 Register SampledImageReg =
4971 MRI->createVirtualRegister(GR.getRegClass(SampledImageType));
4972
4973 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpSampledImage))
4974 .addDef(SampledImageReg)
4975 .addUse(GR.getSPIRVTypeID(SampledImageType))
4976 .addUse(NewImageReg)
4977 .addUse(NewSamplerReg)
4978 .constrainAllUses(TII, TRI, RBI);
4979
4980 auto IntrId = cast<GIntrinsic>(I).getIntrinsicID();
4981 bool IsGatherCmp = IntrId == Intrinsic::spv_resource_gather_cmp;
4982 unsigned Opcode =
4983 IsGatherCmp ? SPIRV::OpImageDrefGather : SPIRV::OpImageGather;
4984
4985 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
4986 .addDef(ResVReg)
4987 .addUse(GR.getSPIRVTypeID(ResType))
4988 .addUse(SampledImageReg)
4989 .addUse(CoordinateReg)
4990 .addUse(ComponentOrCompareReg);
4991
4992 uint32_t ImageOperands = 0;
4993 if (OffsetReg && !isScalarOrVectorIntConstantZero(OffsetReg)) {
4994 if (Dim == SPIRV::Dim::DIM_Cube) {
4995 I.emitGenericError(
4996 "Gather operations with offset are not supported for Cube images.");
4997 return false;
4998 }
4999 if (isConstReg(MRI, OffsetReg))
5000 ImageOperands |= SPIRV::ImageOperand::ConstOffset;
5001 else {
5002 ImageOperands |= SPIRV::ImageOperand::Offset;
5003 }
5004 }
5005
5006 if (ImageOperands != 0) {
5007 MIB.addImm(ImageOperands);
5008 if (ImageOperands &
5009 (SPIRV::ImageOperand::ConstOffset | SPIRV::ImageOperand::Offset))
5010 MIB.addUse(OffsetReg);
5011 }
5012
5013 MIB.constrainAllUses(TII, TRI, RBI);
5014 return true;
5015}
5016
5017bool SPIRVInstructionSelector::generateImageReadOrFetch(
5018 Register &ResVReg, SPIRVTypeInst ResType, Register ImageReg,
5019 Register IdxReg, DebugLoc Loc, MachineInstr &Pos,
5020 const ImageOperands *ImOps) const {
5021 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(ImageReg);
5022 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
5023 "ImageReg is not an image type.");
5024
5025 bool IsSignedInteger =
5026 sampledTypeIsSignedInteger(GR.getTypeForSPIRVType(ImageType));
5027 // Check if the "sampled" operand of the image type is 1.
5028 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpImageFetch
5029 auto SampledOp = ImageType->getOperand(6);
5030 bool IsFetch = (SampledOp.getImm() == 1);
5031
5032 auto AddOperands = [&](MachineInstrBuilder &MIB) {
5033 uint32_t ImageOperandsMask = 0;
5034 if (IsSignedInteger)
5035 ImageOperandsMask |= 0x1000; // SignExtend
5036
5037 if (IsFetch && ImOps) {
5038 if (ImOps->Lod)
5039 ImageOperandsMask |= SPIRV::ImageOperand::Lod;
5040 if (ImOps->Offset && !isScalarOrVectorIntConstantZero(*ImOps->Offset)) {
5041 if (isConstReg(MRI, *ImOps->Offset))
5042 ImageOperandsMask |= SPIRV::ImageOperand::ConstOffset;
5043 else
5044 ImageOperandsMask |= SPIRV::ImageOperand::Offset;
5045 }
5046 }
5047
5048 if (ImageOperandsMask != 0) {
5049 MIB.addImm(ImageOperandsMask);
5050 if (IsFetch && ImOps) {
5051 if (ImOps->Lod)
5052 MIB.addUse(*ImOps->Lod);
5053 if (ImOps->Offset &&
5054 (ImageOperandsMask &
5055 (SPIRV::ImageOperand::Offset | SPIRV::ImageOperand::ConstOffset)))
5056 MIB.addUse(*ImOps->Offset);
5057 }
5058 }
5059 };
5060
5061 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
5062 if (ResultSize == 4) {
5063 auto BMI =
5064 BuildMI(*Pos.getParent(), Pos, Loc,
5065 TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
5066 .addDef(ResVReg)
5067 .addUse(GR.getSPIRVTypeID(ResType))
5068 .addUse(ImageReg)
5069 .addUse(IdxReg);
5070
5071 AddOperands(BMI);
5072 BMI.constrainAllUses(TII, TRI, RBI);
5073 return true;
5074 }
5075
5076 SPIRVTypeInst ReadType = widenTypeToVec4(ResType, Pos);
5077 Register ReadReg = MRI->createVirtualRegister(GR.getRegClass(ReadType));
5078 auto BMI =
5079 BuildMI(*Pos.getParent(), Pos, Loc,
5080 TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
5081 .addDef(ReadReg)
5082 .addUse(GR.getSPIRVTypeID(ReadType))
5083 .addUse(ImageReg)
5084 .addUse(IdxReg);
5085 AddOperands(BMI);
5086 BMI.constrainAllUses(TII, TRI, RBI);
5087
5088 if (ResultSize == 1) {
5089 BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpCompositeExtract))
5090 .addDef(ResVReg)
5091 .addUse(GR.getSPIRVTypeID(ResType))
5092 .addUse(ReadReg)
5093 .addImm(0)
5094 .constrainAllUses(TII, TRI, RBI);
5095 return true;
5096 }
5097 return extractSubvector(ResVReg, ResType, ReadReg, Pos);
5098}
5099
5100bool SPIRVInstructionSelector::selectResourceGetPointer(Register &ResVReg,
5101 SPIRVTypeInst ResType,
5102 MachineInstr &I) const {
5103 Register ResourcePtr = I.getOperand(2).getReg();
5104 SPIRVTypeInst RegType = GR.getSPIRVTypeForVReg(ResourcePtr, I.getMF());
5105 if (RegType->getOpcode() == SPIRV::OpTypeImage) {
5106 // For texel buffers, the index into the image is part of the OpImageRead or
5107 // OpImageWrite instructions. So we will do nothing in this case. This
5108 // intrinsic will be combined with the load or store when selecting the load
5109 // or store.
5110 return true;
5111 }
5112
5113 assert(ResType->getOpcode() == SPIRV::OpTypePointer);
5114 MachineIRBuilder MIRBuilder(I);
5115
5116 Register IndexReg = I.getOperand(3).getReg();
5117 Register ZeroReg =
5118 buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I);
5119 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain))
5120 .addDef(ResVReg)
5121 .addUse(GR.getSPIRVTypeID(ResType))
5122 .addUse(ResourcePtr)
5123 .addUse(ZeroReg)
5124 .addUse(IndexReg)
5125 .constrainAllUses(TII, TRI, RBI);
5126 return true;
5127}
5128
5129bool SPIRVInstructionSelector::selectPushConstantGetPointer(
5130 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5131 MRI->replaceRegWith(ResVReg, I.getOperand(2).getReg());
5132 return true;
5133}
5134
5135bool SPIRVInstructionSelector::selectResourceNonUniformIndex(
5136 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5137 Register ObjReg = I.getOperand(2).getReg();
5138 if (!BuildCOPY(ResVReg, ObjReg, I))
5139 return false;
5140
5141 buildOpDecorate(ResVReg, I, TII, SPIRV::Decoration::NonUniformEXT, {});
5142 // Check for the registers that use the index marked as non-uniform
5143 // and recursively mark them as non-uniform.
5144 // Per the spec, it's necessary that the final argument used for
5145 // load/store/sample/atomic must be decorated, so we need to propagate the
5146 // decoration through access chains and copies.
5147 // https://docs.vulkan.org/samples/latest/samples/extensions/descriptor_indexing/README.html#_when_to_use_non_uniform_indexing_qualifier
5148 decorateUsesAsNonUniform(ResVReg);
5149 return true;
5150}
5151
5152void SPIRVInstructionSelector::decorateUsesAsNonUniform(
5153 Register &NonUniformReg) const {
5154 llvm::SmallVector<Register> WorkList = {NonUniformReg};
5155 while (WorkList.size() > 0) {
5156 Register CurrentReg = WorkList.back();
5157 WorkList.pop_back();
5158
5159 bool IsDecorated = false;
5160 for (MachineInstr &Use : MRI->use_instructions(CurrentReg)) {
5161 if (Use.getOpcode() == SPIRV::OpDecorate &&
5162 Use.getOperand(1).getImm() == SPIRV::Decoration::NonUniformEXT) {
5163 IsDecorated = true;
5164 continue;
5165 }
5166 // Check if the instruction has the result register and add it to the
5167 // worklist.
5168 if (Use.getOperand(0).isReg() && Use.getOperand(0).isDef()) {
5169 Register ResultReg = Use.getOperand(0).getReg();
5170 if (ResultReg == CurrentReg)
5171 continue;
5172 WorkList.push_back(ResultReg);
5173 }
5174 }
5175
5176 if (!IsDecorated) {
5177 buildOpDecorate(CurrentReg, *MRI->getVRegDef(CurrentReg), TII,
5178 SPIRV::Decoration::NonUniformEXT, {});
5179 }
5180 }
5181}
5182
5183bool SPIRVInstructionSelector::extractSubvector(
5184 Register &ResVReg, SPIRVTypeInst ResType, Register &ReadReg,
5185 MachineInstr &InsertionPoint) const {
5186 SPIRVTypeInst InputType = GR.getResultType(ReadReg);
5187 [[maybe_unused]] uint64_t InputSize =
5188 GR.getScalarOrVectorComponentCount(InputType);
5189 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
5190 assert(InputSize > 1 && "The input must be a vector.");
5191 assert(ResultSize > 1 && "The result must be a vector.");
5192 assert(ResultSize < InputSize &&
5193 "Cannot extract more element than there are in the input.");
5194 SmallVector<Register> ComponentRegisters;
5195 SPIRVTypeInst ScalarType = GR.getScalarOrVectorComponentType(ResType);
5196 const TargetRegisterClass *ScalarRegClass = GR.getRegClass(ScalarType);
5197 for (uint64_t I = 0; I < ResultSize; I++) {
5198 Register ComponentReg = MRI->createVirtualRegister(ScalarRegClass);
5199 BuildMI(*InsertionPoint.getParent(), InsertionPoint,
5200 InsertionPoint.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
5201 .addDef(ComponentReg)
5202 .addUse(ScalarType->getOperand(0).getReg())
5203 .addUse(ReadReg)
5204 .addImm(I)
5205 .constrainAllUses(TII, TRI, RBI);
5206 ComponentRegisters.emplace_back(ComponentReg);
5207 }
5208
5209 MachineInstrBuilder MIB = BuildMI(*InsertionPoint.getParent(), InsertionPoint,
5210 InsertionPoint.getDebugLoc(),
5211 TII.get(SPIRV::OpCompositeConstruct))
5212 .addDef(ResVReg)
5213 .addUse(GR.getSPIRVTypeID(ResType));
5214
5215 for (Register ComponentReg : ComponentRegisters)
5216 MIB.addUse(ComponentReg);
5217 MIB.constrainAllUses(TII, TRI, RBI);
5218 return true;
5219}
5220
5221bool SPIRVInstructionSelector::selectImageWriteIntrinsic(
5222 MachineInstr &I) const {
5223 // If the load of the image is in a different basic block, then
5224 // this will generate invalid code. A proper solution is to move
5225 // the OpLoad from selectHandleFromBinding here. However, to do
5226 // that we will need to change the return type of the intrinsic.
5227 // We will do that when we can, but for now trying to move forward with other
5228 // issues.
5229 Register ImageReg = I.getOperand(1).getReg();
5230 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
5231 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
5232 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
5233 *ImageDef, I)) {
5234 return false;
5235 }
5236
5237 Register CoordinateReg = I.getOperand(2).getReg();
5238 Register DataReg = I.getOperand(3).getReg();
5239 assert(GR.getResultType(DataReg)->getOpcode() == SPIRV::OpTypeVector);
5241 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpImageWrite))
5242 .addUse(NewImageReg)
5243 .addUse(CoordinateReg)
5244 .addUse(DataReg)
5245 .constrainAllUses(TII, TRI, RBI);
5246 return true;
5247}
5248
5249Register SPIRVInstructionSelector::buildPointerToResource(
5250 SPIRVTypeInst SpirvResType, SPIRV::StorageClass::StorageClass SC,
5251 uint32_t Set, uint32_t Binding, uint32_t ArraySize, Register IndexReg,
5252 StringRef Name, MachineIRBuilder MIRBuilder) const {
5253 const Type *ResType = GR.getTypeForSPIRVType(SpirvResType);
5254 if (ArraySize == 1) {
5255 SPIRVTypeInst PtrType =
5256 GR.getOrCreateSPIRVPointerType(ResType, MIRBuilder, SC);
5257 assert(GR.getPointeeType(PtrType) == SpirvResType &&
5258 "SpirvResType did not have an explicit layout.");
5259 return GR.getOrCreateGlobalVariableWithBinding(PtrType, Set, Binding, Name,
5260 MIRBuilder);
5261 }
5262
5263 const Type *VarType = ArrayType::get(const_cast<Type *>(ResType), ArraySize);
5264 SPIRVTypeInst VarPointerType =
5265 GR.getOrCreateSPIRVPointerType(VarType, MIRBuilder, SC);
5267 VarPointerType, Set, Binding, Name, MIRBuilder);
5268
5269 SPIRVTypeInst ResPointerType =
5270 GR.getOrCreateSPIRVPointerType(ResType, MIRBuilder, SC);
5271 Register AcReg = MRI->createVirtualRegister(GR.getRegClass(ResPointerType));
5272
5273 MIRBuilder.buildInstr(SPIRV::OpAccessChain)
5274 .addDef(AcReg)
5275 .addUse(GR.getSPIRVTypeID(ResPointerType))
5276 .addUse(VarReg)
5277 .addUse(IndexReg);
5278
5279 return AcReg;
5280}
5281
5282bool SPIRVInstructionSelector::selectFirstBitSet16(
5283 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
5284 unsigned ExtendOpcode, unsigned BitSetOpcode) const {
5285 Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5286 if (!selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()},
5287 ExtendOpcode))
5288 return false;
5289
5290 return selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode);
5291}
5292
5293bool SPIRVInstructionSelector::selectFirstBitSet32(
5294 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
5295 unsigned BitSetOpcode) const {
5296 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
5297 .addDef(ResVReg)
5298 .addUse(GR.getSPIRVTypeID(ResType))
5299 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
5300 .addImm(BitSetOpcode)
5301 .addUse(SrcReg)
5302 .constrainAllUses(TII, TRI, RBI);
5303 return true;
5304}
5305
5306bool SPIRVInstructionSelector::selectFirstBitSet64Overflow(
5307 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
5308 unsigned BitSetOpcode, bool SwapPrimarySide) const {
5309
5310 // SPIR-V allow vectors of size 2,3,4 only. Calling with a larger vectors
5311 // requires creating a param register and return register with an invalid
5312 // vector size. If that is resolved, then this function can be used for
5313 // vectors of any component size.
5314 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType);
5315 assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops");
5316
5317 MachineIRBuilder MIRBuilder(I);
5318 SPIRVTypeInst BaseType = GR.retrieveScalarOrVectorIntType(ResType);
5319 SPIRVTypeInst I64Type = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder);
5320 SPIRVTypeInst I64x2Type =
5321 GR.getOrCreateSPIRVVectorType(I64Type, 2, MIRBuilder, false);
5322 SPIRVTypeInst Vec2ResType =
5323 GR.getOrCreateSPIRVVectorType(BaseType, 2, MIRBuilder, false);
5324
5325 std::vector<Register> PartialRegs;
5326
5327 // Loops 0, 2, 4, ... but stops one loop early when ComponentCount is odd
5328 unsigned CurrentComponent = 0;
5329 for (; CurrentComponent + 1 < ComponentCount; CurrentComponent += 2) {
5330 // This register holds the firstbitX result for each of the i64x2 vectors
5331 // extracted from SrcReg
5332 Register BitSetResult =
5333 MRI->createVirtualRegister(GR.getRegClass(I64x2Type));
5334
5335 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
5336 TII.get(SPIRV::OpVectorShuffle))
5337 .addDef(BitSetResult)
5338 .addUse(GR.getSPIRVTypeID(I64x2Type))
5339 .addUse(SrcReg)
5340 .addUse(SrcReg)
5341 .addImm(CurrentComponent)
5342 .addImm(CurrentComponent + 1);
5343
5344 MIB.constrainAllUses(TII, TRI, RBI);
5345
5346 Register SubVecBitSetReg =
5347 MRI->createVirtualRegister(GR.getRegClass(Vec2ResType));
5348
5349 if (!selectFirstBitSet64(SubVecBitSetReg, Vec2ResType, I, BitSetResult,
5350 BitSetOpcode, SwapPrimarySide))
5351 return false;
5352
5353 PartialRegs.push_back(SubVecBitSetReg);
5354 }
5355
5356 // On odd component counts we need to handle one more component
5357 if (CurrentComponent != ComponentCount) {
5358 bool ZeroAsNull = !STI.isShader();
5359 Register FinalElemReg = MRI->createVirtualRegister(GR.getRegClass(I64Type));
5360 Register ConstIntLastIdx = GR.getOrCreateConstInt(
5361 ComponentCount - 1, I, BaseType, TII, ZeroAsNull);
5362
5363 if (!selectOpWithSrcs(FinalElemReg, I64Type, I, {SrcReg, ConstIntLastIdx},
5364 SPIRV::OpVectorExtractDynamic))
5365 return false;
5366
5367 Register FinalElemBitSetReg =
5369
5370 if (!selectFirstBitSet64(FinalElemBitSetReg, BaseType, I, FinalElemReg,
5371 BitSetOpcode, SwapPrimarySide))
5372 return false;
5373
5374 PartialRegs.push_back(FinalElemBitSetReg);
5375 }
5376
5377 // Join all the resulting registers back into the return type in order
5378 // (ie i32x2, i32x2, i32x1 -> i32x5)
5379 return selectOpWithSrcs(ResVReg, ResType, I, std::move(PartialRegs),
5380 SPIRV::OpCompositeConstruct);
5381}
5382
5383bool SPIRVInstructionSelector::selectFirstBitSet64(
5384 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
5385 unsigned BitSetOpcode, bool SwapPrimarySide) const {
5386 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType);
5387 SPIRVTypeInst BaseType = GR.retrieveScalarOrVectorIntType(ResType);
5388 bool ZeroAsNull = !STI.isShader();
5389 Register ConstIntZero =
5390 GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull);
5391 Register ConstIntOne =
5392 GR.getOrCreateConstInt(1, I, BaseType, TII, ZeroAsNull);
5393
5394 // SPIRV doesn't support vectors with more than 4 components. Since the
5395 // algoritm below converts i64 -> i32x2 and i64x4 -> i32x8 it can only
5396 // operate on vectors with 2 or less components. When largers vectors are
5397 // seen. Split them, recurse, then recombine them.
5398 if (ComponentCount > 2) {
5399 return selectFirstBitSet64Overflow(ResVReg, ResType, I, SrcReg,
5400 BitSetOpcode, SwapPrimarySide);
5401 }
5402
5403 // 1. Split int64 into 2 pieces using a bitcast
5404 MachineIRBuilder MIRBuilder(I);
5405 SPIRVTypeInst PostCastType = GR.getOrCreateSPIRVVectorType(
5406 BaseType, 2 * ComponentCount, MIRBuilder, false);
5407 Register BitcastReg =
5408 MRI->createVirtualRegister(GR.getRegClass(PostCastType));
5409
5410 if (!selectOpWithSrcs(BitcastReg, PostCastType, I, {SrcReg},
5411 SPIRV::OpBitcast))
5412 return false;
5413
5414 // 2. Find the first set bit from the primary side for all the pieces in #1
5415 Register FBSReg = MRI->createVirtualRegister(GR.getRegClass(PostCastType));
5416 if (!selectFirstBitSet32(FBSReg, PostCastType, I, BitcastReg, BitSetOpcode))
5417 return false;
5418
5419 // 3. Split result vector into high bits and low bits
5420 Register HighReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5421 Register LowReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5422
5423 bool IsScalarRes = ResType->getOpcode() != SPIRV::OpTypeVector;
5424 if (IsScalarRes) {
5425 // if scalar do a vector extract
5426 if (!selectOpWithSrcs(HighReg, ResType, I, {FBSReg, ConstIntZero},
5427 SPIRV::OpVectorExtractDynamic))
5428 return false;
5429 if (!selectOpWithSrcs(LowReg, ResType, I, {FBSReg, ConstIntOne},
5430 SPIRV::OpVectorExtractDynamic))
5431 return false;
5432 } else {
5433 // if vector do a shufflevector
5434 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
5435 TII.get(SPIRV::OpVectorShuffle))
5436 .addDef(HighReg)
5437 .addUse(GR.getSPIRVTypeID(ResType))
5438 .addUse(FBSReg)
5439 // Per the spec, repeat the vector if only one vec is needed
5440 .addUse(FBSReg);
5441
5442 // high bits are stored in even indexes. Extract them from FBSReg
5443 for (unsigned J = 0; J < ComponentCount * 2; J += 2) {
5444 MIB.addImm(J);
5445 }
5446
5447 MIB.constrainAllUses(TII, TRI, RBI);
5448
5449 MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
5450 TII.get(SPIRV::OpVectorShuffle))
5451 .addDef(LowReg)
5452 .addUse(GR.getSPIRVTypeID(ResType))
5453 .addUse(FBSReg)
5454 // Per the spec, repeat the vector if only one vec is needed
5455 .addUse(FBSReg);
5456
5457 // low bits are stored in odd indexes. Extract them from FBSReg
5458 for (unsigned J = 1; J < ComponentCount * 2; J += 2) {
5459 MIB.addImm(J);
5460 }
5461 MIB.constrainAllUses(TII, TRI, RBI);
5462 }
5463
5464 // 4. Check the result. When primary bits == -1 use secondary, otherwise use
5465 // primary
5466 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
5467 Register NegOneReg;
5468 Register Reg0;
5469 Register Reg32;
5470 unsigned SelectOp;
5471 unsigned AddOp;
5472
5473 if (IsScalarRes) {
5474 NegOneReg =
5475 GR.getOrCreateConstInt((unsigned)-1, I, ResType, TII, ZeroAsNull);
5476 Reg0 = GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
5477 Reg32 = GR.getOrCreateConstInt(32, I, ResType, TII, ZeroAsNull);
5478 SelectOp = SPIRV::OpSelectSISCond;
5479 AddOp = SPIRV::OpIAddS;
5480 } else {
5481 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, ComponentCount,
5482 MIRBuilder, false);
5483 NegOneReg =
5484 GR.getOrCreateConstVector((unsigned)-1, I, ResType, TII, ZeroAsNull);
5485 Reg0 = GR.getOrCreateConstVector(0, I, ResType, TII, ZeroAsNull);
5486 Reg32 = GR.getOrCreateConstVector(32, I, ResType, TII, ZeroAsNull);
5487 SelectOp = SPIRV::OpSelectVIVCond;
5488 AddOp = SPIRV::OpIAddV;
5489 }
5490
5491 Register PrimaryReg = HighReg;
5492 Register SecondaryReg = LowReg;
5493 Register PrimaryShiftReg = Reg32;
5494 Register SecondaryShiftReg = Reg0;
5495
5496 // By default the emitted opcodes check for the set bit from the MSB side.
5497 // Setting SwapPrimarySide checks the set bit from the LSB side
5498 if (SwapPrimarySide) {
5499 PrimaryReg = LowReg;
5500 SecondaryReg = HighReg;
5501 PrimaryShiftReg = Reg0;
5502 SecondaryShiftReg = Reg32;
5503 }
5504
5505 // Check if the primary bits are == -1
5506 Register BReg = MRI->createVirtualRegister(GR.getRegClass(BoolType));
5507 if (!selectOpWithSrcs(BReg, BoolType, I, {PrimaryReg, NegOneReg},
5508 SPIRV::OpIEqual))
5509 return false;
5510
5511 // Select secondary bits if true in BReg, otherwise primary bits
5512 Register TmpReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5513 if (!selectOpWithSrcs(TmpReg, ResType, I, {BReg, SecondaryReg, PrimaryReg},
5514 SelectOp))
5515 return false;
5516
5517 // 5. Add 32 when high bits are used, otherwise 0 for low bits
5518 Register ValReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5519 if (!selectOpWithSrcs(ValReg, ResType, I,
5520 {BReg, SecondaryShiftReg, PrimaryShiftReg}, SelectOp))
5521 return false;
5522
5523 return selectOpWithSrcs(ResVReg, ResType, I, {ValReg, TmpReg}, AddOp);
5524}
5525
5526bool SPIRVInstructionSelector::selectFirstBitHigh(Register ResVReg,
5527 SPIRVTypeInst ResType,
5528 MachineInstr &I,
5529 bool IsSigned) const {
5530 // FindUMsb and FindSMsb intrinsics only support 32 bit integers
5531 Register OpReg = I.getOperand(2).getReg();
5532 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
5533 // zero or sign extend
5534 unsigned ExtendOpcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
5535 unsigned BitSetOpcode = IsSigned ? GL::FindSMsb : GL::FindUMsb;
5536
5537 switch (GR.getScalarOrVectorBitWidth(OpType)) {
5538 case 16:
5539 return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode);
5540 case 32:
5541 return selectFirstBitSet32(ResVReg, ResType, I, OpReg, BitSetOpcode);
5542 case 64:
5543 return selectFirstBitSet64(ResVReg, ResType, I, OpReg, BitSetOpcode,
5544 /*SwapPrimarySide=*/false);
5545 default:
5547 "spv_firstbituhigh and spv_firstbitshigh only support 16,32,64 bits.");
5548 }
5549}
5550
5551bool SPIRVInstructionSelector::selectFirstBitLow(Register ResVReg,
5552 SPIRVTypeInst ResType,
5553 MachineInstr &I) const {
5554 // FindILsb intrinsic only supports 32 bit integers
5555 Register OpReg = I.getOperand(2).getReg();
5556 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
5557 // OpUConvert treats the operand bits as an unsigned i16 and zero extends it
5558 // to an unsigned i32. As this leaves all the least significant bits unchanged
5559 // so the first set bit from the LSB side doesn't change.
5560 unsigned ExtendOpcode = SPIRV::OpUConvert;
5561 unsigned BitSetOpcode = GL::FindILsb;
5562
5563 switch (GR.getScalarOrVectorBitWidth(OpType)) {
5564 case 16:
5565 return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode);
5566 case 32:
5567 return selectFirstBitSet32(ResVReg, ResType, I, OpReg, BitSetOpcode);
5568 case 64:
5569 return selectFirstBitSet64(ResVReg, ResType, I, OpReg, BitSetOpcode,
5570 /*SwapPrimarySide=*/true);
5571 default:
5572 report_fatal_error("spv_firstbitlow only supports 16,32,64 bits.");
5573 }
5574}
5575
5576bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg,
5577 SPIRVTypeInst ResType,
5578 MachineInstr &I) const {
5579 // there was an allocation size parameter to the allocation instruction
5580 // that is not 1
5581 MachineBasicBlock &BB = *I.getParent();
5582 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVariableLengthArrayINTEL))
5583 .addDef(ResVReg)
5584 .addUse(GR.getSPIRVTypeID(ResType))
5585 .addUse(I.getOperand(2).getReg())
5586 .constrainAllUses(TII, TRI, RBI);
5587 if (!STI.isShader()) {
5588 unsigned Alignment = I.getOperand(3).getImm();
5589 buildOpDecorate(ResVReg, I, TII, SPIRV::Decoration::Alignment, {Alignment});
5590 }
5591 return true;
5592}
5593
5594bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg,
5595 SPIRVTypeInst ResType,
5596 MachineInstr &I) const {
5597 // Change order of instructions if needed: all OpVariable instructions in a
5598 // function must be the first instructions in the first block
5599 auto It = getOpVariableMBBIt(I);
5600 BuildMI(*It->getParent(), It, It->getDebugLoc(), TII.get(SPIRV::OpVariable))
5601 .addDef(ResVReg)
5602 .addUse(GR.getSPIRVTypeID(ResType))
5603 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
5604 .constrainAllUses(TII, TRI, RBI);
5605 if (!STI.isShader()) {
5606 unsigned Alignment = I.getOperand(2).getImm();
5607 buildOpDecorate(ResVReg, *It, TII, SPIRV::Decoration::Alignment,
5608 {Alignment});
5609 }
5610 return true;
5611}
5612
5613bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const {
5614 // InstructionSelector walks backwards through the instructions. We can use
5615 // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
5616 // first, so can generate an OpBranchConditional here. If there is no
5617 // G_BRCOND, we just use OpBranch for a regular unconditional branch.
5618 const MachineInstr *PrevI = I.getPrevNode();
5619 MachineBasicBlock &MBB = *I.getParent();
5620 if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) {
5621 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
5622 .addUse(PrevI->getOperand(0).getReg())
5623 .addMBB(PrevI->getOperand(1).getMBB())
5624 .addMBB(I.getOperand(0).getMBB())
5625 .constrainAllUses(TII, TRI, RBI);
5626 return true;
5627 }
5628 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch))
5629 .addMBB(I.getOperand(0).getMBB())
5630 .constrainAllUses(TII, TRI, RBI);
5631 return true;
5632}
5633
5634bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const {
5635 // InstructionSelector walks backwards through the instructions. For an
5636 // explicit conditional branch with no fallthrough, we use both a G_BR and a
5637 // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
5638 // generate the OpBranchConditional in selectBranch above.
5639 //
5640 // If an OpBranchConditional has been generated, we simply return, as the work
5641 // is alread done. If there is no OpBranchConditional, LLVM must be relying on
5642 // implicit fallthrough to the next basic block, so we need to create an
5643 // OpBranchConditional with an explicit "false" argument pointing to the next
5644 // basic block that LLVM would fall through to.
5645 const MachineInstr *NextI = I.getNextNode();
5646 // Check if this has already been successfully selected.
5647 if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional)
5648 return true;
5649 // Must be relying on implicit block fallthrough, so generate an
5650 // OpBranchConditional with the "next" basic block as the "false" target.
5651 MachineBasicBlock &MBB = *I.getParent();
5652 unsigned NextMBBNum = MBB.getNextNode()->getNumber();
5653 MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum);
5654 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
5655 .addUse(I.getOperand(0).getReg())
5656 .addMBB(I.getOperand(1).getMBB())
5657 .addMBB(NextMBB)
5658 .constrainAllUses(TII, TRI, RBI);
5659 return true;
5660}
5661
5662bool SPIRVInstructionSelector::selectPhi(Register ResVReg,
5663 MachineInstr &I) const {
5664 auto MIB =
5665 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::PHI))
5666 .addDef(ResVReg);
5667 const unsigned NumOps = I.getNumOperands();
5668 for (unsigned i = 1; i < NumOps; i += 2) {
5669 MIB.addUse(I.getOperand(i + 0).getReg());
5670 MIB.addMBB(I.getOperand(i + 1).getMBB());
5671 }
5672 MIB.constrainAllUses(TII, TRI, RBI);
5673 return true;
5674}
5675
5676bool SPIRVInstructionSelector::selectGlobalValue(
5677 Register ResVReg, MachineInstr &I, const MachineInstr *Init) const {
5678 // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
5679 MachineIRBuilder MIRBuilder(I);
5680 const GlobalValue *GV = I.getOperand(1).getGlobal();
5682
5683 std::string GlobalIdent;
5684 if (!GV->hasName()) {
5685 unsigned &ID = UnnamedGlobalIDs[GV];
5686 if (ID == 0)
5687 ID = UnnamedGlobalIDs.size();
5688 GlobalIdent = "__unnamed_" + Twine(ID).str();
5689 } else {
5690 GlobalIdent = GV->getName();
5691 }
5692
5693 // Behaviour of functions as operands depends on availability of the
5694 // corresponding extension (SPV_INTEL_function_pointers):
5695 // - If there is an extension to operate with functions as operands:
5696 // We create a proper constant operand and evaluate a correct type for a
5697 // function pointer.
5698 // - Without the required extension:
5699 // We have functions as operands in tests with blocks of instruction e.g. in
5700 // transcoding/global_block.ll. These operands are not used and should be
5701 // substituted by zero constants. Their type is expected to be always
5702 // OpTypePointer Function %uchar.
5703 if (isa<Function>(GV)) {
5704 const Constant *ConstVal = GV;
5705 MachineBasicBlock &BB = *I.getParent();
5706 Register NewReg = GR.find(ConstVal, GR.CurMF);
5707 if (!NewReg.isValid()) {
5708 const Function *GVFun =
5709 STI.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
5710 ? dyn_cast<Function>(GV)
5711 : nullptr;
5712 SPIRVTypeInst ResType = GR.getOrCreateSPIRVPointerType(
5713 GVType, I,
5714 GVFun ? SPIRV::StorageClass::CodeSectionINTEL
5716 if (GVFun) {
5717 // References to a function via function pointers generate virtual
5718 // registers without a definition. We will resolve it later, during
5719 // module analysis stage.
5720 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
5721 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
5722 Register FuncVReg =
5723 MRI->createGenericVirtualRegister(GR.getRegType(ResType));
5724 MRI->setRegClass(FuncVReg, &SPIRV::pIDRegClass);
5725 GR.assignSPIRVTypeToVReg(ResType, FuncVReg, *GR.CurMF);
5726 MachineInstrBuilder MIB1 =
5727 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
5728 .addDef(FuncVReg)
5729 .addUse(ResTypeReg);
5730 MachineInstrBuilder MIB2 =
5731 BuildMI(BB, I, I.getDebugLoc(),
5732 TII.get(SPIRV::OpConstantFunctionPointerINTEL))
5733 .addDef(ResVReg)
5734 .addUse(ResTypeReg)
5735 .addUse(FuncVReg);
5736 GR.add(ConstVal, MIB2);
5737 // mapping the function pointer to the used Function
5738 GR.recordFunctionPointer(&MIB2.getInstr()->getOperand(2), GVFun);
5739 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF);
5740 MIB1.constrainAllUses(TII, TRI, RBI);
5741 MIB2.constrainAllUses(TII, TRI, RBI);
5742 return true;
5743 }
5744 MachineInstrBuilder MIB3 =
5745 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
5746 .addDef(ResVReg)
5747 .addUse(GR.getSPIRVTypeID(ResType));
5748 GR.add(ConstVal, MIB3);
5749 MIB3.constrainAllUses(TII, TRI, RBI);
5750 return true;
5751 }
5752 assert(NewReg != ResVReg);
5753 return BuildCOPY(ResVReg, NewReg, I);
5754 }
5756 assert(GlobalVar->getName() != "llvm.global.annotations");
5757
5758 // Skip empty declaration for GVs with initializers till we get the decl with
5759 // passed initializer.
5760 if (hasInitializer(GlobalVar) && !Init)
5761 return true;
5762
5763 const std::optional<SPIRV::LinkageType::LinkageType> LnkType =
5764 getSpirvLinkageTypeFor(STI, *GV);
5765
5766 const unsigned AddrSpace = GV->getAddressSpace();
5767 SPIRV::StorageClass::StorageClass StorageClass =
5768 addressSpaceToStorageClass(AddrSpace, STI);
5769 SPIRVTypeInst ResType =
5772 ResVReg, ResType, GlobalIdent, GV, StorageClass, Init,
5773 GlobalVar->isConstant(), LnkType, MIRBuilder, true);
5774 // TODO: For AMDGCN, we pipe externally_initialized through via
5775 // HostAccessINTEL, with ReadWrite (3) access, which is we then handle during
5776 // reverse translation. We should remove this once SPIR-V gains the ability to
5777 // express the concept.
5778 if (GlobalVar->isExternallyInitialized() &&
5779 STI.getTargetTriple().getVendor() == Triple::AMD) {
5780 constexpr unsigned ReadWriteINTEL = 3u;
5781 buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::HostAccessINTEL,
5782 {ReadWriteINTEL});
5783 MachineInstrBuilder MIB(*MF, --MIRBuilder.getInsertPt());
5784 addStringImm(GV->getName(), MIB);
5785 }
5786 return Reg.isValid();
5787}
5788
5789bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
5790 SPIRVTypeInst ResType,
5791 MachineInstr &I) const {
5792 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
5793 return selectExtInst(ResVReg, ResType, I, CL::log10);
5794 }
5795
5796 // There is no log10 instruction in the GLSL Extended Instruction set, so it
5797 // is implemented as:
5798 // log10(x) = log2(x) * (1 / log2(10))
5799 // = log2(x) * 0.30103
5800
5801 MachineIRBuilder MIRBuilder(I);
5802 MachineBasicBlock &BB = *I.getParent();
5803
5804 // Build log2(x).
5805 Register VarReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5806 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
5807 .addDef(VarReg)
5808 .addUse(GR.getSPIRVTypeID(ResType))
5809 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
5810 .addImm(GL::Log2)
5811 .add(I.getOperand(1))
5812 .constrainAllUses(TII, TRI, RBI);
5813
5814 // Build 0.30103.
5815 assert(ResType->getOpcode() == SPIRV::OpTypeVector ||
5816 ResType->getOpcode() == SPIRV::OpTypeFloat);
5817 // TODO: Add matrix implementation once supported by the HLSL frontend.
5818 SPIRVTypeInst SpirvScalarType = ResType->getOpcode() == SPIRV::OpTypeVector
5819 ? SPIRVTypeInst(GR.getSPIRVTypeForVReg(
5820 ResType->getOperand(1).getReg()))
5821 : ResType;
5822 Register ScaleReg =
5823 GR.buildConstantFP(APFloat(0.30103f), MIRBuilder, SpirvScalarType);
5824
5825 // Multiply log2(x) by 0.30103 to get log10(x) result.
5826 auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector
5827 ? SPIRV::OpVectorTimesScalar
5828 : SPIRV::OpFMulS;
5829 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
5830 .addDef(ResVReg)
5831 .addUse(GR.getSPIRVTypeID(ResType))
5832 .addUse(VarReg)
5833 .addUse(ScaleReg)
5834 .constrainAllUses(TII, TRI, RBI);
5835 return true;
5836}
5837
5838bool SPIRVInstructionSelector::selectFpowi(Register ResVReg,
5839 SPIRVTypeInst ResType,
5840 MachineInstr &I) const {
5841 // On OpenCL targets, pown(gentype x, intn n) maps directly.
5842 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std))
5843 return selectExtInst(ResVReg, ResType, I, CL::pown);
5844
5845 // On GLSL (Vulkan) targets, there is no integer-exponent power instruction.
5846 // Lower as: Pow(base, OpConvertSToF(exp)).
5847 if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
5848 Register BaseReg = I.getOperand(1).getReg();
5849 Register ExpReg = I.getOperand(2).getReg();
5850 Register FloatExpReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5851 if (!selectOpWithSrcs(FloatExpReg, ResType, I, {ExpReg},
5852 SPIRV::OpConvertSToF))
5853 return false;
5854 return selectExtInst(ResVReg, ResType, I, GL::Pow,
5855 /*setMIFlags=*/true, /*useMISrc=*/false,
5856 {BaseReg, FloatExpReg});
5857 }
5858 return false;
5859}
5860
5861bool SPIRVInstructionSelector::selectModf(Register ResVReg,
5862 SPIRVTypeInst ResType,
5863 MachineInstr &I) const {
5864 // llvm.modf has a single arg --the number to be decomposed-- and returns a
5865 // struct { restype, restype }, while OpenCLLIB::modf has two args --the
5866 // number to be decomposed and a pointer--, returns the fractional part and
5867 // the integral part is stored in the pointer argument. Therefore, we can't
5868 // use directly the OpenCLLIB::modf intrinsic. However, we can do some
5869 // scaffolding to make it work. The idea is to create an alloca instruction
5870 // to get a ptr, pass this ptr to OpenCL::modf, and then load the value
5871 // from this ptr to place it in the struct. llvm.modf returns the fractional
5872 // part as the first element of the result, and the integral part as the
5873 // second element of the result.
5874
5875 // At this point, the return type is not a struct anymore, but rather two
5876 // independent elements of SPIRVResType. We can get each independent element
5877 // from I.getDefs() or I.getOperands().
5878 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
5879 MachineIRBuilder MIRBuilder(I);
5880 // Get pointer type for alloca variable.
5881 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
5882 ResType, MIRBuilder, SPIRV::StorageClass::Function);
5883 // Create new register for the pointer type of alloca variable.
5884 Register PtrTyReg =
5885 MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
5886 MIRBuilder.getMRI()->setType(
5887 PtrTyReg,
5888 LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Function),
5889 GR.getPointerSize()));
5890
5891 // Assign SPIR-V type of the pointer type of the alloca variable to the
5892 // new register.
5893 GR.assignSPIRVTypeToVReg(PtrType, PtrTyReg, MIRBuilder.getMF());
5894 MachineBasicBlock &EntryBB = I.getMF()->front();
5897 auto AllocaMIB =
5898 BuildMI(EntryBB, VarPos, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
5899 .addDef(PtrTyReg)
5900 .addUse(GR.getSPIRVTypeID(PtrType))
5901 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function));
5902 Register Variable = AllocaMIB->getOperand(0).getReg();
5903
5904 MachineBasicBlock &BB = *I.getParent();
5905 // Create the OpenCLLIB::modf instruction.
5906 auto MIB =
5907 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
5908 .addDef(ResVReg)
5909 .addUse(GR.getSPIRVTypeID(ResType))
5910 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
5911 .addImm(CL::modf)
5912 .setMIFlags(I.getFlags())
5913 .add(I.getOperand(I.getNumExplicitDefs())) // Floating point value.
5914 .addUse(Variable); // Pointer to integral part.
5915 // Assign the integral part stored in the ptr to the second element of the
5916 // result.
5917 Register IntegralPartReg = I.getOperand(1).getReg();
5918 if (IntegralPartReg.isValid()) {
5919 // Load the value from the pointer to integral part.
5920 auto LoadMIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
5921 .addDef(IntegralPartReg)
5922 .addUse(GR.getSPIRVTypeID(ResType))
5923 .addUse(Variable);
5924 LoadMIB.constrainAllUses(TII, TRI, RBI);
5925 return true;
5926 }
5927
5928 MIB.constrainAllUses(TII, TRI, RBI);
5929 return true;
5930 } else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
5931 assert(false && "GLSL::Modf is deprecated.");
5932 // FIXME: GL::Modf is deprecated, use Modfstruct instead.
5933 return false;
5934 }
5935 return false;
5936}
5937
5938// Generate the instructions to load 3-element vector builtin input
5939// IDs/Indices.
5940// Like: GlobalInvocationId, LocalInvocationId, etc....
5941
5942bool SPIRVInstructionSelector::loadVec3BuiltinInputID(
5943 SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg,
5944 SPIRVTypeInst ResType, MachineInstr &I) const {
5945 MachineIRBuilder MIRBuilder(I);
5946 const SPIRVTypeInst Vec3Ty =
5947 GR.getOrCreateSPIRVVectorType(ResType, 3, MIRBuilder, false);
5948 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
5949 Vec3Ty, MIRBuilder, SPIRV::StorageClass::Input);
5950
5951 // Create new register for the input ID builtin variable.
5952 Register NewRegister =
5953 MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
5954 MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 64));
5955 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
5956
5957 // Build global variable with the necessary decorations for the input ID
5958 // builtin variable.
5960 NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr,
5961 SPIRV::StorageClass::Input, nullptr, true, std::nullopt, MIRBuilder,
5962 false);
5963
5964 // Create new register for loading value.
5965 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
5966 Register LoadedRegister = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
5967 MIRBuilder.getMRI()->setType(LoadedRegister, LLT::pointer(0, 64));
5968 GR.assignSPIRVTypeToVReg(Vec3Ty, LoadedRegister, MIRBuilder.getMF());
5969
5970 // Load v3uint value from the global variable.
5971 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
5972 .addDef(LoadedRegister)
5973 .addUse(GR.getSPIRVTypeID(Vec3Ty))
5974 .addUse(Variable);
5975
5976 // Get the input ID index. Expecting operand is a constant immediate value,
5977 // wrapped in a type assignment.
5978 assert(I.getOperand(2).isReg());
5979 const uint32_t ThreadId = foldImm(I.getOperand(2), MRI);
5980
5981 // Extract the input ID from the loaded vector value.
5982 MachineBasicBlock &BB = *I.getParent();
5983 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
5984 .addDef(ResVReg)
5985 .addUse(GR.getSPIRVTypeID(ResType))
5986 .addUse(LoadedRegister)
5987 .addImm(ThreadId);
5988 MIB.constrainAllUses(TII, TRI, RBI);
5989 return true;
5990}
5991
5992// Generate the instructions to load 32-bit integer builtin input IDs/Indices.
5993// Like LocalInvocationIndex
5994bool SPIRVInstructionSelector::loadBuiltinInputID(
5995 SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg,
5996 SPIRVTypeInst ResType, MachineInstr &I) const {
5997 MachineIRBuilder MIRBuilder(I);
5998 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
5999 ResType, MIRBuilder, SPIRV::StorageClass::Input);
6000
6001 // Create new register for the input ID builtin variable.
6002 Register NewRegister =
6003 MIRBuilder.getMRI()->createVirtualRegister(GR.getRegClass(PtrType));
6004 MIRBuilder.getMRI()->setType(
6005 NewRegister,
6006 LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Input),
6007 GR.getPointerSize()));
6008 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
6009
6010 // Build global variable with the necessary decorations for the input ID
6011 // builtin variable.
6013 NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr,
6014 SPIRV::StorageClass::Input, nullptr, true, std::nullopt, MIRBuilder,
6015 false);
6016
6017 // Load uint value from the global variable.
6018 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
6019 .addDef(ResVReg)
6020 .addUse(GR.getSPIRVTypeID(ResType))
6021 .addUse(Variable);
6022
6023 MIB.constrainAllUses(TII, TRI, RBI);
6024 return true;
6025}
6026
6027SPIRVTypeInst SPIRVInstructionSelector::widenTypeToVec4(SPIRVTypeInst Type,
6028 MachineInstr &I) const {
6029 MachineIRBuilder MIRBuilder(I);
6030 if (Type->getOpcode() != SPIRV::OpTypeVector)
6031 return GR.getOrCreateSPIRVVectorType(Type, 4, MIRBuilder, false);
6032
6033 uint64_t VectorSize = Type->getOperand(2).getImm();
6034 if (VectorSize == 4)
6035 return Type;
6036
6037 Register ScalarTypeReg = Type->getOperand(1).getReg();
6038 const SPIRVTypeInst ScalarType = GR.getSPIRVTypeForVReg(ScalarTypeReg);
6039 return GR.getOrCreateSPIRVVectorType(ScalarType, 4, MIRBuilder, false);
6040}
6041
6042bool SPIRVInstructionSelector::loadHandleBeforePosition(
6043 Register &HandleReg, SPIRVTypeInst ResType, GIntrinsic &HandleDef,
6044 MachineInstr &Pos) const {
6045
6046 assert(HandleDef.getIntrinsicID() ==
6047 Intrinsic::spv_resource_handlefrombinding);
6048 uint32_t Set = foldImm(HandleDef.getOperand(2), MRI);
6049 uint32_t Binding = foldImm(HandleDef.getOperand(3), MRI);
6050 uint32_t ArraySize = foldImm(HandleDef.getOperand(4), MRI);
6051 Register IndexReg = HandleDef.getOperand(5).getReg();
6052 std::string Name =
6053 getStringValueFromReg(HandleDef.getOperand(6).getReg(), *MRI);
6054
6055 bool IsStructuredBuffer = ResType->getOpcode() == SPIRV::OpTypePointer;
6056 MachineIRBuilder MIRBuilder(HandleDef);
6057 SPIRVTypeInst VarType = ResType;
6058 SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::UniformConstant;
6059
6060 if (IsStructuredBuffer) {
6061 VarType = GR.getPointeeType(ResType);
6062 SC = GR.getPointerStorageClass(ResType);
6063 }
6064
6065 if (ResType->getOpcode() == SPIRV::OpTypeImage && ArraySize == 0)
6066 MIRBuilder.buildInstr(SPIRV::OpCapability)
6067 .addImm(SPIRV::Capability::RuntimeDescriptorArrayEXT);
6068
6069 Register VarReg =
6070 buildPointerToResource(SPIRVTypeInst(VarType), SC, Set, Binding,
6071 ArraySize, IndexReg, Name, MIRBuilder);
6072
6073 // The handle for the buffer is the pointer to the resource. For an image, the
6074 // handle is the image object. So images get an extra load.
6075 uint32_t LoadOpcode =
6076 IsStructuredBuffer ? SPIRV::OpCopyObject : SPIRV::OpLoad;
6077 GR.assignSPIRVTypeToVReg(ResType, HandleReg, *Pos.getMF());
6078 BuildMI(*Pos.getParent(), Pos, HandleDef.getDebugLoc(), TII.get(LoadOpcode))
6079 .addDef(HandleReg)
6080 .addUse(GR.getSPIRVTypeID(ResType))
6081 .addUse(VarReg)
6082 .constrainAllUses(TII, TRI, RBI);
6083 return true;
6084}
6085
6086void SPIRVInstructionSelector::errorIfInstrOutsideShader(
6087 MachineInstr &I) const {
6088 if (!STI.isShader()) {
6089 std::string DiagMsg;
6090 raw_string_ostream OS(DiagMsg);
6091 I.print(OS, true, false, false, false);
6092 DiagMsg += " is only supported in shaders.\n";
6093 report_fatal_error(DiagMsg.c_str(), false);
6094 }
6095}
6096
6097namespace llvm {
6098InstructionSelector *
6100 const SPIRVSubtarget &Subtarget,
6101 const RegisterBankInfo &RBI) {
6102 return new SPIRVInstructionSelector(TM, Subtarget, RBI);
6103}
6104} // namespace llvm
MachineInstrBuilder & UseMI
#define GET_GLOBALISEL_PREDICATES_INIT
#define GET_GLOBALISEL_TEMPORARIES_INIT
@ Generic
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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
basic Basic Alias true
#define X(NUM, ENUM, NAME)
Definition ELF.h:849
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
DXIL Resource Implicit Binding
#define DEBUG_TYPE
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
LLVMTypeRef LLVMIntType(unsigned NumBits)
Definition Core.cpp:729
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
Loop::LoopBounds::Direction Direction
Definition LoopInfo.cpp:253
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
static StringRef getName(Value *V)
static unsigned getFCmpOpcode(CmpInst::Predicate Pred, unsigned Size)
static APFloat getOneFP(const Type *LLVMFloatTy)
static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC)
static bool isASCastInGVar(MachineRegisterInfo *MRI, Register ResVReg)
static bool mayApplyGenericSelection(unsigned Opcode)
static APFloat getZeroFP(const Type *LLVMFloatTy)
std::vector< std::pair< SPIRV::InstructionSet::InstructionSet, uint32_t > > ExtInstList
static bool intrinsicHasSideEffects(Intrinsic::ID ID)
static unsigned getBoolCmpOpcode(unsigned PredNum)
static unsigned getICmpOpcode(unsigned PredNum)
static bool isOpcodeWithNoSideEffects(unsigned Opcode)
static void addMemoryOperands(MachineMemOperand *MemOp, MachineInstrBuilder &MIB, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry &GR)
static bool isConstReg(MachineRegisterInfo *MRI, MachineInstr *OpDef)
static unsigned getPtrCmpOpcode(unsigned Pred)
unsigned getVectorSizeOrOne(SPIRVTypeInst Type)
bool isDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
spirv structurize SPIRV
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:114
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
BinaryOperator * Mul
static const fltSemantics & IEEEsingle()
Definition APFloat.h:296
static const fltSemantics & IEEEdouble()
Definition APFloat.h:297
static const fltSemantics & IEEEhalf()
Definition APFloat.h:294
static APFloat getOne(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative One.
Definition APFloat.h:1143
static APFloat getZero(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Zero.
Definition APFloat.h:1134
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:235
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:676
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:679
@ ICMP_SLT
signed less than
Definition InstrTypes.h:705
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:706
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:682
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition InstrTypes.h:691
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:680
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:681
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:700
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:699
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:703
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition InstrTypes.h:690
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:684
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition InstrTypes.h:687
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:701
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition InstrTypes.h:688
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:683
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:685
@ ICMP_NE
not equal
Definition InstrTypes.h:698
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:704
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition InstrTypes.h:692
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:702
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition InstrTypes.h:689
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:686
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
unsigned size() const
Definition DenseMap.h:110
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:358
Represents a call to an intrinsic.
Intrinsic::ID getIntrinsicID() const
unsigned getAddressSpace() const
Module * getParent()
Get the module that this global value is contained inside of...
@ InternalLinkage
Rename collisions when linking (static functions).
Definition GlobalValue.h:60
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:354
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Helper class to build MachineInstr.
MachineBasicBlock::iterator getInsertPt()
Current insertion point for new instructions.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
void constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
LLVM_ABI unsigned getNumExplicitDefs() const
Returns the number of non-implicit definitions.
LLVM_ABI void emitGenericError(const Twine &ErrMsg) const
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
A description of a memory reference used in the backend.
@ MOVolatile
The memory access is volatile.
@ MONonTemporal
The memory access is non-temporal.
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.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
defusechain_instr_iterator< true, false, false, true > use_instr_iterator
use_instr_iterator/use_instr_begin/use_instr_end - Walk all uses of the specified register,...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
use_instr_iterator use_instr_begin(Register RegNo) const
static def_instr_iterator def_instr_end()
defusechain_instr_iterator< false, true, false, true > def_instr_iterator
def_instr_iterator/def_instr_begin/def_instr_end - Walk all defs of the specified register,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
def_instr_iterator def_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
static use_instr_iterator use_instr_end()
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
const MachineFunction & getMF() const
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
iterator_range< use_instr_iterator > use_instructions(Register Reg) const
unsigned getNumVirtRegs() const
getNumVirtRegs - Return the number of virtual registers created.
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
Analysis providing profile information.
Holds all the information related to register banks.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
bool isScalarOrVectorSigned(SPIRVTypeInst Type) const
SPIRVTypeInst getOrCreateOpTypeSampledImage(SPIRVTypeInst ImageType, MachineIRBuilder &MIRBuilder)
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg, const MachineFunction &MF)
const TargetRegisterClass * getRegClass(SPIRVTypeInst SpvType) const
MachineInstr * getOrAddMemAliasingINTELInst(MachineIRBuilder &MIRBuilder, const MDNode *AliasingListMD)
bool isAggregateType(SPIRVTypeInst Type) const
unsigned getScalarOrVectorBitWidth(SPIRVTypeInst Type) const
SPIRVTypeInst getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
Register buildGlobalVariable(Register Reg, SPIRVTypeInst BaseType, StringRef Name, const GlobalValue *GV, SPIRV::StorageClass::StorageClass Storage, const MachineInstr *Init, bool IsConst, const std::optional< SPIRV::LinkageType::LinkageType > &LinkageType, MachineIRBuilder &MIRBuilder, bool IsInstSelector)
SPIRVTypeInst getResultType(Register VReg, MachineFunction *MF=nullptr)
unsigned getScalarOrVectorComponentCount(Register VReg) const
const Type * getTypeForSPIRVType(SPIRVTypeInst Ty) const
bool isBitcastCompatible(SPIRVTypeInst Type1, SPIRVTypeInst Type2) const
Register getOrCreateConstFP(APFloat Val, MachineInstr &I, SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII, bool ZeroAsNull=true)
LLT getRegType(SPIRVTypeInst SpvType) const
void invalidateMachineInstr(MachineInstr *MI)
SPIRVTypeInst getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder, bool EmitIR)
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC)
bool isScalarOfType(Register VReg, unsigned TypeOpcode) const
Register getSPIRVTypeID(SPIRVTypeInst SpirvType) const
Register getOrCreateConstInt(uint64_t Val, MachineInstr &I, SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII, bool ZeroAsNull=true)
Register getOrCreateConstIntArray(uint64_t Val, size_t Num, MachineInstr &I, SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII)
bool findValueAttrs(const MachineInstr *Key, Type *&Ty, StringRef &Name)
SPIRVTypeInst retrieveScalarOrVectorIntType(SPIRVTypeInst Type) const
Register getOrCreateGlobalVariableWithBinding(SPIRVTypeInst VarType, uint32_t Set, uint32_t Binding, StringRef Name, MachineIRBuilder &MIRBuilder)
SPIRVTypeInst changePointerStorageClass(SPIRVTypeInst PtrType, SPIRV::StorageClass::StorageClass SC, MachineInstr &I)
Register getOrCreateConstVector(uint64_t Val, MachineInstr &I, SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII, bool ZeroAsNull=true)
Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder, SPIRVTypeInst SpvType=nullptr)
void addGlobalObject(const Value *V, const MachineFunction *MF, Register R)
SPIRVTypeInst getScalarOrVectorComponentType(SPIRVTypeInst Type) const
void recordFunctionPointer(const MachineOperand *MO, const Function *F)
SPIRVTypeInst getOrCreateSPIRVFloatType(unsigned BitWidth, MachineInstr &I, const SPIRVInstrInfo &TII)
SPIRVTypeInst getPointeeType(SPIRVTypeInst PtrType)
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const
MachineFunction * setCurrentFunc(MachineFunction &MF)
Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder, SPIRVTypeInst SpvType)
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
Type * getDeducedGlobalValueType(const GlobalValue *Global)
Register getOrCreateUndef(MachineInstr &I, SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII)
SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const
bool erase(const MachineInstr *MI)
bool add(SPIRV::IRHandle Handle, const MachineInstr *MI)
Register find(SPIRV::IRHandle Handle, const MachineFunction *MF)
bool isPhysicalSPIRV() const
bool isAtLeastSPIRVVer(VersionTuple VerToCompareTo) const
bool canUseExtInstSet(SPIRV::InstructionSet::InstructionSet E) const
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
bool erase(PtrType Ptr)
Remove pointer from the set.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
constexpr size_t size() const
size - Get the string size.
Definition StringRef.h:143
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:483
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
@ HalfTyID
16-bit floating point type
Definition Type.h:57
@ FloatTyID
32-bit floating point type
Definition Type.h:59
@ DoubleTyID
64-bit floating point type
Definition Type.h:60
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:370
bool isStructTy() const
True if this is an instance of StructType.
Definition Type.h:278
bool isAggregateType() const
Return true if the type is an aggregate type.
Definition Type.h:321
TypeID getTypeID() const
Return the type id for the type.
Definition Type.h:138
Value * getOperand(unsigned i) const
Definition User.h:207
bool hasName() const
Definition Value.h:262
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:322
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition ilist_node.h:348
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char IsConst[]
Key for Kernel::Arg::Metadata::mIsConst.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
NodeAddr< InstrNode * > Instr
Definition RDFGraph.h:389
NodeAddr< UseNode * > Use
Definition RDFGraph.h:385
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
Definition SFrame.h:77
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
void buildOpName(Register Target, const StringRef &Name, MachineIRBuilder &MIRBuilder)
@ Offset
Definition DWP.cpp:532
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1739
int64_t getIConstValSext(Register ConstReg, const MachineRegisterInfo *MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool isTypeFoldingSupported(unsigned Opcode)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
Definition InstrProf.h:296
void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB)
LLVM_ABI void salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI)
Assuming the instruction MI is going to be deleted, attempt to salvage debug users of MI by writing t...
Definition Utils.cpp:1725
LLVM_ABI void 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.
Register createVirtualRegister(SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF)
unsigned getArrayComponentCount(const MachineRegisterInfo *MRI, const MachineInstr *ResType)
uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI)
SmallVector< MachineInstr *, 4 > createContinuedInstructions(MachineIRBuilder &MIRBuilder, unsigned Opcode, unsigned MinWC, unsigned ContinuedOpcode, ArrayRef< Register > Args, Register ReturnRegister, Register TypeID)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
constexpr unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)
Definition SPIRVUtils.h:247
MachineBasicBlock::iterator getFirstValidInstructionInsertPoint(MachineBasicBlock &BB)
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, const std::vector< uint32_t > &DecArgs, StringRef StrImm)
MachineBasicBlock::iterator getOpVariableMBBIt(MachineInstr &I)
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
Type * toTypedPointer(Type *Ty)
Definition SPIRVUtils.h:465
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr bool isGenericCastablePtr(SPIRV::StorageClass::StorageClass SC)
Definition SPIRVUtils.h:232
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
MachineInstr * passCopy(MachineInstr *Def, const MachineRegisterInfo *MRI)
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
std::optional< SPIRV::LinkageType::LinkageType > getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV)
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
AtomicOrdering
Atomic ordering for LLVM's memory model.
SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id)
InstructionSelector * createSPIRVInstructionSelector(const SPIRVTargetMachine &TM, const SPIRVSubtarget &Subtarget, const RegisterBankInfo &RBI)
std::string getStringValueFromReg(Register Reg, MachineRegisterInfo &MRI)
int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
MachineInstr * getDefInstrMaybeConstant(Register &ConstReg, const MachineRegisterInfo *MRI)
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
bool hasInitializer(const GlobalVariable *GV)
Definition SPIRVUtils.h:349
void addStringImm(const StringRef &Str, MCInst &Inst)
MachineInstr * getVRegDef(MachineRegisterInfo &MRI, Register Reg)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
std::string getLinkStringForBuiltIn(SPIRV::BuiltIn::BuiltIn BuiltInValue)
LLVM_ABI bool isTriviallyDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
Check whether an instruction MI is dead: it only defines dead virtual registers, and doesn't have oth...
Definition Utils.cpp:220
#define N