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