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