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
15#include "MCTargetDesc/SPIRVBaseInfo.h"
16#include "MCTargetDesc/SPIRVMCTargetDesc.h"
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"
25#include "llvm/ADT/STLExtras.h"
26#include "llvm/ADT/STLFunctionalExtras.h"
27#include "llvm/ADT/SmallSet.h"
28#include "llvm/ADT/StringExtras.h"
29#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
30#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
31#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
32#include "llvm/CodeGen/MachineInstrBuilder.h"
33#include "llvm/CodeGen/MachineRegisterInfo.h"
34#include "llvm/CodeGen/Register.h"
35#include "llvm/CodeGen/TargetOpcodes.h"
36#include "llvm/IR/DiagnosticInfo.h"
37#include "llvm/IR/IntrinsicsSPIRV.h"
38#include "llvm/Support/Debug.h"
39#include "llvm/Support/ErrorHandling.h"
40#include <functional>
41#include <optional>
42
43#define DEBUG_TYPE "spirv-isel"
44
45using namespace llvm;
46namespace CL = SPIRV::OpenCLExtInst;
47namespace GL = SPIRV::GLSLExtInst;
48
49using ExtInstList =
50 std::vector<std::pair<SPIRV::InstructionSet::InstructionSet, uint32_t>>;
51
52namespace {
53
54struct ImageOperands {
55 std::optional<Register> Bias;
56 std::optional<Register> Offset;
57 std::optional<Register> MinLod;
58 std::optional<Register> GradX;
59 std::optional<Register> GradY;
60 std::optional<Register> Lod;
61 std::optional<Register> Compare;
62};
63
64llvm::SPIRV::SelectionControl::SelectionControl
65getSelectionOperandForImm(int Imm) {
66 if (Imm == 2)
67 return SPIRV::SelectionControl::Flatten;
68 if (Imm == 1)
69 return SPIRV::SelectionControl::DontFlatten;
70 if (Imm == 0)
71 return SPIRV::SelectionControl::None;
72 llvm_unreachable("Invalid immediate");
73}
74
75#define GET_GLOBALISEL_PREDICATE_BITSET
76#include "SPIRVGenGlobalISel.inc"
77#undef GET_GLOBALISEL_PREDICATE_BITSET
78
79class SPIRVInstructionSelector : public InstructionSelector {
80 const SPIRVSubtarget &STI;
81 const SPIRVInstrInfo &TII;
82 const SPIRVRegisterInfo &TRI;
83 const RegisterBankInfo &RBI;
84 SPIRVGlobalRegistry &GR;
85 MachineRegisterInfo *MRI;
86 MachineFunction *HasVRegsReset = nullptr;
87
88 /// We need to keep track of the number we give to anonymous global values to
89 /// generate the same name every time when this is needed.
90 mutable DenseMap<const GlobalValue *, unsigned> UnnamedGlobalIDs;
91 SmallPtrSet<MachineInstr *, 8> DeadMIs;
92
93public:
94 SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
95 const SPIRVSubtarget &ST,
96 const RegisterBankInfo &RBI);
97 void setupMF(MachineFunction &MF, GISelValueTracking *VT,
98 CodeGenCoverage *CoverageInfo, ProfileSummaryInfo *PSI,
99 BlockFrequencyInfo *BFI) override;
100 // Common selection code. Instruction-specific selection occurs in spvSelect.
101 bool select(MachineInstr &I) override;
102 static const char *getName() { return DEBUG_TYPE; }
103
104#define GET_GLOBALISEL_PREDICATES_DECL
105#include "SPIRVGenGlobalISel.inc"
106#undef GET_GLOBALISEL_PREDICATES_DECL
107
108#define GET_GLOBALISEL_TEMPORARIES_DECL
109#include "SPIRVGenGlobalISel.inc"
110#undef GET_GLOBALISEL_TEMPORARIES_DECL
111
112private:
113 void resetVRegsType(MachineFunction &MF);
114 void removeDeadInstruction(MachineInstr &MI) const;
115 void removeOpNamesForDeadMI(MachineInstr &MI) const;
116
117 // tblgen-erated 'select' implementation, used as the initial selector for
118 // the patterns that don't require complex C++.
119 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
120
121 // All instruction-specific selection that didn't happen in "select()".
122 // Is basically a large Switch/Case delegating to all other select method.
123 bool spvSelect(Register ResVReg, SPIRVTypeInst ResType,
124 MachineInstr &I) const;
125
126 bool selectFirstBitHigh(Register ResVReg, SPIRVTypeInst ResType,
127 MachineInstr &I, bool IsSigned) const;
128
129 bool selectFirstBitLow(Register ResVReg, SPIRVTypeInst ResType,
130 MachineInstr &I) const;
131
132 bool selectFirstBitSet16(Register ResVReg, SPIRVTypeInst ResType,
133 MachineInstr &I, unsigned ExtendOpcode,
134 unsigned BitSetOpcode) const;
135
136 bool selectFirstBitSet32(Register ResVReg, SPIRVTypeInst ResType,
137 MachineInstr &I, Register SrcReg,
138 unsigned BitSetOpcode) const;
139
140 bool selectFirstBitSet64(Register ResVReg, SPIRVTypeInst ResType,
141 MachineInstr &I, Register SrcReg,
142 unsigned BitSetOpcode, 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, ArrayRef<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 selectAtomicLoad(Register ResVReg, SPIRVTypeInst ResType,
160 MachineInstr &I) const;
161 bool selectStore(MachineInstr &I) const;
162 bool selectAtomicStore(MachineInstr &I) const;
163
164 bool selectStackSave(Register ResVReg, SPIRVTypeInst ResType,
165 MachineInstr &I) const;
166 bool selectStackRestore(MachineInstr &I) const;
167
168 bool selectMemOperation(Register ResVReg, MachineInstr &I) const;
169 Register getOrCreateMemSetGlobal(MachineInstr &I) const;
170 bool selectCopyMemory(MachineInstr &I, Register SrcReg) const;
171
172 bool selectAtomicRMW(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
173 unsigned NewOpcode, unsigned NegateOpcode = 0) const;
174
175 // Creates an integer-typed register with bitwidth equal to pointer size.
176 Register createPtrSizedIntReg(MachineIRBuilder &MIRBuilder) const;
177 // Emit an OpConvertPtrToU that converts the pointer value in \p PtrVal into
178 // an integer of equal bitwidth, returning the register holding the result.
179 Register convertPtrToInt(Register PtrVal, MachineIRBuilder &MIRBuilder) const;
180 // Emit an OpBitcast that reinterprets the pointer \p Ptr as a pointer to an
181 // integer of pointer size in storage class \p SC, returning the result.
182 Register castPtrToPtrToInt(Register Ptr, SPIRV::StorageClass::StorageClass SC,
183 MachineIRBuilder &MIRBuilder) const;
184 // Handle atomic loads, stores and exchanges of pointer types by casting
185 // to/from integer types as needed.
186 bool selectAtomicPtrValue(
187 Register ResVReg, SPIRVTypeInst ResType, MachineIRBuilder &MIRBuilder,
188 function_ref<Register(SPIRVTypeInst IntType)> EmitAtomic) const;
189
190 bool selectAtomicCmpXchg(Register ResVReg, SPIRVTypeInst ResType,
191 MachineInstr &I) const;
192
193 bool selectFence(MachineInstr &I) const;
194
195 bool selectAddrSpaceCast(Register ResVReg, SPIRVTypeInst ResType,
196 MachineInstr &I) const;
197
198 bool selectPtrMask(Register ResVReg, SPIRVTypeInst ResType,
199 MachineInstr &I) const;
200
201 bool selectAnyOrAll(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
202 unsigned OpType) const;
203
204 bool selectAll(Register ResVReg, SPIRVTypeInst ResType,
205 MachineInstr &I) const;
206
207 bool selectAny(Register ResVReg, SPIRVTypeInst ResType,
208 MachineInstr &I) const;
209
210 bool selectBitreverse(Register ResVReg, SPIRVTypeInst ResType,
211 MachineInstr &I) const;
212
213 bool selectBitreverseViaI32(Register ResVReg, SPIRVTypeInst ResType,
214 MachineInstr &I, Register Op) const;
215
216 bool selectBitreverse64(Register ResVReg, SPIRVTypeInst ResType,
217 MachineInstr &I, Register SrcReg) const;
218
219 bool selectBitreverseNative(Register ResVReg, SPIRVTypeInst ResType,
220 MachineInstr &I, Register Op) const;
221
222 bool selectBuildVector(Register ResVReg, SPIRVTypeInst ResType,
223 MachineInstr &I) const;
224 bool selectSplatVector(Register ResVReg, SPIRVTypeInst ResType,
225 MachineInstr &I) const;
226 bool selectConcatVectors(Register ResVReg, SPIRVTypeInst ResType,
227 MachineInstr &I) const;
228
229 bool selectCmp(Register ResVReg, SPIRVTypeInst ResType,
230 unsigned comparisonOpcode, MachineInstr &I) const;
231 bool selectDiscard(Register ResVReg, SPIRVTypeInst ResType,
232 MachineInstr &I) const;
233
234 bool selectICmp(Register ResVReg, SPIRVTypeInst ResType,
235 MachineInstr &I) const;
236 bool selectFCmp(Register ResVReg, SPIRVTypeInst ResType,
237 MachineInstr &I) const;
238
239 bool selectSign(Register ResVReg, SPIRVTypeInst ResType,
240 MachineInstr &I) const;
241
242 bool selectFloatDot(Register ResVReg, SPIRVTypeInst ResType,
243 MachineInstr &I) const;
244
245 bool selectOverflowArith(Register ResVReg, SPIRVTypeInst ResType,
246 MachineInstr &I, unsigned Opcode) const;
247 bool selectDebugTrap(Register ResVReg, SPIRVTypeInst ResType,
248 MachineInstr &I) const;
249 bool selectPrefetch(MachineInstr &I) const;
250
251 bool selectIntegerDot(Register ResVReg, SPIRVTypeInst ResType,
252 MachineInstr &I, bool Signed) const;
253
254 bool selectIntegerDotExpansion(Register ResVReg, SPIRVTypeInst ResType,
255 MachineInstr &I) const;
256
257 bool selectOpIsInf(Register ResVReg, SPIRVTypeInst ResType,
258 MachineInstr &I) const;
259
260 bool selectOpIsNan(Register ResVReg, SPIRVTypeInst ResType,
261 MachineInstr &I) const;
262
263 bool selectOpIsFinite(Register ResVReg, SPIRVTypeInst ResType,
264 MachineInstr &I) const;
265
266 bool selectOpIsNormal(Register ResVReg, SPIRVTypeInst ResType,
267 MachineInstr &I) const;
268
269 bool selectPopCount(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
270 unsigned Opcode) const;
271
272 bool selectPopCount16(Register ResVReg, SPIRVTypeInst ResType,
273 MachineInstr &I, unsigned ExtOpcode,
274 unsigned Opcode) const;
275
276 bool selectPopCount32(Register ResVReg, SPIRVTypeInst ResType,
277 MachineInstr &I, Register SrcReg,
278 unsigned Opcode) const;
279
280 bool selectPopCount64(Register ResVReg, SPIRVTypeInst ResType,
281 MachineInstr &I, Register SrcReg,
282 unsigned Opcode) const;
283
284 template <bool Signed>
285 bool selectDot4AddPacked(Register ResVReg, SPIRVTypeInst ResType,
286 MachineInstr &I) const;
287 template <bool Signed>
288 bool selectDot4AddPackedExpansion(Register ResVReg, SPIRVTypeInst ResType,
289 MachineInstr &I) const;
290
291 bool selectWavePrefixBitCount(Register ResVReg, SPIRVTypeInst ResType,
292 MachineInstr &I) const;
293
294 template <typename PickOpcodeFn>
295 bool selectWaveReduce(Register ResVReg, SPIRVTypeInst ResType,
296 MachineInstr &I, bool IsUnsigned,
297 PickOpcodeFn &&PickOpcode) const;
298
299 bool selectWaveReduceOp(Register ResVReg, SPIRVTypeInst ResType,
300 MachineInstr &I, unsigned Opcode) const;
301
302 bool selectWaveReduceMax(Register ResVReg, SPIRVTypeInst ResType,
303 MachineInstr &I, bool IsUnsigned) const;
304
305 bool selectWaveReduceMin(Register ResVReg, SPIRVTypeInst ResType,
306 MachineInstr &I, bool IsUnsigned) const;
307
308 bool selectWaveReduceSum(Register ResVReg, SPIRVTypeInst ResType,
309 MachineInstr &I) const;
310
311 bool selectWaveReduceProduct(Register ResVReg, const SPIRVTypeInst ResType,
312 MachineInstr &I) const;
313
314 template <typename PickOpcodeFn>
315 bool selectWaveExclusiveScan(Register ResVReg, SPIRVTypeInst ResType,
316 MachineInstr &I, bool IsUnsigned,
317 PickOpcodeFn &&PickOpcode) const;
318
319 bool selectWaveExclusiveScanSum(Register ResVReg, SPIRVTypeInst ResType,
320 MachineInstr &I) const;
321
322 bool selectWaveExclusiveScanProduct(Register ResVReg, SPIRVTypeInst ResType,
323 MachineInstr &I) const;
324
325 bool selectQuadSwap(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
326 unsigned Direction) const;
327
328 bool selectConst(Register ResVReg, SPIRVTypeInst ResType,
329 MachineInstr &I) const;
330
331 bool selectSelect(Register ResVReg, SPIRVTypeInst ResType,
332 MachineInstr &I) const;
333 bool selectBoolToInt(Register ResVReg, SPIRVTypeInst ResType,
334 Register BooleanVReg, MachineInstr &InsertAt,
335 bool IsSigned) const;
336 bool selectIToF(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
337 bool IsSigned, unsigned Opcode) const;
338 bool selectExt(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
339 bool IsSigned) const;
340
341 bool selectTrunc(Register ResVReg, SPIRVTypeInst ResType,
342 MachineInstr &I) const;
343
344 bool selectSUCmp(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
345 bool IsSigned) const;
346
347 bool selectIntToBool(Register IntReg, Register ResVReg, MachineInstr &I,
348 SPIRVTypeInst intTy, SPIRVTypeInst boolTy) const;
349
350 bool selectOpUndef(Register ResVReg, SPIRVTypeInst ResType,
351 MachineInstr &I) const;
352 bool selectFreeze(Register ResVReg, SPIRVTypeInst ResType,
353 MachineInstr &I) const;
354 bool selectIntrinsic(Register ResVReg, SPIRVTypeInst ResType,
355 MachineInstr &I) const;
356 bool selectExtractVal(Register ResVReg, SPIRVTypeInst ResType,
357 MachineInstr &I) const;
358 bool selectInsertVal(Register ResVReg, SPIRVTypeInst ResType,
359 MachineInstr &I) const;
360 bool selectExtractElt(Register ResVReg, SPIRVTypeInst ResType,
361 MachineInstr &I) const;
362 bool selectInsertElt(Register ResVReg, SPIRVTypeInst ResType,
363 MachineInstr &I) const;
364 bool selectGEP(Register ResVReg, SPIRVTypeInst ResType,
365 MachineInstr &I) const;
366
367 bool selectMaskedGather(Register ResVReg, SPIRVTypeInst ResType,
368 MachineInstr &I) const;
369 bool selectMaskedScatter(MachineInstr &I) const;
370
371 bool diagnoseUnsupported(const MachineInstr &I, const Twine &Msg) const;
372
373 bool selectAbort(MachineInstr &I) const;
374 bool selectTrap(MachineInstr &I) const;
375 bool selectFrameIndex(Register ResVReg, SPIRVTypeInst ResType,
376 MachineInstr &I) const;
377 bool selectAllocaArray(Register ResVReg, SPIRVTypeInst ResType,
378 MachineInstr &I) const;
379
380 bool selectBranch(MachineInstr &I) const;
381 bool selectBranchCond(MachineInstr &I) const;
382
383 bool selectPhi(Register ResVReg, MachineInstr &I) const;
384
385 bool selectExtInst(Register ResVReg, SPIRVTypeInst RestType, MachineInstr &I,
386 GL::GLSLExtInst GLInst, bool setMIFlags = true,
387 bool useMISrc = true,
388 ArrayRef<Register> SrcRegs = {}) const;
389 bool selectExtInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
390 CL::OpenCLExtInst CLInst, bool setMIFlags = true,
391 bool useMISrc = true,
392 ArrayRef<Register> SrcRegs = {}) const;
393 bool selectExtInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
394 CL::OpenCLExtInst CLInst, GL::GLSLExtInst GLInst,
395 bool setMIFlags = true, bool useMISrc = true,
396 ArrayRef<Register> SrcRegs = {}) const;
397 bool selectExtInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
398 const ExtInstList &ExtInsts, bool setMIFlags = true,
399 bool useMISrc = true,
400 ArrayRef<Register> SrcRegs = {}) const;
401
402 bool selectLog10(Register ResVReg, SPIRVTypeInst ResType,
403 MachineInstr &I) const;
404
405 bool selectFpowi(Register ResVReg, SPIRVTypeInst ResType,
406 MachineInstr &I) const;
407
408 bool selectSaturate(Register ResVReg, SPIRVTypeInst ResType,
409 MachineInstr &I) const;
410
411 bool selectWaveOpInst(Register ResVReg, SPIRVTypeInst ResType,
412 MachineInstr &I, unsigned Opcode) const;
413
414 bool selectBarrierInst(MachineInstr &I, unsigned Scope, unsigned MemSem,
415 bool WithGroupSync) const;
416
417 bool selectWaveActiveCountBits(Register ResVReg, SPIRVTypeInst ResType,
418 MachineInstr &I) const;
419
420 bool selectWaveActiveAllEqual(Register ResVReg, SPIRVTypeInst ResType,
421 MachineInstr &I) const;
422
423 bool selectUnmergeValues(MachineInstr &I) const;
424
425 bool selectHandleFromBinding(Register &ResVReg, SPIRVTypeInst ResType,
426 MachineInstr &I) const;
427
428 bool selectCounterHandleFromBinding(Register &ResVReg, SPIRVTypeInst ResType,
429 MachineInstr &I) const;
430
431 bool selectReadImageIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
432 MachineInstr &I) const;
433 bool selectGetDimensionsIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
434 MachineInstr &I) const;
435 bool selectGetDimensionsLevelsIntrinsic(Register &ResVReg,
436 SPIRVTypeInst ResType,
437 MachineInstr &I) const;
438 bool selectGetDimensionsMSIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
439 MachineInstr &I) const;
440 bool
441 selectImageQuerySize(Register ImageReg, Register &ResVReg, MachineInstr &I,
442 std::optional<Register> LodReg = std::nullopt) const;
443 bool selectSampleBasicIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
444 MachineInstr &I) const;
445 bool selectCalculateLodIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
446 MachineInstr &I) const;
447 bool selectSampleBiasIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
448 MachineInstr &I) const;
449 bool selectSampleGradIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
450 MachineInstr &I) const;
451 bool selectSampleLevelIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
452 MachineInstr &I) const;
453 bool selectLoadLevelIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
454 MachineInstr &I) const;
455 bool selectSampleCmpIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
456 MachineInstr &I) const;
457 bool selectSampleCmpLevelZeroIntrinsic(Register &ResVReg,
458 SPIRVTypeInst ResType,
459 MachineInstr &I) const;
460 bool selectGatherIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
461 MachineInstr &I) const;
462 bool selectImageWriteIntrinsic(MachineInstr &I) const;
463 bool selectResourceGetPointer(Register &ResVReg, SPIRVTypeInst ResType,
464 MachineInstr &I) const;
465 bool selectPushConstantGetPointer(Register &ResVReg, SPIRVTypeInst ResType,
466 MachineInstr &I) const;
467 bool selectResourceNonUniformIndex(Register &ResVReg, SPIRVTypeInst ResType,
468 MachineInstr &I) const;
469 bool selectModf(Register ResVReg, SPIRVTypeInst ResType,
470 MachineInstr &I) const;
471 bool selectUpdateCounter(Register &ResVReg, SPIRVTypeInst ResType,
472 MachineInstr &I) const;
473 bool selectFrexp(Register ResVReg, SPIRVTypeInst ResType,
474 MachineInstr &I) const;
475
476 bool selectCopySign(Register ResVReg, SPIRVTypeInst ResType,
477 MachineInstr &I) const;
478
479 bool selectLdexp(Register ResVReg, SPIRVTypeInst ResType,
480 MachineInstr &I) const;
481 bool selectSincos(Register ResVReg, SPIRVTypeInst ResType,
482 MachineInstr &I) const;
483 bool selectExp10(Register ResVReg, SPIRVTypeInst ResType,
484 MachineInstr &I) const;
485 bool selectDerivativeInst(Register ResVReg, SPIRVTypeInst ResType,
486 MachineInstr &I, const unsigned DPdOpCode) const;
487 // Utilities
488 Register buildI32Constant(uint32_t Val, MachineInstr &I,
489 SPIRVTypeInst ResType = nullptr) const;
490 Register buildI32ConstantInEntryBlock(uint32_t Val, MachineInstr &I,
491 SPIRVTypeInst ResType = nullptr) const;
492
493 Register buildZerosVal(SPIRVTypeInst ResType, MachineInstr &I) const;
494 bool isScalarOrVectorIntConstantZero(Register Reg) const;
495 Register buildZerosValF(SPIRVTypeInst ResType, MachineInstr &I) const;
496 Register buildOnesVal(bool AllOnes, SPIRVTypeInst ResType,
497 MachineInstr &I) const;
498 Register buildOnesValF(SPIRVTypeInst ResType, MachineInstr &I) const;
499 Register buildVectorSplat(Register ScalarReg, unsigned NumElts,
500 MachineInstr &I) const;
501
502 bool wrapIntoSpecConstantOp(MachineInstr &I,
503 SmallVector<Register> &CompositeArgs) const;
504
505 Register getUcharPtrTypeReg(MachineInstr &I,
506 SPIRV::StorageClass::StorageClass SC) const;
507 MachineInstrBuilder buildSpecConstantOp(MachineInstr &I, Register Dest,
508 Register Src, Register DestType,
509 uint32_t Opcode) const;
510 MachineInstrBuilder buildConstGenericPtr(MachineInstr &I, Register SrcPtr,
511 SPIRVTypeInst SrcPtrTy) const;
512 Register buildPointerToResource(SPIRVTypeInst ResType,
513 SPIRV::StorageClass::StorageClass SC,
514 uint32_t Set, uint32_t Binding,
515 uint32_t ArraySize, Register IndexReg,
516 StringRef Name,
517 MachineIRBuilder MIRBuilder) const;
518 SPIRVTypeInst widenTypeToVec4(SPIRVTypeInst Type, MachineInstr &I) const;
519 bool extractSubvector(Register &ResVReg, SPIRVTypeInst ResType,
520 Register &ReadReg, MachineInstr &InsertionPoint) const;
521 bool generateImageReadOrFetch(Register &ResVReg, SPIRVTypeInst ResType,
522 Register ImageReg, Register IdxReg,
523 DebugLoc Loc, MachineInstr &Pos,
524 const ImageOperands *ImOps = nullptr) const;
525 bool generateSampleImage(Register ResVReg, SPIRVTypeInst ResType,
526 Register ImageReg, Register SamplerReg,
527 Register CoordinateReg, const ImageOperands &ImOps,
528 DebugLoc Loc, MachineInstr &I) const;
529 bool BuildCOPY(Register DestReg, Register SrcReg, MachineInstr &I) const;
530 bool loadVec3BuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue,
531 Register ResVReg, SPIRVTypeInst ResType,
532 MachineInstr &I) const;
533 bool loadBuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue,
534 Register ResVReg, SPIRVTypeInst ResType,
535 MachineInstr &I) const;
536 bool loadHandleBeforePosition(Register &HandleReg, SPIRVTypeInst ResType,
537 GIntrinsic &HandleDef, MachineInstr &Pos) const;
538 void decorateUsesAsNonUniform(Register &NonUniformReg) const;
539 bool errorIfInstrOutsideShader(MachineInstr &I) const;
540
541 bool
542 handle64BitOverflow(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
543 Register SrcReg, unsigned int Opcode,
544 std::function<bool(Register, SPIRVTypeInst,
545 MachineInstr &, Register, unsigned)>
546 CallbackFunction) const;
547};
548
549bool sampledTypeIsSignedInteger(const llvm::Type *HandleType) {
550 const TargetExtType *TET = cast<TargetExtType>(Val: HandleType);
551 if (TET->getTargetExtName() == "spirv.Image") {
552 return false;
553 }
554 assert(TET->getTargetExtName() == "spirv.SignedImage");
555 return TET->getTypeParameter(i: 0)->isIntegerTy();
556}
557} // end anonymous namespace
558
559#define GET_GLOBALISEL_IMPL
560#include "SPIRVGenGlobalISel.inc"
561#undef GET_GLOBALISEL_IMPL
562
563SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
564 const SPIRVSubtarget &ST,
565 const RegisterBankInfo &RBI)
566 : InstructionSelector(), STI(ST), TII(*ST.getInstrInfo()),
567 TRI(*ST.getRegisterInfo()), RBI(RBI), GR(*ST.getSPIRVGlobalRegistry()),
568 MRI(nullptr),
569#define GET_GLOBALISEL_PREDICATES_INIT
570#include "SPIRVGenGlobalISel.inc"
571#undef GET_GLOBALISEL_PREDICATES_INIT
572#define GET_GLOBALISEL_TEMPORARIES_INIT
573#include "SPIRVGenGlobalISel.inc"
574#undef GET_GLOBALISEL_TEMPORARIES_INIT
575{
576}
577
578void SPIRVInstructionSelector::setupMF(MachineFunction &MF,
579 GISelValueTracking *VT,
580 CodeGenCoverage *CoverageInfo,
581 ProfileSummaryInfo *PSI,
582 BlockFrequencyInfo *BFI) {
583 MRI = &MF.getRegInfo();
584 GR.setCurrentFunc(MF);
585 InstructionSelector::setupMF(mf&: MF, vt: VT, covinfo: CoverageInfo, psi: PSI, bfi: BFI);
586}
587
588// Ensure that register classes correspond to pattern matching rules.
589void SPIRVInstructionSelector::resetVRegsType(MachineFunction &MF) {
590 if (HasVRegsReset == &MF)
591 return;
592 HasVRegsReset = &MF;
593
594 MachineRegisterInfo &MRI = MF.getRegInfo();
595 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
596 Register Reg = Register::index2VirtReg(Index: I);
597 LLT RegType = MRI.getType(Reg);
598 if (RegType.isScalar())
599 MRI.setType(VReg: Reg, Ty: LLT::scalar(SizeInBits: 64));
600 else if (RegType.isPointer())
601 MRI.setType(VReg: Reg, Ty: LLT::pointer(AddressSpace: 0, SizeInBits: 64));
602 else if (RegType.isVector())
603 MRI.setType(VReg: Reg, Ty: LLT::fixed_vector(NumElements: 2, ScalarTy: LLT::scalar(SizeInBits: 64)));
604 }
605 for (const auto &MBB : MF) {
606 for (const auto &MI : MBB) {
607 if (isPreISelGenericOpcode(Opcode: MI.getOpcode()))
608 GR.erase(MI: &MI);
609 if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)
610 continue;
611
612 Register DstReg = MI.getOperand(i: 0).getReg();
613 LLT DstType = MRI.getType(Reg: DstReg);
614 Register SrcReg = MI.getOperand(i: 1).getReg();
615 LLT SrcType = MRI.getType(Reg: SrcReg);
616 if (DstType != SrcType)
617 MRI.setType(VReg: DstReg, Ty: MRI.getType(Reg: SrcReg));
618
619 const TargetRegisterClass *DstRC = MRI.getRegClassOrNull(Reg: DstReg);
620 const TargetRegisterClass *SrcRC = MRI.getRegClassOrNull(Reg: SrcReg);
621 if (DstRC != SrcRC && SrcRC)
622 MRI.setRegClass(Reg: DstReg, RC: SrcRC);
623 }
624 }
625}
626
627// Return true if the MachineInstr represents a constant register
628static bool isConstReg(MachineRegisterInfo *MRI, MachineInstr *OpDef) {
629
630 SmallVector<MachineInstr *> Stack = {OpDef};
631 SmallPtrSet<MachineInstr *, 4> Visited;
632
633 while (!Stack.empty()) {
634 MachineInstr *MI = Stack.pop_back_val();
635 MI = passCopy(Def: MI, MRI);
636 if (!Visited.insert(Ptr: MI).second)
637 continue;
638 switch (MI->getOpcode()) {
639 case TargetOpcode::G_INTRINSIC:
640 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
641 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: {
642 GIntrinsic *GIntr = cast<GIntrinsic>(Val: MI);
643 unsigned IntrID = GIntr->getIntrinsicID();
644 if (IntrID != Intrinsic::spv_const_composite &&
645 IntrID != Intrinsic::spv_undef && IntrID != Intrinsic::spv_poison)
646 return false;
647 continue;
648 }
649 case TargetOpcode::G_BUILD_VECTOR:
650 case TargetOpcode::G_SPLAT_VECTOR:
651 for (unsigned i = OpDef->getNumExplicitDefs();
652 i < OpDef->getNumOperands(); i++) {
653 if (!OpDef->getOperand(i).isReg())
654 continue;
655 MachineInstr *OpNestedDef =
656 MRI->getVRegDef(Reg: OpDef->getOperand(i).getReg());
657 Stack.push_back(Elt: OpNestedDef);
658 }
659 continue;
660 case TargetOpcode::G_CONSTANT:
661 case TargetOpcode::G_FCONSTANT:
662 case TargetOpcode::G_IMPLICIT_DEF:
663 case SPIRV::OpConstantTrue:
664 case SPIRV::OpConstantFalse:
665 case SPIRV::OpConstantI:
666 case SPIRV::OpConstantF:
667 case SPIRV::OpConstantComposite:
668 case SPIRV::OpConstantCompositeContinuedINTEL:
669 case SPIRV::OpConstantSampler:
670 case SPIRV::OpConstantNull:
671 case SPIRV::OpUndef:
672 case SPIRV::OpPoisonKHR:
673 case SPIRV::OpConstantFunctionPointerINTEL:
674 continue;
675 default:
676 return false;
677 }
678 }
679 return true;
680}
681
682// Return true if the virtual register represents a constant
683static bool isConstReg(MachineRegisterInfo *MRI, Register OpReg) {
684 if (MachineInstr *OpDef = MRI->getVRegDef(Reg: OpReg))
685 return isConstReg(MRI, OpDef);
686 return false;
687}
688
689// TODO(168736): We should make this either a flag in tabelgen
690// or reduce our dependence on the global registry, so we can remove this
691// function. It can easily be missed when new intrinsics are added.
692
693// Most SPIR-V intrinsics are considered to have side-effects in their tablegen
694// definition because they are referenced in the global registry. This is a list
695// of intrinsics that have no side effects other than their references in the
696// global registry.
697static bool intrinsicHasSideEffects(Intrinsic::ID ID) {
698 switch (ID) {
699 // This is not an exhaustive list and may need to be updated.
700 case Intrinsic::spv_all:
701 case Intrinsic::spv_alloca:
702 case Intrinsic::spv_any:
703 case Intrinsic::spv_bitcast:
704 case Intrinsic::spv_const_composite:
705 case Intrinsic::spv_degrees:
706 case Intrinsic::spv_distance:
707 case Intrinsic::spv_extractelt:
708 case Intrinsic::spv_extractv:
709 case Intrinsic::spv_faceforward:
710 case Intrinsic::spv_fdot:
711 case Intrinsic::spv_firstbitlow:
712 case Intrinsic::spv_firstbitshigh:
713 case Intrinsic::spv_firstbituhigh:
714 case Intrinsic::spv_frac:
715 case Intrinsic::spv_gep:
716 case Intrinsic::spv_global_offset:
717 case Intrinsic::spv_global_size:
718 case Intrinsic::spv_group_id:
719 case Intrinsic::spv_insertelt:
720 case Intrinsic::spv_insertv:
721 case Intrinsic::spv_isinf:
722 case Intrinsic::spv_isnan:
723 case Intrinsic::spv_isfinite:
724 case Intrinsic::spv_isnormal:
725 case Intrinsic::spv_lerp:
726 case Intrinsic::spv_length:
727 case Intrinsic::spv_normalize:
728 case Intrinsic::spv_num_subgroups:
729 case Intrinsic::spv_num_workgroups:
730 case Intrinsic::spv_ptrcast:
731 case Intrinsic::spv_radians:
732 case Intrinsic::spv_reflect:
733 case Intrinsic::spv_refract:
734 case Intrinsic::spv_resource_getbasepointer:
735 case Intrinsic::spv_resource_getpointer:
736 case Intrinsic::spv_resource_handlefrombinding:
737 case Intrinsic::spv_resource_handlefromimplicitbinding:
738 case Intrinsic::spv_resource_nonuniformindex:
739 case Intrinsic::spv_resource_sample:
740 case Intrinsic::spv_rsqrt:
741 case Intrinsic::spv_saturate:
742 case Intrinsic::spv_sdot:
743 case Intrinsic::spv_sign:
744 case Intrinsic::spv_smoothstep:
745 case Intrinsic::spv_subgroup_id:
746 case Intrinsic::spv_subgroup_local_invocation_id:
747 case Intrinsic::spv_subgroup_max_size:
748 case Intrinsic::spv_subgroup_size:
749 case Intrinsic::spv_thread_id:
750 case Intrinsic::spv_thread_id_in_group:
751 case Intrinsic::spv_udot:
752 case Intrinsic::spv_undef:
753 case Intrinsic::spv_value_md:
754 case Intrinsic::spv_workgroup_size:
755 return false;
756 default:
757 return true;
758 }
759}
760
761// TODO(168736): We should make this either a flag in tabelgen
762// or reduce our dependence on the global registry, so we can remove this
763// function. It can easily be missed when new intrinsics are added.
764static bool isOpcodeWithNoSideEffects(unsigned Opcode) {
765 switch (Opcode) {
766 case SPIRV::OpTypeVoid:
767 case SPIRV::OpTypeBool:
768 case SPIRV::OpTypeInt:
769 case SPIRV::OpTypeFloat:
770 case SPIRV::OpTypeVector:
771 case SPIRV::OpTypeVectorIdEXT:
772 case SPIRV::OpTypeMatrix:
773 case SPIRV::OpTypeImage:
774 case SPIRV::OpTypeSampler:
775 case SPIRV::OpTypeSampledImage:
776 case SPIRV::OpTypeArray:
777 case SPIRV::OpTypeRuntimeArray:
778 case SPIRV::OpTypeStruct:
779 case SPIRV::OpTypeOpaque:
780 case SPIRV::OpTypePointer:
781 case SPIRV::OpTypeFunction:
782 case SPIRV::OpTypeEvent:
783 case SPIRV::OpTypeDeviceEvent:
784 case SPIRV::OpTypeReserveId:
785 case SPIRV::OpTypeQueue:
786 case SPIRV::OpTypePipe:
787 case SPIRV::OpTypeForwardPointer:
788 case SPIRV::OpTypePipeStorage:
789 case SPIRV::OpTypeNamedBarrier:
790 case SPIRV::OpTypeAccelerationStructureNV:
791 case SPIRV::OpTypeCooperativeMatrixNV:
792 case SPIRV::OpTypeCooperativeMatrixKHR:
793 return true;
794 default:
795 return false;
796 }
797}
798
799bool isDead(const MachineInstr &MI, const MachineRegisterInfo &MRI) {
800 // If there are no definitions, then assume there is some other
801 // side-effect that makes this instruction live.
802 if (MI.getNumDefs() == 0)
803 return false;
804
805 for (const auto &MO : MI.all_defs()) {
806 Register Reg = MO.getReg();
807 if (Reg.isPhysical()) {
808 LLVM_DEBUG(dbgs() << "Not dead: def of physical register " << Reg);
809 return false;
810 }
811 for (const auto &UseMI : MRI.use_nodbg_instructions(Reg)) {
812 if (UseMI.getOpcode() != SPIRV::OpName) {
813 LLVM_DEBUG(dbgs() << "Not dead: def " << MO << " has use in " << UseMI);
814 return false;
815 }
816 }
817 }
818
819 if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE || MI.isFakeUse() ||
820 MI.isLifetimeMarker()) {
821 LLVM_DEBUG(
822 dbgs()
823 << "Not dead: Opcode is LOCAL_ESCAPE, fake use, or lifetime marker.\n");
824 return false;
825 }
826 if (MI.isPHI()) {
827 LLVM_DEBUG(dbgs() << "Dead: Phi instruction with no uses.\n");
828 return true;
829 }
830
831 // It is possible that the only side effect is that the instruction is
832 // referenced in the global registry. If that is the only side effect, the
833 // intrinsic is dead.
834 if (MI.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
835 MI.getOpcode() == TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS) {
836 const auto &Intr = cast<GIntrinsic>(Val: MI);
837 if (!intrinsicHasSideEffects(ID: Intr.getIntrinsicID())) {
838 LLVM_DEBUG(dbgs() << "Dead: Intrinsic with no real side effects.\n");
839 return true;
840 }
841 }
842
843 if (MI.mayStore() || MI.isCall() ||
844 (MI.mayLoad() && MI.hasOrderedMemoryRef()) || MI.isPosition() ||
845 MI.isDebugInstr() || MI.isTerminator() || MI.isJumpTableDebugInfo()) {
846 LLVM_DEBUG(dbgs() << "Not dead: instruction has side effects.\n");
847 return false;
848 }
849
850 if (isPreISelGenericOpcode(Opcode: MI.getOpcode())) {
851 // TODO: Is there a generic way to check if the opcode has side effects?
852 LLVM_DEBUG(dbgs() << "Dead: Generic opcode with no uses.\n");
853 return true;
854 }
855
856 if (isOpcodeWithNoSideEffects(Opcode: MI.getOpcode())) {
857 LLVM_DEBUG(dbgs() << "Dead: known opcode with no side effects\n");
858 return true;
859 }
860
861 return false;
862}
863
864void SPIRVInstructionSelector::removeOpNamesForDeadMI(MachineInstr &MI) const {
865 // Delete the OpName that uses the result if there is one.
866 for (const auto &MO : MI.all_defs()) {
867 Register Reg = MO.getReg();
868 if (Reg.isPhysical())
869 continue;
870 SmallVector<MachineInstr *, 4> UselessOpNames;
871 for (MachineInstr &UseMI : MRI->use_nodbg_instructions(Reg)) {
872 assert(UseMI.getOpcode() == SPIRV::OpName &&
873 "There is still a use of the dead function.");
874 UselessOpNames.push_back(Elt: &UseMI);
875 }
876 for (MachineInstr *OpNameMI : UselessOpNames) {
877 GR.invalidateMachineInstr(MI: OpNameMI);
878 OpNameMI->eraseFromParent();
879 }
880 }
881}
882
883void SPIRVInstructionSelector::removeDeadInstruction(MachineInstr &MI) const {
884 salvageDebugInfo(MRI: *MRI, MI);
885 GR.invalidateMachineInstr(MI: &MI);
886 removeOpNamesForDeadMI(MI);
887 MI.eraseFromParent();
888}
889
890bool SPIRVInstructionSelector::select(MachineInstr &I) {
891 resetVRegsType(MF&: *I.getParent()->getParent());
892
893 assert(I.getParent() && "Instruction should be in a basic block!");
894 assert(I.getParent()->getParent() && "Instruction should be in a function!");
895
896 LLVM_DEBUG(dbgs() << "Checking if instruction is dead: " << I;);
897 if (isDead(MI: I, MRI: *MRI)) {
898 LLVM_DEBUG(dbgs() << "Instruction is dead.\n");
899 removeDeadInstruction(MI&: I);
900 return true;
901 }
902
903 Register Opcode = I.getOpcode();
904 // If it's not a GMIR instruction, we've selected it already.
905 if (!isPreISelGenericOpcode(Opcode)) {
906 if (Opcode == SPIRV::ASSIGN_TYPE) { // These pseudos aren't needed any more.
907 Register DstReg = I.getOperand(i: 0).getReg();
908 Register SrcReg = I.getOperand(i: 1).getReg();
909 auto *Def = MRI->getVRegDef(Reg: SrcReg);
910 if (isTypeFoldingSupported(Opcode: Def->getOpcode()) &&
911 Def->getOpcode() != TargetOpcode::G_CONSTANT &&
912 Def->getOpcode() != TargetOpcode::G_FCONSTANT) {
913 if (Def->getOpcode() == TargetOpcode::G_SELECT) {
914 Register SelectDstReg = Def->getOperand(i: 0).getReg();
915 bool SuccessToSelectSelect [[maybe_unused]] = selectSelect(
916 ResVReg: SelectDstReg, ResType: GR.getSPIRVTypeForVReg(VReg: SelectDstReg), I&: *Def);
917 assert(SuccessToSelectSelect);
918 GR.invalidateMachineInstr(MI: Def);
919 Def->eraseFromParent();
920 MRI->replaceRegWith(FromReg: DstReg, ToReg: SelectDstReg);
921 GR.invalidateMachineInstr(MI: &I);
922 I.eraseFromParent();
923 return true;
924 }
925
926 bool Res = selectImpl(I, CoverageInfo&: *CoverageInfo);
927 LLVM_DEBUG({
928 if (!Res && Def->getOpcode() != TargetOpcode::G_CONSTANT) {
929 dbgs() << "Unexpected pattern in ASSIGN_TYPE.\nInstruction: ";
930 I.print(dbgs());
931 }
932 });
933 assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT);
934 if (Res) {
935 if (!isTriviallyDead(MI: *Def, MRI: *MRI) && isDead(MI: *Def, MRI: *MRI))
936 DeadMIs.insert(Ptr: Def);
937 return Res;
938 }
939 }
940 MRI->setRegClass(Reg: SrcReg, RC: MRI->getRegClass(Reg: DstReg));
941 MRI->replaceRegWith(FromReg: SrcReg, ToReg: DstReg);
942 GR.invalidateMachineInstr(MI: &I);
943 I.eraseFromParent();
944 return true;
945 } else if (I.getNumDefs() == 1) {
946 // Make all vregs 64 bits (for SPIR-V IDs).
947 MRI->setType(VReg: I.getOperand(i: 0).getReg(), Ty: LLT::scalar(SizeInBits: 64));
948 }
949 constrainSelectedInstRegOperands(I, TII, TRI, RBI);
950 return true;
951 }
952
953 if (DeadMIs.contains(Ptr: &I)) {
954 // if the instruction has been already made dead by folding it away
955 // erase it
956 LLVM_DEBUG(dbgs() << "Instruction is folded and dead.\n");
957 removeDeadInstruction(MI&: I);
958 DeadMIs.erase(Ptr: &I);
959 return true;
960 }
961
962 if (I.getNumOperands() != I.getNumExplicitOperands()) {
963 LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
964 return false;
965 }
966
967 // Common code for getting return reg+type, and removing selected instr
968 // from parent occurs here. Instr-specific selection happens in spvSelect().
969 bool HasDefs = I.getNumDefs() > 0;
970 Register ResVReg = HasDefs ? I.getOperand(i: 0).getReg() : Register(0);
971 SPIRVTypeInst ResType = HasDefs ? GR.getSPIRVTypeForVReg(VReg: ResVReg) : nullptr;
972 assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
973 I.getOpcode() == TargetOpcode::G_IMPLICIT_DEF);
974 if (spvSelect(ResVReg, ResType, I)) {
975 if (HasDefs) // Make all vregs 64 bits (for SPIR-V IDs).
976 for (unsigned i = 0; i < I.getNumDefs(); ++i)
977 MRI->setType(VReg: I.getOperand(i).getReg(), Ty: LLT::scalar(SizeInBits: 64));
978 GR.invalidateMachineInstr(MI: &I);
979 I.eraseFromParent();
980 return true;
981 }
982 return false;
983}
984
985static bool mayApplyGenericSelection(unsigned Opcode) {
986 switch (Opcode) {
987 case TargetOpcode::G_CONSTANT:
988 case TargetOpcode::G_FCONSTANT:
989 return false;
990 }
991 return isTypeFoldingSupported(Opcode);
992}
993
994bool SPIRVInstructionSelector::BuildCOPY(Register DestReg, Register SrcReg,
995 MachineInstr &I) const {
996 const TargetRegisterClass *DstRC = MRI->getRegClassOrNull(Reg: DestReg);
997 const TargetRegisterClass *SrcRC = MRI->getRegClassOrNull(Reg: SrcReg);
998 if (DstRC != SrcRC && SrcRC)
999 MRI->setRegClass(Reg: DestReg, RC: SrcRC);
1000 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: TargetOpcode::COPY))
1001 .addDef(RegNo: DestReg)
1002 .addUse(RegNo: SrcReg)
1003 .constrainAllUses(TII, TRI, RBI);
1004 return true;
1005}
1006
1007bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
1008 SPIRVTypeInst ResType,
1009 MachineInstr &I) const {
1010 const unsigned Opcode = I.getOpcode();
1011 if (mayApplyGenericSelection(Opcode))
1012 return selectImpl(I, CoverageInfo&: *CoverageInfo);
1013 switch (Opcode) {
1014 case TargetOpcode::G_CONSTANT:
1015 case TargetOpcode::G_FCONSTANT:
1016 return selectConst(ResVReg, ResType, I);
1017 case TargetOpcode::G_GLOBAL_VALUE:
1018 return selectGlobalValue(ResVReg, I);
1019 case TargetOpcode::G_IMPLICIT_DEF:
1020 return selectOpUndef(ResVReg, ResType, I);
1021 case TargetOpcode::G_FREEZE:
1022 return selectFreeze(ResVReg, ResType, I);
1023
1024 case TargetOpcode::G_INTRINSIC:
1025 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
1026 case TargetOpcode::G_INTRINSIC_CONVERGENT:
1027 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
1028 return selectIntrinsic(ResVReg, ResType, I);
1029 case TargetOpcode::G_BITREVERSE:
1030 return selectBitreverse(ResVReg, ResType, I);
1031
1032 case TargetOpcode::G_BUILD_VECTOR:
1033 return selectBuildVector(ResVReg, ResType, I);
1034 case TargetOpcode::G_SPLAT_VECTOR:
1035 return selectSplatVector(ResVReg, ResType, I);
1036 case TargetOpcode::G_CONCAT_VECTORS:
1037 return selectConcatVectors(ResVReg, ResType, I);
1038
1039 case TargetOpcode::G_SHUFFLE_VECTOR: {
1040 MachineBasicBlock &BB = *I.getParent();
1041 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpVectorShuffle))
1042 .addDef(RegNo: ResVReg)
1043 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
1044 .addUse(RegNo: I.getOperand(i: 1).getReg())
1045 .addUse(RegNo: I.getOperand(i: 2).getReg());
1046 for (auto V : I.getOperand(i: 3).getShuffleMask())
1047 MIB.addImm(Val: V);
1048 MIB.constrainAllUses(TII, TRI, RBI);
1049 return true;
1050 }
1051 case TargetOpcode::G_MEMMOVE:
1052 case TargetOpcode::G_MEMCPY:
1053 case TargetOpcode::G_MEMCPY_INLINE:
1054 case TargetOpcode::G_MEMSET:
1055 case TargetOpcode::G_MEMSET_INLINE:
1056 return selectMemOperation(ResVReg, I);
1057
1058 case TargetOpcode::G_ICMP:
1059 return selectICmp(ResVReg, ResType, I);
1060 case TargetOpcode::G_FCMP:
1061 return selectFCmp(ResVReg, ResType, I);
1062
1063 case TargetOpcode::G_FRAME_INDEX:
1064 return selectFrameIndex(ResVReg, ResType, I);
1065
1066 case TargetOpcode::G_LOAD:
1067 return selectLoad(ResVReg, ResType, I);
1068 case TargetOpcode::G_STORE:
1069 return selectStore(I);
1070
1071 case TargetOpcode::G_BR:
1072 return selectBranch(I);
1073 case TargetOpcode::G_BRCOND:
1074 return selectBranchCond(I);
1075
1076 case TargetOpcode::G_PHI:
1077 return selectPhi(ResVReg, I);
1078
1079 case TargetOpcode::G_FPTOSI:
1080 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpConvertFToS);
1081 case TargetOpcode::G_FPTOUI:
1082 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpConvertFToU);
1083
1084 case TargetOpcode::G_FPTOSI_SAT:
1085 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpConvertFToS);
1086 case TargetOpcode::G_FPTOUI_SAT:
1087 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpConvertFToU);
1088
1089 case TargetOpcode::G_SITOFP:
1090 return selectIToF(ResVReg, ResType, I, IsSigned: true, Opcode: SPIRV::OpConvertSToF);
1091 case TargetOpcode::G_UITOFP:
1092 return selectIToF(ResVReg, ResType, I, IsSigned: false, Opcode: SPIRV::OpConvertUToF);
1093
1094 case TargetOpcode::G_CTPOP:
1095 return selectPopCount(ResVReg, ResType, I, Opcode: SPIRV::OpBitCount);
1096 case TargetOpcode::G_SMIN:
1097 return selectExtInst(ResVReg, ResType, I, CLInst: CL::s_min, GLInst: GL::SMin);
1098 case TargetOpcode::G_UMIN:
1099 return selectExtInst(ResVReg, ResType, I, CLInst: CL::u_min, GLInst: GL::UMin);
1100
1101 case TargetOpcode::G_SMAX:
1102 return selectExtInst(ResVReg, ResType, I, CLInst: CL::s_max, GLInst: GL::SMax);
1103 case TargetOpcode::G_UMAX:
1104 return selectExtInst(ResVReg, ResType, I, CLInst: CL::u_max, GLInst: GL::UMax);
1105
1106 case TargetOpcode::G_SCMP:
1107 return selectSUCmp(ResVReg, ResType, I, IsSigned: true);
1108 case TargetOpcode::G_UCMP:
1109 return selectSUCmp(ResVReg, ResType, I, IsSigned: false);
1110 case TargetOpcode::G_LROUND:
1111 case TargetOpcode::G_LLROUND: {
1112 Register regForLround =
1113 MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: ResVReg), Name: "lround");
1114 MRI->setRegClass(Reg: regForLround, RC: &SPIRV::iIDRegClass);
1115 GR.assignSPIRVTypeToVReg(Type: GR.getSPIRVTypeForVReg(VReg: I.getOperand(i: 1).getReg()),
1116 VReg: regForLround, MF: *(I.getParent()->getParent()));
1117 selectExtInst(ResVReg: regForLround, ResType: GR.getSPIRVTypeForVReg(VReg: regForLround), I,
1118 CLInst: CL::round, GLInst: GL::Round, /* setMIFlags */ false);
1119 MachineBasicBlock &BB = *I.getParent();
1120 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpConvertFToS))
1121 .addDef(RegNo: ResVReg)
1122 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
1123 .addUse(RegNo: regForLround);
1124 MIB.constrainAllUses(TII, TRI, RBI);
1125 return true;
1126 }
1127 case TargetOpcode::G_STRICT_FMA:
1128 case TargetOpcode::G_FMA: {
1129 if (STI.canUseExtension(E: SPIRV::Extension::SPV_KHR_fma)) {
1130 MachineBasicBlock &BB = *I.getParent();
1131 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpFmaKHR))
1132 .addDef(RegNo: ResVReg)
1133 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
1134 .addUse(RegNo: I.getOperand(i: 1).getReg())
1135 .addUse(RegNo: I.getOperand(i: 2).getReg())
1136 .addUse(RegNo: I.getOperand(i: 3).getReg())
1137 .setMIFlags(I.getFlags());
1138 MIB.constrainAllUses(TII, TRI, RBI);
1139 return true;
1140 }
1141 return selectExtInst(ResVReg, ResType, I, CLInst: CL::fma, GLInst: GL::Fma);
1142 }
1143
1144 case TargetOpcode::G_FLDEXP:
1145 case TargetOpcode::G_STRICT_FLDEXP:
1146 return selectLdexp(ResVReg, ResType, I);
1147
1148 case TargetOpcode::G_FPOW:
1149 return selectExtInst(ResVReg, ResType, I, CLInst: CL::pow, GLInst: GL::Pow);
1150 case TargetOpcode::G_FPOWI:
1151 return selectFpowi(ResVReg, ResType, I);
1152
1153 case TargetOpcode::G_FEXP:
1154 return selectExtInst(ResVReg, ResType, I, CLInst: CL::exp, GLInst: GL::Exp);
1155 case TargetOpcode::G_FEXP2:
1156 return selectExtInst(ResVReg, ResType, I, CLInst: CL::exp2, GLInst: GL::Exp2);
1157 case TargetOpcode::G_FEXP10:
1158 return selectExp10(ResVReg, ResType, I);
1159
1160 case TargetOpcode::G_FMODF:
1161 return selectModf(ResVReg, ResType, I);
1162 case TargetOpcode::G_FSINCOS:
1163 return selectSincos(ResVReg, ResType, I);
1164
1165 case TargetOpcode::G_FLOG:
1166 return selectExtInst(ResVReg, ResType, I, CLInst: CL::log, GLInst: GL::Log);
1167 case TargetOpcode::G_FLOG2:
1168 return selectExtInst(ResVReg, ResType, I, CLInst: CL::log2, GLInst: GL::Log2);
1169 case TargetOpcode::G_FLOG10:
1170 return selectLog10(ResVReg, ResType, I);
1171
1172 case TargetOpcode::G_FABS:
1173 return selectExtInst(ResVReg, ResType, I, CLInst: CL::fabs, GLInst: GL::FAbs);
1174 case TargetOpcode::G_ABS:
1175 return selectExtInst(ResVReg, ResType, I, CLInst: CL::s_abs, GLInst: GL::SAbs);
1176
1177 case TargetOpcode::G_FMINNUM:
1178 return selectExtInst(ResVReg, ResType, I, CLInst: CL::fmin, GLInst: GL::NMin);
1179 case TargetOpcode::G_FMAXNUM:
1180 return selectExtInst(ResVReg, ResType, I, CLInst: CL::fmax, GLInst: GL::NMax);
1181
1182 case TargetOpcode::G_FCOPYSIGN:
1183 return selectCopySign(ResVReg, ResType, I);
1184
1185 case TargetOpcode::G_FCEIL:
1186 return selectExtInst(ResVReg, ResType, I, CLInst: CL::ceil, GLInst: GL::Ceil);
1187 case TargetOpcode::G_FFLOOR:
1188 return selectExtInst(ResVReg, ResType, I, CLInst: CL::floor, GLInst: GL::Floor);
1189
1190 case TargetOpcode::G_FCOS:
1191 return selectExtInst(ResVReg, ResType, I, CLInst: CL::cos, GLInst: GL::Cos);
1192 case TargetOpcode::G_FSIN:
1193 return selectExtInst(ResVReg, ResType, I, CLInst: CL::sin, GLInst: GL::Sin);
1194 case TargetOpcode::G_FTAN:
1195 return selectExtInst(ResVReg, ResType, I, CLInst: CL::tan, GLInst: GL::Tan);
1196 case TargetOpcode::G_FACOS:
1197 return selectExtInst(ResVReg, ResType, I, CLInst: CL::acos, GLInst: GL::Acos);
1198 case TargetOpcode::G_FASIN:
1199 return selectExtInst(ResVReg, ResType, I, CLInst: CL::asin, GLInst: GL::Asin);
1200 case TargetOpcode::G_FATAN:
1201 return selectExtInst(ResVReg, ResType, I, CLInst: CL::atan, GLInst: GL::Atan);
1202 case TargetOpcode::G_FATAN2:
1203 return selectExtInst(ResVReg, ResType, I, CLInst: CL::atan2, GLInst: GL::Atan2);
1204 case TargetOpcode::G_FCOSH:
1205 return selectExtInst(ResVReg, ResType, I, CLInst: CL::cosh, GLInst: GL::Cosh);
1206 case TargetOpcode::G_FSINH:
1207 return selectExtInst(ResVReg, ResType, I, CLInst: CL::sinh, GLInst: GL::Sinh);
1208 case TargetOpcode::G_FTANH:
1209 return selectExtInst(ResVReg, ResType, I, CLInst: CL::tanh, GLInst: GL::Tanh);
1210
1211 case TargetOpcode::G_STRICT_FSQRT:
1212 case TargetOpcode::G_FSQRT:
1213 return selectExtInst(ResVReg, ResType, I, CLInst: CL::sqrt, GLInst: GL::Sqrt);
1214
1215 case TargetOpcode::G_CTTZ:
1216 case TargetOpcode::G_CTTZ_ZERO_POISON:
1217 return selectExtInst(ResVReg, ResType, I, CLInst: CL::ctz);
1218 case TargetOpcode::G_CTLZ:
1219 case TargetOpcode::G_CTLZ_ZERO_POISON:
1220 return selectExtInst(ResVReg, ResType, I, CLInst: CL::clz);
1221
1222 case TargetOpcode::G_INTRINSIC_ROUND:
1223 return selectExtInst(ResVReg, ResType, I, CLInst: CL::round, GLInst: GL::Round);
1224 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1225 return selectExtInst(ResVReg, ResType, I, CLInst: CL::rint, GLInst: GL::RoundEven);
1226 case TargetOpcode::G_INTRINSIC_TRUNC:
1227 return selectExtInst(ResVReg, ResType, I, CLInst: CL::trunc, GLInst: GL::Trunc);
1228 case TargetOpcode::G_FRINT:
1229 case TargetOpcode::G_FNEARBYINT:
1230 return selectExtInst(ResVReg, ResType, I, CLInst: CL::rint, GLInst: GL::RoundEven);
1231
1232 case TargetOpcode::G_SMULH:
1233 return selectExtInst(ResVReg, ResType, I, CLInst: CL::s_mul_hi);
1234 case TargetOpcode::G_UMULH:
1235 return selectExtInst(ResVReg, ResType, I, CLInst: CL::u_mul_hi);
1236
1237 case TargetOpcode::G_SADDSAT:
1238 return selectExtInst(ResVReg, ResType, I, CLInst: CL::s_add_sat);
1239 case TargetOpcode::G_UADDSAT:
1240 return selectExtInst(ResVReg, ResType, I, CLInst: CL::u_add_sat);
1241 case TargetOpcode::G_SSUBSAT:
1242 return selectExtInst(ResVReg, ResType, I, CLInst: CL::s_sub_sat);
1243 case TargetOpcode::G_USUBSAT:
1244 return selectExtInst(ResVReg, ResType, I, CLInst: CL::u_sub_sat);
1245
1246 case TargetOpcode::G_FFREXP:
1247 return selectFrexp(ResVReg, ResType, I);
1248
1249 case TargetOpcode::G_UADDO:
1250 return selectOverflowArith(ResVReg, ResType, I,
1251 Opcode: isVectorType(SPVTy: ResType) ? SPIRV::OpIAddCarryV
1252 : SPIRV::OpIAddCarryS);
1253 case TargetOpcode::G_USUBO:
1254 return selectOverflowArith(ResVReg, ResType, I,
1255 Opcode: isVectorType(SPVTy: ResType) ? SPIRV::OpISubBorrowV
1256 : SPIRV::OpISubBorrowS);
1257 case TargetOpcode::G_UMULO:
1258 return selectOverflowArith(ResVReg, ResType, I, Opcode: SPIRV::OpUMulExtended);
1259 case TargetOpcode::G_SMULO:
1260 return selectOverflowArith(ResVReg, ResType, I, Opcode: SPIRV::OpSMulExtended);
1261
1262 case TargetOpcode::G_SEXT:
1263 return selectExt(ResVReg, ResType, I, IsSigned: true);
1264 case TargetOpcode::G_ANYEXT:
1265 case TargetOpcode::G_ZEXT:
1266 return selectExt(ResVReg, ResType, I, IsSigned: false);
1267 case TargetOpcode::G_TRUNC:
1268 return selectTrunc(ResVReg, ResType, I);
1269 case TargetOpcode::G_FPTRUNC:
1270 case TargetOpcode::G_FPEXT:
1271 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpFConvert);
1272
1273 case TargetOpcode::G_PTRTOINT:
1274 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpConvertPtrToU);
1275 case TargetOpcode::G_INTTOPTR:
1276 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpConvertUToPtr);
1277 case TargetOpcode::G_BITCAST:
1278 return selectBitcast(ResVReg, ResType, I);
1279 case TargetOpcode::G_ADDRSPACE_CAST:
1280 return selectAddrSpaceCast(ResVReg, ResType, I);
1281 case TargetOpcode::G_PTRMASK:
1282 return selectPtrMask(ResVReg, ResType, I);
1283 case TargetOpcode::G_PTR_ADD: {
1284 // Currently, we get G_PTR_ADD only applied to global variables.
1285 assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
1286 Register GV = I.getOperand(i: 1).getReg();
1287 MachineRegisterInfo::def_instr_iterator II = MRI->def_instr_begin(RegNo: GV);
1288 (void)II;
1289 assert(((*II).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
1290 (*II).getOpcode() == TargetOpcode::COPY ||
1291 (*II).getOpcode() == SPIRV::OpVariable ||
1292 (*II).getOpcode() == SPIRV::OpUntypedVariableKHR) &&
1293 getImm(I.getOperand(2), MRI));
1294 // It may be the initialization of a global variable.
1295 bool IsGVInit = false;
1296 for (MachineRegisterInfo::use_instr_iterator
1297 UseIt = MRI->use_instr_begin(RegNo: I.getOperand(i: 0).getReg()),
1298 UseEnd = MRI->use_instr_end();
1299 UseIt != UseEnd; UseIt = std::next(x: UseIt)) {
1300 if ((*UseIt).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
1301 (*UseIt).getOpcode() == SPIRV::OpSpecConstantOp ||
1302 (*UseIt).getOpcode() == SPIRV::OpVariable ||
1303 (*UseIt).getOpcode() == SPIRV::OpUntypedVariableKHR) {
1304 IsGVInit = true;
1305 break;
1306 }
1307 }
1308 MachineBasicBlock &BB = *I.getParent();
1309 // An untyped result needs OpUntypedInBoundsPtrAccessChainKHR, which spells
1310 // out the Base Type. The offset of G_PTR_ADD is a byte count, so the Base
1311 // Type is i8 and the offset is the Element index as is. The opcode is
1312 // picked by the result type alone because an untyped access chain accepts
1313 // a typed base while a typed access chain rejects an untyped result.
1314 SPIRVTypeInst GVType = GR.getSPIRVTypeForVReg(VReg: GV);
1315 const bool UseUntypedPointers =
1316 ResType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
1317 if (UseUntypedPointers) {
1318 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpSpecConstantOp))
1319 .addDef(RegNo: ResVReg)
1320 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
1321 .addImm(Val: static_cast<uint32_t>(
1322 SPIRV::Opcode::UntypedInBoundsPtrAccessChainKHR))
1323 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: GR.getOrCreateSPIRVIntegerType(BitWidth: 8, I, TII)))
1324 .addUse(RegNo: GV)
1325 .addUse(RegNo: I.getOperand(i: 2).getReg())
1326 .constrainAllUses(TII, TRI, RBI);
1327 return true;
1328 }
1329 if (!IsGVInit) {
1330 SPIRVTypeInst GVPointeeType = GR.getPointeeType(PtrType: GVType);
1331 SPIRVTypeInst ResPointeeType = GR.getPointeeType(PtrType: ResType);
1332 if (GVPointeeType && ResPointeeType && GVPointeeType != ResPointeeType) {
1333 // Build a new virtual register that is associated with the required
1334 // data type.
1335 Register NewVReg = MRI->createGenericVirtualRegister(Ty: MRI->getType(Reg: GV));
1336 MRI->setRegClass(Reg: NewVReg, RC: MRI->getRegClass(Reg: GV));
1337 // Having a correctly typed base we are ready to build the actually
1338 // required GEP. It may not be a constant though, because all Operands
1339 // of OpSpecConstantOp is to originate from other const instructions,
1340 // and only the AccessChain named opcodes accept a global OpVariable
1341 // instruction. We can't use an AccessChain opcode because of the type
1342 // mismatch between result and base types.
1343 if (!GR.isBitcastCompatible(Type1: ResType, Type2: GVType))
1344 return diagnoseUnsupported(
1345 I, Msg: "incompatible result and operand types in a bitcast");
1346 Register ResTypeReg = GR.getSPIRVTypeID(SpirvType: ResType);
1347 MachineInstrBuilder MIB =
1348 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpBitcast))
1349 .addDef(RegNo: NewVReg)
1350 .addUse(RegNo: ResTypeReg)
1351 .addUse(RegNo: GV);
1352 MIB.constrainAllUses(TII, TRI, RBI);
1353 BuildMI(BB, I, MIMD: I.getDebugLoc(),
1354 MCID: TII.get(Opcode: STI.isLogicalSPIRV() ? SPIRV::OpInBoundsAccessChain
1355 : SPIRV::OpInBoundsPtrAccessChain))
1356 .addDef(RegNo: ResVReg)
1357 .addUse(RegNo: ResTypeReg)
1358 .addUse(RegNo: NewVReg)
1359 .addUse(RegNo: I.getOperand(i: 2).getReg())
1360 .constrainAllUses(TII, TRI, RBI);
1361 } else {
1362 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpSpecConstantOp))
1363 .addDef(RegNo: ResVReg)
1364 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
1365 .addImm(
1366 Val: static_cast<uint32_t>(SPIRV::Opcode::InBoundsPtrAccessChain))
1367 .addUse(RegNo: GV)
1368 .addUse(RegNo: I.getOperand(i: 2).getReg())
1369 .constrainAllUses(TII, TRI, RBI);
1370 }
1371 return true;
1372 }
1373 // It's possible to translate G_PTR_ADD to OpSpecConstantOp: either to
1374 // initialize a global variable with a constant expression (e.g., the test
1375 // case opencl/basic/progvar_prog_scope_init.ll), or for another use case
1376 Register Idx = buildZerosVal(ResType: GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII), I);
1377 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpSpecConstantOp))
1378 .addDef(RegNo: ResVReg)
1379 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
1380 .addImm(Val: static_cast<uint32_t>(
1381 SPIRV::Opcode::InBoundsPtrAccessChain))
1382 .addUse(RegNo: GV)
1383 .addUse(RegNo: Idx)
1384 .addUse(RegNo: I.getOperand(i: 2).getReg());
1385 MIB.constrainAllUses(TII, TRI, RBI);
1386 return true;
1387 }
1388
1389 case TargetOpcode::G_ATOMICRMW_OR:
1390 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicOr);
1391 case TargetOpcode::G_ATOMICRMW_ADD:
1392 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicIAdd);
1393 case TargetOpcode::G_ATOMICRMW_AND:
1394 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicAnd);
1395 case TargetOpcode::G_ATOMICRMW_MAX:
1396 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicSMax);
1397 case TargetOpcode::G_ATOMICRMW_MIN:
1398 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicSMin);
1399 case TargetOpcode::G_ATOMICRMW_SUB:
1400 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicISub);
1401 case TargetOpcode::G_ATOMICRMW_XOR:
1402 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicXor);
1403 case TargetOpcode::G_ATOMICRMW_UMAX:
1404 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicUMax);
1405 case TargetOpcode::G_ATOMICRMW_UMIN:
1406 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicUMin);
1407 case TargetOpcode::G_ATOMICRMW_XCHG:
1408 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicExchange);
1409
1410 case TargetOpcode::G_ATOMICRMW_FADD:
1411 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicFAddEXT);
1412 case TargetOpcode::G_ATOMICRMW_FSUB:
1413 // Translate G_ATOMICRMW_FSUB to OpAtomicFAddEXT with negative value operand
1414 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicFAddEXT,
1415 NegateOpcode: isVectorType(SPVTy: ResType) ? SPIRV::OpFNegateV
1416 : SPIRV::OpFNegate);
1417 case TargetOpcode::G_ATOMICRMW_FMIN:
1418 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicFMinEXT);
1419 case TargetOpcode::G_ATOMICRMW_FMAX:
1420 return selectAtomicRMW(ResVReg, ResType, I, NewOpcode: SPIRV::OpAtomicFMaxEXT);
1421
1422 case TargetOpcode::G_FENCE:
1423 return selectFence(I);
1424
1425 case TargetOpcode::G_STACKSAVE:
1426 return selectStackSave(ResVReg, ResType, I);
1427 case TargetOpcode::G_STACKRESTORE:
1428 return selectStackRestore(I);
1429
1430 case TargetOpcode::G_UNMERGE_VALUES:
1431 return selectUnmergeValues(I);
1432
1433 case TargetOpcode::G_TRAP:
1434 case TargetOpcode::G_UBSANTRAP:
1435 return selectTrap(I);
1436
1437 // Discard gen opcodes for intrinsics which we do not expect to actually
1438 // represent code after lowering or intrinsics which are not implemented but
1439 // should not crash when found in a customer's LLVM IR input.
1440 case TargetOpcode::DBG_LABEL:
1441 return true;
1442 case TargetOpcode::G_DEBUGTRAP:
1443 return selectDebugTrap(ResVReg, ResType, I);
1444 case TargetOpcode::G_PREFETCH:
1445 return selectPrefetch(I);
1446
1447 default:
1448 return false;
1449 }
1450}
1451
1452bool SPIRVInstructionSelector::selectDebugTrap(Register ResVReg,
1453 SPIRVTypeInst ResType,
1454 MachineInstr &I) const {
1455 unsigned Opcode = SPIRV::OpNop;
1456 MachineBasicBlock &BB = *I.getParent();
1457 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
1458 .constrainAllUses(TII, TRI, RBI);
1459 return true;
1460}
1461
1462bool SPIRVInstructionSelector::selectPrefetch(MachineInstr &I) const {
1463 // llvm.prefetch is missing info about how many bytes to prefetch that
1464 // OpUntypedPrefetchKHR instruction requires, so just drop the instruction
1465 // in case untyped pointers are enabled since OCL prefetch cannot take
1466 // untyped pointers.
1467 if (STI.canUseExtension(E: SPIRV::Extension::SPV_KHR_untyped_pointers))
1468 return true;
1469
1470 if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::OpenCL_std)) {
1471 MachineIRBuilder MIRBuilder(I);
1472 const unsigned PointerSize = GR.getPointerSize();
1473 const SPIRVTypeInst PointerSizeType =
1474 GR.getOrCreateSPIRVIntegerType(BitWidth: PointerSize, MIRBuilder);
1475 bool ZeroAsNull = !STI.isShader();
1476
1477 // Assume that a single element needs prefetch.
1478 Register ConstIntOne =
1479 GR.getOrCreateConstInt(Val: 1, I, SpvType: PointerSizeType, TII, ZeroAsNull);
1480
1481 Register AddrVal = I.getOperand(i: 0).getReg();
1482 Register ExtReg = MRI->createVirtualRegister(
1483 RegClass: GR.getRegClass(SpvType: GR.getOpTypeVoid(MIRBuilder)));
1484 return selectExtInst(ResVReg: ExtReg, ResType: GR.getOpTypeVoid(MIRBuilder), I, CLInst: CL::prefetch,
1485 /*setMIFlags=*/false, /*useMSSrc=*/useMISrc: false,
1486 SrcRegs: {AddrVal, ConstIntOne});
1487 }
1488 return true;
1489}
1490
1491bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
1492 SPIRVTypeInst ResType,
1493 MachineInstr &I,
1494 GL::GLSLExtInst GLInst,
1495 bool setMIFlags, bool useMISrc,
1496 ArrayRef<Register> SrcRegs) const {
1497 if (!STI.canUseExtInstSet(
1498 E: SPIRV::InstructionSet::InstructionSet::GLSL_std_450))
1499 return diagnoseUnsupported(
1500 I,
1501 Msg: "this instruction is only supported with the GLSL extended instruction "
1502 "set.");
1503 return selectExtInst(ResVReg, ResType, I,
1504 ExtInsts: {{SPIRV::InstructionSet::GLSL_std_450, GLInst}},
1505 setMIFlags, useMISrc, SrcRegs);
1506}
1507
1508bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
1509 SPIRVTypeInst ResType,
1510 MachineInstr &I,
1511 CL::OpenCLExtInst CLInst,
1512 bool setMIFlags, bool useMISrc,
1513 ArrayRef<Register> SrcRegs) const {
1514 return selectExtInst(ResVReg, ResType, I,
1515 ExtInsts: {{SPIRV::InstructionSet::OpenCL_std, CLInst}},
1516 setMIFlags, useMISrc, SrcRegs);
1517}
1518
1519bool SPIRVInstructionSelector::selectExtInst(
1520 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
1521 CL::OpenCLExtInst CLInst, GL::GLSLExtInst GLInst, bool setMIFlags,
1522 bool useMISrc, ArrayRef<Register> SrcRegs) const {
1523 ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst},
1524 {SPIRV::InstructionSet::GLSL_std_450, GLInst}};
1525 return selectExtInst(ResVReg, ResType, I, ExtInsts, setMIFlags, useMISrc,
1526 SrcRegs);
1527}
1528
1529bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
1530 SPIRVTypeInst ResType,
1531 MachineInstr &I,
1532 const ExtInstList &Insts,
1533 bool setMIFlags, bool useMISrc,
1534 ArrayRef<Register> SrcRegs) const {
1535
1536 for (const auto &[InstructionSet, Opcode] : Insts) {
1537 if (!STI.canUseExtInstSet(E: InstructionSet))
1538 continue;
1539 MachineBasicBlock &BB = *I.getParent();
1540 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpExtInst))
1541 .addDef(RegNo: ResVReg)
1542 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
1543 .addImm(Val: static_cast<uint32_t>(InstructionSet))
1544 .addImm(Val: Opcode);
1545 if (setMIFlags)
1546 MIB.setMIFlags(I.getFlags());
1547 if (useMISrc) {
1548 const unsigned NumOps = I.getNumOperands();
1549 unsigned Index = 1;
1550 if (Index < NumOps &&
1551 I.getOperand(i: Index).getType() ==
1552 MachineOperand::MachineOperandType::MO_IntrinsicID)
1553 Index = 2;
1554 for (; Index < NumOps; ++Index)
1555 MIB.add(MO: I.getOperand(i: Index));
1556 } else {
1557 for (Register SReg : SrcRegs) {
1558 MIB.addUse(RegNo: SReg);
1559 }
1560 }
1561 MIB.constrainAllUses(TII, TRI, RBI);
1562 return true;
1563 }
1564 return false;
1565}
1566
1567bool SPIRVInstructionSelector::selectCopySign(Register ResVReg,
1568 SPIRVTypeInst ResType,
1569 MachineInstr &I) const {
1570 if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::OpenCL_std))
1571 return selectExtInst(ResVReg, ResType, I, CLInst: CL::copysign);
1572
1573 // There is no copysign instruction in the GLSL Extended Instruction set, so
1574 // it is implemented with bit manipulation:
1575 // bitcast((bitcast(magnitude) & ~signBit) | (bitcast(sign) & signBit))
1576 Register MagnitudeReg = I.getOperand(i: 1).getReg();
1577 Register SignReg = I.getOperand(i: 2).getReg();
1578
1579 const unsigned BitWidth = GR.getScalarOrVectorBitWidth(Type: ResType);
1580 const unsigned ComponentCount = GR.getScalarOrVectorComponentCount(Type: ResType);
1581 SPIRVTypeInst IntType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII);
1582 const APInt SignMaskVal = APInt::getSignMask(BitWidth);
1583
1584 Register SignMask, NotSignMask;
1585 unsigned AndOpcode, OrOpcode;
1586 if (ComponentCount > 1) {
1587 IntType = GR.getOrCreateSPIRVVectorType(BaseType: IntType, NumElements: ComponentCount, I, TII);
1588 SignMask = GR.getOrCreateConstVector(Val: SignMaskVal, I, SpvType: IntType, TII);
1589 NotSignMask = GR.getOrCreateConstVector(Val: ~SignMaskVal, I, SpvType: IntType, TII);
1590 AndOpcode = SPIRV::OpBitwiseAndV;
1591 OrOpcode = SPIRV::OpBitwiseOrV;
1592 } else {
1593 SignMask = GR.getOrCreateConstInt(Val: SignMaskVal, I, SpvType: IntType, TII);
1594 NotSignMask = GR.getOrCreateConstInt(Val: ~SignMaskVal, I, SpvType: IntType, TII);
1595 AndOpcode = SPIRV::OpBitwiseAndS;
1596 OrOpcode = SPIRV::OpBitwiseOrS;
1597 }
1598
1599 auto EmitBitOp = [&](Register &ResReg, ArrayRef<Register> SrcRegs,
1600 unsigned Opcode) {
1601 ResReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: IntType));
1602 return selectOpWithSrcs(ResVReg: ResReg, ResType: IntType, I, SrcRegs, Opcode);
1603 };
1604
1605 Register MagnitudeInt, SignInt, MagnitudeBits, SignBits, CombinedInt;
1606 if (!EmitBitOp(MagnitudeInt, {MagnitudeReg}, SPIRV::OpBitcast) ||
1607 !EmitBitOp(SignInt, {SignReg}, SPIRV::OpBitcast) ||
1608 !EmitBitOp(MagnitudeBits, {MagnitudeInt, NotSignMask}, AndOpcode) ||
1609 !EmitBitOp(SignBits, {SignInt, SignMask}, AndOpcode) ||
1610 !EmitBitOp(CombinedInt, {MagnitudeBits, SignBits}, OrOpcode))
1611 return false;
1612
1613 return selectOpWithSrcs(ResVReg, ResType, I, SrcRegs: {CombinedInt}, Opcode: SPIRV::OpBitcast);
1614}
1615
1616bool SPIRVInstructionSelector::selectFrexp(Register ResVReg,
1617 SPIRVTypeInst ResType,
1618 MachineInstr &I) const {
1619 ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CL::frexp},
1620 {SPIRV::InstructionSet::GLSL_std_450, GL::Frexp}};
1621 for (const auto &Ex : ExtInsts) {
1622 SPIRV::InstructionSet::InstructionSet Set = Ex.first;
1623 uint32_t Opcode = Ex.second;
1624 if (!STI.canUseExtInstSet(E: Set))
1625 continue;
1626
1627 MachineIRBuilder MIRBuilder(I);
1628 SPIRVTypeInst PointeeTy = GR.getSPIRVTypeForVReg(VReg: I.getOperand(i: 1).getReg());
1629 const SPIRVTypeInst PointerType = GR.getOrCreateSPIRVPointerType(
1630 BaseType: PointeeTy, MIRBuilder, SC: SPIRV::StorageClass::Function);
1631 Register PointerVReg =
1632 createVirtualRegister(SpvType: PointerType, GR: &GR, MRI, MF: MRI->getMF());
1633
1634 auto It = getOpVariableMBBIt(MF&: *I.getMF());
1635 // An untyped pointer result type is only legal on OpUntypedVariableKHR,
1636 // but not on OpVariable.
1637 const bool IsUntyped =
1638 PointerType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
1639 auto VarMIB =
1640 BuildMI(BB&: *It->getParent(), I: It, MIMD: It->getDebugLoc(),
1641 MCID: TII.get(Opcode: IsUntyped ? SPIRV::OpUntypedVariableKHR
1642 : SPIRV::OpVariable))
1643 .addDef(RegNo: PointerVReg)
1644 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: PointerType))
1645 .addImm(Val: static_cast<uint32_t>(SPIRV::StorageClass::Function));
1646 if (IsUntyped)
1647 VarMIB.addUse(RegNo: GR.getSPIRVTypeID(SpirvType: PointeeTy)); // Data Type
1648 VarMIB.constrainAllUses(TII, TRI, RBI);
1649
1650 SPIRVTypeInst MantissaTy = GR.getSPIRVTypeForVReg(VReg: I.getOperand(i: 2).getReg());
1651 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpExtInst))
1652 .addDef(RegNo: ResVReg)
1653 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: MantissaTy))
1654 .addImm(Val: static_cast<uint32_t>(Ex.first))
1655 .addImm(Val: Opcode)
1656 .add(MO: I.getOperand(i: 2))
1657 .addUse(RegNo: PointerVReg)
1658 .constrainAllUses(TII, TRI, RBI);
1659
1660 Register ExpResReg = I.getOperand(i: 1).getReg();
1661 if (!MRI->use_nodbg_empty(RegNo: ExpResReg))
1662 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpLoad))
1663 .addDef(RegNo: ExpResReg)
1664 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: PointeeTy))
1665 .addUse(RegNo: PointerVReg)
1666 .constrainAllUses(TII, TRI, RBI);
1667 return true;
1668 }
1669 return false;
1670}
1671
1672bool SPIRVInstructionSelector::selectLdexp(Register ResVReg,
1673 SPIRVTypeInst ResType,
1674 MachineInstr &I) const {
1675 Register XReg = I.getOperand(i: 1).getReg();
1676 Register ExpReg = I.getOperand(i: 2).getReg();
1677
1678 // Both OpenCL.std ldexp and GLSL.std.450 Ldexp require the exponent to have
1679 // the same number of components as the result, but G_FLDEXP's exponent is
1680 // scalar even for vector operands. Splat it when the result is a vector.
1681 SPIRVTypeInst ExpType = GR.getSPIRVTypeForVReg(VReg: ExpReg);
1682 if (ResType->getOpcode() == SPIRV::OpTypeVector &&
1683 ExpType->getOpcode() != SPIRV::OpTypeVector) {
1684 unsigned NumElts = ResType->getOperand(i: 2).getImm();
1685 ExpReg = buildVectorSplat(ScalarReg: ExpReg, NumElts, I);
1686 }
1687
1688 return selectExtInst(ResVReg, ResType, I, CLInst: CL::ldexp, GLInst: GL::Ldexp,
1689 /*setMIFlags=*/true, /*useMISrc=*/false, SrcRegs: {XReg, ExpReg});
1690}
1691
1692bool SPIRVInstructionSelector::selectSincos(Register ResVReg,
1693 SPIRVTypeInst ResType,
1694 MachineInstr &I) const {
1695 Register CosResVReg = I.getOperand(i: 1).getReg();
1696 unsigned SrcIdx = I.getNumExplicitDefs();
1697 Register ResTypeReg = GR.getSPIRVTypeID(SpirvType: ResType);
1698
1699 if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::OpenCL_std)) {
1700 // OpenCL.std sincos(x, cosval*) -> returns sin(x), writes cos(x) to ptr.
1701 MachineIRBuilder MIRBuilder(I);
1702 const SPIRVTypeInst PointerType = GR.getOrCreateSPIRVPointerType(
1703 BaseType: ResType, MIRBuilder, SC: SPIRV::StorageClass::Function);
1704 Register PointerVReg =
1705 createVirtualRegister(SpvType: PointerType, GR: &GR, MRI, MF: MRI->getMF());
1706
1707 auto It = getOpVariableMBBIt(MF&: *I.getMF());
1708 // An untyped pointer result type is only legal on OpUntypedVariableKHR,
1709 // but not on OpVariable.
1710 const bool IsUntyped =
1711 PointerType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
1712 auto VarMIB =
1713 BuildMI(BB&: *It->getParent(), I: It, MIMD: It->getDebugLoc(),
1714 MCID: TII.get(Opcode: IsUntyped ? SPIRV::OpUntypedVariableKHR
1715 : SPIRV::OpVariable))
1716 .addDef(RegNo: PointerVReg)
1717 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: PointerType))
1718 .addImm(Val: static_cast<uint32_t>(SPIRV::StorageClass::Function));
1719 if (IsUntyped)
1720 VarMIB.addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType)); // Data Type
1721 VarMIB.constrainAllUses(TII, TRI, RBI);
1722 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpExtInst))
1723 .addDef(RegNo: ResVReg)
1724 .addUse(RegNo: ResTypeReg)
1725 .addImm(Val: static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
1726 .addImm(Val: CL::sincos)
1727 .add(MO: I.getOperand(i: SrcIdx))
1728 .addUse(RegNo: PointerVReg)
1729 .constrainAllUses(TII, TRI, RBI);
1730 if (!MRI->use_nodbg_empty(RegNo: CosResVReg))
1731 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpLoad))
1732 .addDef(RegNo: CosResVReg)
1733 .addUse(RegNo: ResTypeReg)
1734 .addUse(RegNo: PointerVReg)
1735 .constrainAllUses(TII, TRI, RBI);
1736 return true;
1737 } else if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::GLSL_std_450)) {
1738 // GLSL.std.450 has no combined sincos; emit separate Sin and Cos.
1739 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpExtInst))
1740 .addDef(RegNo: ResVReg)
1741 .addUse(RegNo: ResTypeReg)
1742 .addImm(Val: static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1743 .addImm(Val: GL::Sin)
1744 .add(MO: I.getOperand(i: SrcIdx))
1745 .constrainAllUses(TII, TRI, RBI);
1746 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpExtInst))
1747 .addDef(RegNo: CosResVReg)
1748 .addUse(RegNo: ResTypeReg)
1749 .addImm(Val: static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1750 .addImm(Val: GL::Cos)
1751 .add(MO: I.getOperand(i: SrcIdx))
1752 .constrainAllUses(TII, TRI, RBI);
1753 return true;
1754 }
1755 return false;
1756}
1757
1758bool SPIRVInstructionSelector::selectOpWithSrcs(Register ResVReg,
1759 SPIRVTypeInst ResType,
1760 MachineInstr &I,
1761 ArrayRef<Register> Srcs,
1762 unsigned Opcode) const {
1763 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
1764 .addDef(RegNo: ResVReg)
1765 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
1766 for (Register SReg : Srcs) {
1767 MIB.addUse(RegNo: SReg);
1768 }
1769 MIB.constrainAllUses(TII, TRI, RBI);
1770 return true;
1771}
1772
1773bool SPIRVInstructionSelector::selectPopCount16(Register ResVReg,
1774 SPIRVTypeInst ResType,
1775 MachineInstr &I,
1776 unsigned ExtOpcode,
1777 unsigned Opcode) const {
1778 MachineIRBuilder MIRBuilder(I);
1779
1780 Register OpReg = I.getOperand(i: 1).getReg();
1781 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(VReg: OpReg);
1782 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(Type: SrcType);
1783 bool IsScalar = !isVectorType(SPVTy: SrcType);
1784 SPIRVTypeInst I32Type = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, MIRBuilder);
1785
1786 SPIRVTypeInst ExtType =
1787 IsScalar ? I32Type
1788 : GR.getOrCreateSPIRVVectorType(BaseType: I32Type, NumElements: ComponentCount,
1789 MIRBuilder, /*IsSigned=*/EmitIR: false);
1790
1791 Register ExtReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ExtType));
1792 // Always use OpUConvert to always use a 0 extend
1793 if (!selectOpWithSrcs(ResVReg: ExtReg, ResType: ExtType, I, Srcs: {OpReg}, Opcode: SPIRV::OpUConvert))
1794 return false;
1795
1796 Register PopCountReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ExtType));
1797 if (!selectPopCount32(ResVReg: PopCountReg, ResType: ExtType, I, SrcReg: ExtReg, Opcode))
1798 return false;
1799
1800 return selectOpWithSrcs(ResVReg, ResType, I, Srcs: {PopCountReg}, Opcode: ExtOpcode);
1801}
1802
1803bool SPIRVInstructionSelector::selectPopCount32(Register ResVReg,
1804 SPIRVTypeInst ResType,
1805 MachineInstr &I,
1806 Register SrcReg,
1807 unsigned Opcode) const {
1808 return selectOpWithSrcs(ResVReg, ResType, I, Srcs: {SrcReg}, Opcode);
1809}
1810
1811bool SPIRVInstructionSelector::selectPopCount64(Register ResVReg,
1812 SPIRVTypeInst ResType,
1813 MachineInstr &I,
1814 Register SrcReg,
1815 unsigned Opcode) const {
1816 MachineIRBuilder MIRBuilder(I);
1817
1818 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(VReg: SrcReg);
1819 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(Type: SrcType);
1820 bool IsScalar = !isVectorType(SPVTy: SrcType);
1821 SPIRVTypeInst I32Type = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, MIRBuilder);
1822
1823 // We need to work with a type matching the shape of the input but using 32
1824 // bit int instead of 64.
1825 SPIRVTypeInst WorkingType =
1826 IsScalar ? I32Type
1827 : GR.getOrCreateSPIRVVectorType(BaseType: I32Type, NumElements: ComponentCount,
1828 MIRBuilder, /*IsSigned=*/EmitIR: false);
1829
1830 // Truncate and count the low bits.
1831 Register Trunc = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: WorkingType));
1832 if (!selectOpWithSrcs(ResVReg: Trunc, ResType: WorkingType, I, Srcs: {SrcReg}, Opcode: SPIRV::OpUConvert))
1833 return false;
1834
1835 Register LowCount = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: WorkingType));
1836 if (!selectOpWithSrcs(ResVReg: LowCount, ResType: WorkingType, I, Srcs: {Trunc}, Opcode: SPIRV::OpBitCount))
1837 return false;
1838
1839 // Shift the high bits over and count them too.
1840 Register ShiftAmount = IsScalar
1841 ? GR.getOrCreateConstInt(Val: 32, I, SpvType: SrcType, TII)
1842 : GR.getOrCreateConstVector(Val: 32, I, SpvType: SrcType, TII);
1843 unsigned ShiftOp =
1844 IsScalar ? SPIRV::OpShiftRightLogicalS : SPIRV::OpShiftRightLogicalV;
1845 Register Shift = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: SrcType));
1846 if (!selectOpWithSrcs(ResVReg: Shift, ResType: SrcType, I, Srcs: {SrcReg, ShiftAmount}, Opcode: ShiftOp))
1847 return false;
1848
1849 Trunc = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: WorkingType));
1850 if (!selectOpWithSrcs(ResVReg: Trunc, ResType: WorkingType, I, Srcs: {Shift}, Opcode: SPIRV::OpUConvert))
1851 return false;
1852
1853 Register HighCount = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: WorkingType));
1854 if (!selectOpWithSrcs(ResVReg: HighCount, ResType: WorkingType, I, Srcs: {Trunc}, Opcode: SPIRV::OpBitCount))
1855 return false;
1856
1857 // Add them up and zext or sext back to 64 bit values.
1858 Register Sum = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: WorkingType));
1859 if (!selectOpWithSrcs(ResVReg: Sum, ResType: WorkingType, I, Srcs: {HighCount, LowCount},
1860 Opcode: IsScalar ? SPIRV::OpIAddS : SPIRV::OpIAddV))
1861 return false;
1862
1863 bool IsSigned = GR.isScalarOrVectorSigned(Type: ResType);
1864 unsigned ConvOp = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
1865 return selectOpWithSrcs(ResVReg, ResType, I, Srcs: {Sum}, Opcode: ConvOp);
1866}
1867
1868bool SPIRVInstructionSelector::selectPopCount(Register ResVReg,
1869 SPIRVTypeInst ResType,
1870 MachineInstr &I,
1871 unsigned Opcode) const {
1872 // Vulkan restricts OpBitCount to 32-bit integers or vectors of 32-bit
1873 // integers unless VK_KHR_maintenance9 is enabled. Until VK_KHR_maintenance9
1874 // is core we will not generate OpBitCount with any other types when
1875 // targeting Vulkan.
1876 if (!STI.getTargetTriple().isVulkanOS())
1877 return selectUnOp(ResVReg, ResType, I, Opcode);
1878
1879 Register OpReg = I.getOperand(i: 1).getReg();
1880 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(VReg: OpReg);
1881 unsigned ExtOpcode = GR.isScalarOrVectorSigned(Type: ResType) ? SPIRV::OpSConvert
1882 : SPIRV::OpUConvert;
1883 switch (GR.getScalarOrVectorBitWidth(Type: OpType)) {
1884 case 8:
1885 case 16:
1886 return selectPopCount16(ResVReg, ResType, I, ExtOpcode, Opcode);
1887 case 32:
1888 return selectPopCount32(ResVReg, ResType, I, SrcReg: OpReg, Opcode);
1889 case 64:
1890 return selectPopCount64(ResVReg, ResType, I, SrcReg: OpReg, Opcode);
1891 default:
1892 return diagnoseUnsupported(I, Msg: "unsupported operand bit width for popcount");
1893 }
1894}
1895
1896bool SPIRVInstructionSelector::selectUnOp(Register ResVReg,
1897 SPIRVTypeInst ResType,
1898 MachineInstr &I,
1899 unsigned Opcode) const {
1900 if (STI.isPhysicalSPIRV() && I.getOperand(i: 1).isReg()) {
1901 Register SrcReg = I.getOperand(i: 1).getReg();
1902 bool IsGV = false;
1903 for (MachineRegisterInfo::def_instr_iterator DefIt =
1904 MRI->def_instr_begin(RegNo: SrcReg);
1905 DefIt != MRI->def_instr_end(); DefIt = std::next(x: DefIt)) {
1906 unsigned DefOpCode = DefIt->getOpcode();
1907 if (DefOpCode == SPIRV::ASSIGN_TYPE || DefOpCode == TargetOpcode::COPY) {
1908 // We need special handling to look through the type assignment or the
1909 // COPY pseudo-op and see if this is a constant or a global.
1910 if (auto *VRD = getVRegDef(MRI&: *MRI, Reg: DefIt->getOperand(i: 1).getReg()))
1911 DefOpCode = VRD->getOpcode();
1912 }
1913 if (DefOpCode == TargetOpcode::G_GLOBAL_VALUE ||
1914 DefOpCode == TargetOpcode::G_CONSTANT ||
1915 DefOpCode == SPIRV::OpVariable ||
1916 DefOpCode == SPIRV::OpUntypedVariableKHR ||
1917 DefOpCode == SPIRV::OpConstantI) {
1918 IsGV = true;
1919 break;
1920 }
1921 }
1922 if (IsGV) {
1923 uint32_t SpecOpcode = 0;
1924 switch (Opcode) {
1925 case SPIRV::OpConvertPtrToU:
1926 SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertPtrToU);
1927 break;
1928 case SPIRV::OpConvertUToPtr:
1929 SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertUToPtr);
1930 break;
1931 }
1932 if (SpecOpcode) {
1933 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
1934 MCID: TII.get(Opcode: SPIRV::OpSpecConstantOp))
1935 .addDef(RegNo: ResVReg)
1936 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
1937 .addImm(Val: SpecOpcode)
1938 .addUse(RegNo: SrcReg)
1939 .constrainAllUses(TII, TRI, RBI);
1940 return true;
1941 }
1942 }
1943 }
1944 return selectOpWithSrcs(ResVReg, ResType, I, Srcs: {I.getOperand(i: 1).getReg()},
1945 Opcode);
1946}
1947
1948bool SPIRVInstructionSelector::selectBitcast(Register ResVReg,
1949 SPIRVTypeInst ResType,
1950 MachineInstr &I) const {
1951 Register OpReg = I.getOperand(i: 1).getReg();
1952 SPIRVTypeInst OpType =
1953 OpReg.isValid() ? GR.getSPIRVTypeForVReg(VReg: OpReg) : nullptr;
1954 if (!GR.isBitcastCompatible(Type1: ResType, Type2: OpType))
1955 return diagnoseUnsupported(
1956 I, Msg: "incompatible result and operand types in a bitcast");
1957 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpBitcast);
1958}
1959
1960static void
1961addMemoryOperands(const MachineMemOperand *MemOp, MachineInstrBuilder &MIB,
1962 MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry &GR,
1963 std::optional<Align> AlignOverride = std::nullopt) {
1964 const SPIRVSubtarget *ST =
1965 static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget());
1966 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
1967 if (MemOp->isVolatile())
1968 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
1969 if (MemOp->isNonTemporal())
1970 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
1971 // Aligned memory operand requires the Kernel capability.
1972 if (!ST->isShader() && MemOp->getAlign().value())
1973 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned);
1974
1975 [[maybe_unused]] MachineInstr *AliasList = nullptr;
1976 [[maybe_unused]] MachineInstr *NoAliasList = nullptr;
1977 if (ST->canUseExtension(E: SPIRV::Extension::SPV_INTEL_memory_access_aliasing)) {
1978 if (auto *MD = MemOp->getAAInfo().Scope) {
1979 AliasList = GR.getOrAddMemAliasingINTELInst(MIRBuilder, AliasingListMD: MD);
1980 if (AliasList)
1981 SpvMemOp |=
1982 static_cast<uint32_t>(SPIRV::MemoryOperand::AliasScopeINTELMask);
1983 }
1984 if (auto *MD = MemOp->getAAInfo().NoAlias) {
1985 NoAliasList = GR.getOrAddMemAliasingINTELInst(MIRBuilder, AliasingListMD: MD);
1986 if (NoAliasList)
1987 SpvMemOp |=
1988 static_cast<uint32_t>(SPIRV::MemoryOperand::NoAliasINTELMask);
1989 }
1990 }
1991
1992 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) {
1993 MIB.addImm(Val: SpvMemOp);
1994 if (SpvMemOp & static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned))
1995 MIB.addImm(Val: AlignOverride.value_or(u: MemOp->getAlign()).value());
1996 if (AliasList)
1997 MIB.addUse(RegNo: AliasList->getOperand(i: 0).getReg());
1998 if (NoAliasList)
1999 MIB.addUse(RegNo: NoAliasList->getOperand(i: 0).getReg());
2000 }
2001}
2002
2003static void addMemoryOperands(uint64_t Flags, MachineInstrBuilder &MIB) {
2004 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
2005 if (Flags & MachineMemOperand::Flags::MOVolatile)
2006 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
2007 if (Flags & MachineMemOperand::Flags::MONonTemporal)
2008 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
2009
2010 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None))
2011 MIB.addImm(Val: SpvMemOp);
2012}
2013
2014bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
2015 SPIRVTypeInst ResType,
2016 MachineInstr &I) const {
2017 unsigned OpOffset = isa<GIntrinsic>(Val: I) ? 1 : 0;
2018 Register Ptr = I.getOperand(i: 1 + OpOffset).getReg();
2019
2020 auto *PtrDef = getVRegDef(MRI&: *MRI, Reg: Ptr);
2021 auto *IntPtrDef = dyn_cast<GIntrinsic>(Val: PtrDef);
2022 if (IntPtrDef &&
2023 (IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
2024 IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
2025
2026 Register HandleReg = IntPtrDef->getOperand(i: 2).getReg();
2027 SPIRVTypeInst HandleType = GR.getSPIRVTypeForVReg(VReg: HandleReg);
2028 if (HandleType->getOpcode() == SPIRV::OpTypeImage) {
2029 Register NewHandleReg =
2030 MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: HandleReg));
2031 auto *HandleDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: HandleReg));
2032 if (!loadHandleBeforePosition(HandleReg&: NewHandleReg, ResType: HandleType, HandleDef&: *HandleDef, Pos&: I)) {
2033 return false;
2034 }
2035
2036 Register IdxReg = IntPtrDef->getOperand(i: 3).getReg();
2037 return generateImageReadOrFetch(ResVReg, ResType, ImageReg: NewHandleReg, IdxReg,
2038 Loc: I.getDebugLoc(), Pos&: I);
2039 }
2040 }
2041
2042 MachineIRBuilder MIRBuilder(I);
2043
2044 if (I.getNumMemOperands()) {
2045 const MachineMemOperand *MemOp = *I.memoperands_begin();
2046 if (MemOp->isAtomic())
2047 return selectAtomicLoad(ResVReg, ResType, I);
2048 }
2049
2050 auto MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpLoad)
2051 .addDef(RegNo: ResVReg)
2052 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2053 .addUse(RegNo: Ptr);
2054 if (!I.getNumMemOperands()) {
2055 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
2056 I.getOpcode() ==
2057 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
2058 addMemoryOperands(Flags: I.getOperand(i: 2 + OpOffset).getImm(), MIB);
2059 } else {
2060 addMemoryOperands(MemOp: *I.memoperands_begin(), MIB, MIRBuilder, GR);
2061 }
2062 MIB.constrainAllUses(TII, TRI, RBI);
2063 return true;
2064}
2065
2066Register SPIRVInstructionSelector::createPtrSizedIntReg(
2067 MachineIRBuilder &MIRBuilder) const {
2068 SPIRVTypeInst IntType =
2069 GR.getOrCreateSPIRVIntegerType(BitWidth: GR.getPointerSize(), MIRBuilder);
2070 Register Reg =
2071 MRI->createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: GR.getPointerSize()));
2072 MRI->setRegClass(Reg, RC: GR.getRegClass(SpvType: IntType));
2073 GR.assignSPIRVTypeToVReg(Type: IntType, VReg: Reg, MF: MIRBuilder.getMF());
2074 return Reg;
2075}
2076
2077Register
2078SPIRVInstructionSelector::convertPtrToInt(Register PtrVal,
2079 MachineIRBuilder &MIRBuilder) const {
2080 SPIRVTypeInst IntType =
2081 GR.getOrCreateSPIRVIntegerType(BitWidth: GR.getPointerSize(), MIRBuilder);
2082 Register IntReg = createPtrSizedIntReg(MIRBuilder);
2083 MIRBuilder.buildInstr(Opcode: SPIRV::OpConvertPtrToU)
2084 .addDef(RegNo: IntReg)
2085 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: IntType)) // Result type
2086 .addUse(RegNo: PtrVal) // Pointer operand
2087 .constrainAllUses(TII, TRI, RBI);
2088 return IntReg;
2089}
2090
2091Register SPIRVInstructionSelector::castPtrToPtrToInt(
2092 Register Ptr, SPIRV::StorageClass::StorageClass SC,
2093 MachineIRBuilder &MIRBuilder) const {
2094 SPIRVTypeInst IntType =
2095 GR.getOrCreateSPIRVIntegerType(BitWidth: GR.getPointerSize(), MIRBuilder);
2096 SPIRVTypeInst PtrType =
2097 GR.getOrCreateSPIRVPointerType(BaseType: IntType, MIRBuilder, SC);
2098 Register CastedPtr =
2099 MRI->createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: GR.getPointerSize()));
2100 MRI->setRegClass(Reg: CastedPtr, RC: GR.getRegClass(SpvType: PtrType));
2101 GR.assignSPIRVTypeToVReg(Type: PtrType, VReg: CastedPtr, MF: MIRBuilder.getMF());
2102 MIRBuilder.buildInstr(Opcode: SPIRV::OpBitcast)
2103 .addDef(RegNo: CastedPtr)
2104 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: PtrType))
2105 .addUse(RegNo: Ptr)
2106 .constrainAllUses(TII, TRI, RBI);
2107 return CastedPtr;
2108}
2109
2110bool SPIRVInstructionSelector::selectAtomicPtrValue(
2111 Register ResVReg, SPIRVTypeInst ResType, MachineIRBuilder &MIRBuilder,
2112 function_ref<Register(SPIRVTypeInst IntType)> EmitAtomic) const {
2113 // Pointer-typed atomics are lowered by bitcasting the Ptr operand to a
2114 // pointer to an integer of the same size as the pointer, so that the actual
2115 // atomic instruction operates on integers as required by the spec. Value
2116 // operands and results are converted with OpConvertPtrToU/OpConvertUToPtr.
2117 unsigned PtrSize = GR.getPointerSize();
2118 SPIRVTypeInst IntType = GR.getOrCreateSPIRVIntegerType(BitWidth: PtrSize, MIRBuilder);
2119
2120 Register IntResult = EmitAtomic(IntType);
2121 if (IntResult.isValid())
2122 MIRBuilder.buildInstr(Opcode: SPIRV::OpConvertUToPtr)
2123 .addDef(RegNo: ResVReg)
2124 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2125 .addUse(RegNo: IntResult)
2126 .constrainAllUses(TII, TRI, RBI);
2127 return true;
2128}
2129
2130bool SPIRVInstructionSelector::selectAtomicLoad(Register ResVReg,
2131 SPIRVTypeInst ResType,
2132 MachineInstr &I) const {
2133 LLVMContext &Context = I.getMF()->getFunction().getContext();
2134
2135 unsigned OpOffset = isa<GIntrinsic>(Val: I) ? 1 : 0;
2136 Register Ptr = I.getOperand(i: 1 + OpOffset).getReg();
2137
2138 if (!ResType.isTypeIntOrFloat() && !ResType.isTypePtr())
2139 return diagnoseUnsupported(
2140 I, Msg: "Lowering to SPIR-V of atomic load is only "
2141 "allowed for integer, floating point or pointer types");
2142
2143 assert(I.getNumMemOperands());
2144 const MachineMemOperand &MemOp = **I.memoperands_begin();
2145 assert(MemOp.isAtomic());
2146
2147 uint32_t Scope = static_cast<uint32_t>(
2148 getMemScope(TT: STI.getTargetTriple(), Ctx&: Context, Id: MemOp.getSyncScopeID()));
2149 Register ScopeReg = buildI32Constant(Val: Scope, I);
2150
2151 AtomicOrdering AO = MemOp.getSuccessOrdering();
2152 uint32_t StorageClass = static_cast<uint32_t>(getMemSemanticsForStorageClass(
2153 SC: addressSpaceToStorageClass(AddrSpace: MemOp.getAddrSpace(), STI)));
2154 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(Ord: AO));
2155 if (MemOp.isVolatile() && STI.getTargetTriple().isVulkanOS())
2156 MemSem |= static_cast<uint32_t>(SPIRV::MemorySemantics::Volatile);
2157 uint32_t Sem = getMemSemanticsWithStorageClass(TT: STI.getTargetTriple(), OrderSem: MemSem,
2158 StorageClassSem: StorageClass);
2159 Register MemSemReg = buildI32Constant(Val: Sem, I);
2160
2161 MachineIRBuilder MIRBuilder(I);
2162
2163 if (ResType.isTypePtr()) {
2164 if (!STI.isPhysicalSPIRV())
2165 return diagnoseUnsupported(
2166 I, Msg: "Lowering to SPIR-V of atomic load is only "
2167 "allowed for pointer types for physical addressing model");
2168 // If data to load is a pointer type we bitcast the Ptr parameter to pointer
2169 // to an integer type of the same size as the pointer size and then generate
2170 // OpAtomicLoad the return value of that OpAtomicLoad is an integer that is
2171 // converted back to a pointer type using OpConvertUToPtr.
2172 SPIRV::StorageClass::StorageClass SC =
2173 addressSpaceToStorageClass(AddrSpace: MemOp.getAddrSpace(), STI);
2174 return selectAtomicPtrValue(
2175 ResVReg, ResType, MIRBuilder, EmitAtomic: [&](SPIRVTypeInst IntType) {
2176 Register CastedPtr = castPtrToPtrToInt(Ptr, SC, MIRBuilder);
2177 Register IntResult = createPtrSizedIntReg(MIRBuilder);
2178 MIRBuilder.buildInstr(Opcode: SPIRV::OpAtomicLoad)
2179 .addDef(RegNo: IntResult)
2180 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: IntType))
2181 .addUse(RegNo: CastedPtr)
2182 .addUse(RegNo: ScopeReg)
2183 .addUse(RegNo: MemSemReg)
2184 .constrainAllUses(TII, TRI, RBI);
2185 return IntResult;
2186 });
2187 }
2188 auto AtomicLoad = MIRBuilder.buildInstr(Opcode: SPIRV::OpAtomicLoad)
2189 .addDef(RegNo: ResVReg)
2190 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2191 .addUse(RegNo: Ptr)
2192 .addUse(RegNo: ScopeReg)
2193 .addUse(RegNo: MemSemReg);
2194 AtomicLoad.constrainAllUses(TII, TRI, RBI);
2195
2196 return true;
2197}
2198
2199bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
2200 unsigned OpOffset = isa<GIntrinsic>(Val: I) ? 1 : 0;
2201 Register StoreVal = I.getOperand(i: 0 + OpOffset).getReg();
2202 Register Ptr = I.getOperand(i: 1 + OpOffset).getReg();
2203
2204 auto *PtrDef = getVRegDef(MRI&: *MRI, Reg: Ptr);
2205 auto *IntPtrDef = dyn_cast<GIntrinsic>(Val: PtrDef);
2206 if (IntPtrDef &&
2207 (IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
2208 IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
2209
2210 Register HandleReg = IntPtrDef->getOperand(i: 2).getReg();
2211 Register NewHandleReg =
2212 MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: HandleReg));
2213 auto *HandleDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: HandleReg));
2214 SPIRVTypeInst HandleType = GR.getSPIRVTypeForVReg(VReg: HandleReg);
2215 if (!loadHandleBeforePosition(HandleReg&: NewHandleReg, ResType: HandleType, HandleDef&: *HandleDef, Pos&: I)) {
2216 return false;
2217 }
2218
2219 Register IdxReg = IntPtrDef->getOperand(i: 3).getReg();
2220 if (HandleType->getOpcode() == SPIRV::OpTypeImage) {
2221 SPIRVTypeInst SampledType =
2222 GR.getSPIRVTypeForVReg(VReg: HandleType->getOperand(i: 1).getReg());
2223 SPIRVTypeInst StoreValCompType =
2224 GR.getScalarOrVectorComponentType(Type: GR.getSPIRVTypeForVReg(VReg: StoreVal));
2225 if (StoreValCompType && StoreValCompType != SampledType) {
2226 // A wide element (e.g. int64_t2) is emulated with a narrower packed
2227 // image. This bitcasts the value to match the format.
2228 SPIRVTypeInst PackedType = widenTypeToVec4(Type: SampledType, I);
2229 Register PackedReg =
2230 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: PackedType));
2231 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpBitcast))
2232 .addDef(RegNo: PackedReg)
2233 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: PackedType))
2234 .addUse(RegNo: StoreVal)
2235 .constrainAllUses(TII, TRI, RBI);
2236 StoreVal = PackedReg;
2237 }
2238
2239 auto BMI = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
2240 MCID: TII.get(Opcode: SPIRV::OpImageWrite))
2241 .addUse(RegNo: NewHandleReg)
2242 .addUse(RegNo: IdxReg)
2243 .addUse(RegNo: StoreVal);
2244
2245 const llvm::Type *LLVMHandleType = GR.getTypeForSPIRVType(Ty: HandleType);
2246 if (sampledTypeIsSignedInteger(HandleType: LLVMHandleType))
2247 BMI.addImm(Val: 0x1000); // SignExtend
2248
2249 BMI.constrainAllUses(TII, TRI, RBI);
2250 return true;
2251 }
2252 }
2253
2254 SPIRVTypeInst PointeeTy = GR.getPointeeType(PtrType: GR.getSPIRVTypeForVReg(VReg: Ptr));
2255 SPIRVTypeInst StoreTy = GR.getSPIRVTypeForVReg(VReg: StoreVal);
2256 if (PointeeTy && PointeeTy->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
2257 StoreTy->getOpcode() != SPIRV::OpTypeVectorIdEXT &&
2258 GR.getScalarOrVectorComponentCount(Type: PointeeTy) == 1) {
2259 MachineInstr *StoreValDef = getVRegDef(MRI&: *MRI, Reg: StoreVal);
2260 Register Reg = StoreValDef->getOperand(i: 0).getReg();
2261 if (auto FC = GFConstant::getConstant(Const: Reg, MRI: *MRI))
2262 StoreVal =
2263 GR.getOrCreateConstVector(Val: FC->getScalarValue(), I, SpvType: PointeeTy, TII);
2264 else if (auto IC = GIConstant::getConstant(Const: Reg, MRI: *MRI))
2265 StoreVal =
2266 GR.getOrCreateConstVector(Val: IC->getScalarValue(), I, SpvType: PointeeTy, TII);
2267 else
2268 llvm_unreachable("Unexpected <1 x T> Store type!");
2269 }
2270
2271 if (I.getNumMemOperands()) {
2272 const MachineMemOperand *MemOp = *I.memoperands_begin();
2273 if (MemOp->isAtomic())
2274 return selectAtomicStore(I);
2275 }
2276
2277 // Stores into a read-only storage class produce invalid SPIR-V. Reject such
2278 // input with a diagnostic rather than silently emitting an OpStore that
2279 // validation rejects.
2280 SPIRV::StorageClass::StorageClass PtrSC = GR.getPointerStorageClass(VReg: Ptr);
2281 if (PtrSC == SPIRV::StorageClass::UniformConstant ||
2282 PtrSC == SPIRV::StorageClass::Input ||
2283 PtrSC == SPIRV::StorageClass::PushConstant)
2284 return diagnoseUnsupported(
2285 I, Msg: "store into a read-only SPIR-V storage class is not allowed");
2286
2287 MachineIRBuilder MIRBuilder(I);
2288 auto MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpStore).addUse(RegNo: Ptr).addUse(RegNo: StoreVal);
2289 if (!I.getNumMemOperands()) {
2290 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
2291 I.getOpcode() ==
2292 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
2293 addMemoryOperands(Flags: I.getOperand(i: 2 + OpOffset).getImm(), MIB);
2294 } else {
2295 addMemoryOperands(MemOp: *I.memoperands_begin(), MIB, MIRBuilder, GR);
2296 }
2297 MIB.constrainAllUses(TII, TRI, RBI);
2298 return true;
2299}
2300
2301bool SPIRVInstructionSelector::selectAtomicStore(MachineInstr &I) const {
2302 LLVMContext &Context = I.getMF()->getFunction().getContext();
2303
2304 unsigned OpOffset = isa<GIntrinsic>(Val: I) ? 1 : 0;
2305 Register StoreVal = I.getOperand(i: 0 + OpOffset).getReg();
2306 Register Ptr = I.getOperand(i: 1 + OpOffset).getReg();
2307
2308 SPIRVTypeInst PtrType = GR.getSPIRVTypeForVReg(VReg: Ptr);
2309 SPIRVTypeInst PointeeType = GR.getPointeeType(PtrType);
2310 // For an untyped pointer the data type is the stored value's type.
2311 if (!PointeeType && PtrType &&
2312 PtrType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR)
2313 PointeeType = GR.getSPIRVTypeForVReg(VReg: StoreVal);
2314 if (!PointeeType)
2315 return diagnoseUnsupported(I,
2316 Msg: "Lowering to SPIR-V of atomic store is only "
2317 "allowed for integer or floating point types");
2318
2319 assert(I.getNumMemOperands());
2320 const MachineMemOperand &MemOp = **I.memoperands_begin();
2321 assert(MemOp.isAtomic());
2322
2323 uint32_t Scope = static_cast<uint32_t>(
2324 getMemScope(TT: STI.getTargetTriple(), Ctx&: Context, Id: MemOp.getSyncScopeID()));
2325 Register ScopeReg = buildI32Constant(Val: Scope, I);
2326
2327 AtomicOrdering AO = MemOp.getSuccessOrdering();
2328 uint32_t StorageClass = static_cast<uint32_t>(getMemSemanticsForStorageClass(
2329 SC: addressSpaceToStorageClass(AddrSpace: MemOp.getAddrSpace(), STI)));
2330 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(Ord: AO));
2331 if (MemOp.isVolatile() && STI.getTargetTriple().isVulkanOS())
2332 MemSem |= static_cast<uint32_t>(SPIRV::MemorySemantics::Volatile);
2333 uint32_t Sem = getMemSemanticsWithStorageClass(TT: STI.getTargetTriple(), OrderSem: MemSem,
2334 StorageClassSem: StorageClass);
2335 Register MemSemReg = buildI32Constant(Val: Sem, I);
2336 MachineIRBuilder MIRBuilder(I);
2337
2338 if (PointeeType.isTypePtr()) {
2339 if (!STI.isPhysicalSPIRV())
2340 return diagnoseUnsupported(
2341 I, Msg: "Lowering to SPIR-V of atomic store is only "
2342 "allowed for pointer types for physical addressing model");
2343 // If data to store is a pointer type we cast it to an integer type of the
2344 // same size as the pointer size using OpConvertPtrToU, bitcast Ptr
2345 // parameter to pointer to integer type and then generate OpAtomicStore
2346 // with casted values as required by spec.
2347 SPIRV::StorageClass::StorageClass SC =
2348 addressSpaceToStorageClass(AddrSpace: MemOp.getAddrSpace(), STI);
2349 return selectAtomicPtrValue(
2350 ResVReg: Register(), ResType: SPIRVTypeInst(), MIRBuilder, EmitAtomic: [&](SPIRVTypeInst IntType) {
2351 Register ValueAsInt = convertPtrToInt(PtrVal: StoreVal, MIRBuilder);
2352 Register CastedPtr = castPtrToPtrToInt(Ptr, SC, MIRBuilder);
2353 MIRBuilder.buildInstr(Opcode: SPIRV::OpAtomicStore)
2354 .addUse(RegNo: CastedPtr)
2355 .addUse(RegNo: ScopeReg)
2356 .addUse(RegNo: MemSemReg)
2357 .addUse(RegNo: ValueAsInt)
2358 .constrainAllUses(TII, TRI, RBI);
2359 // Stores produce no result, so no OpConvertUToPtr is needed.
2360 return Register();
2361 });
2362 }
2363
2364 if (!PointeeType.isTypeIntOrFloat())
2365 return diagnoseUnsupported(I,
2366 Msg: "Lowering to SPIR-V of atomic store is only "
2367 "allowed for integer or floating point types");
2368
2369 auto AtomicStore = MIRBuilder.buildInstr(Opcode: SPIRV::OpAtomicStore)
2370 .addUse(RegNo: Ptr)
2371 .addUse(RegNo: ScopeReg)
2372 .addUse(RegNo: MemSemReg)
2373 .addUse(RegNo: StoreVal);
2374 AtomicStore.constrainAllUses(TII, TRI, RBI);
2375
2376 return true;
2377}
2378
2379bool SPIRVInstructionSelector::selectMaskedGather(Register ResVReg,
2380 SPIRVTypeInst ResType,
2381 MachineInstr &I) const {
2382 assert(I.getNumExplicitDefs() == 1 && "Expected single def for gather");
2383 // Operand indices:
2384 // 0: result (def)
2385 // 1: intrinsic ID
2386 // 2: vector of pointers
2387 // 3: alignment (i32 immediate)
2388 // 4: mask (vector of i1)
2389 // 5: passthru/fill value
2390 const Register PtrsReg = I.getOperand(i: 2).getReg();
2391 const uint32_t Alignment = I.getOperand(i: 3).getImm();
2392 const Register MaskReg = I.getOperand(i: 4).getReg();
2393 const Register PassthruReg = I.getOperand(i: 5).getReg();
2394 const Register AlignmentReg = buildI32Constant(Val: Alignment, I);
2395
2396 MachineBasicBlock &BB = *I.getParent();
2397 auto MIB =
2398 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpMaskedGatherINTEL))
2399 .addDef(RegNo: ResVReg)
2400 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2401 .addUse(RegNo: PtrsReg)
2402 .addUse(RegNo: AlignmentReg)
2403 .addUse(RegNo: MaskReg)
2404 .addUse(RegNo: PassthruReg);
2405 MIB.constrainAllUses(TII, TRI, RBI);
2406 return true;
2407}
2408
2409bool SPIRVInstructionSelector::selectMaskedScatter(MachineInstr &I) const {
2410 assert(I.getNumExplicitDefs() == 0 && "Expected no defs for scatter");
2411 // Operand indices (no explicit defs):
2412 // 0: intrinsic ID
2413 // 1: value vector
2414 // 2: vector of pointers
2415 // 3: alignment (i32 immediate)
2416 // 4: mask (vector of i1)
2417 const Register ValuesReg = I.getOperand(i: 1).getReg();
2418 const Register PtrsReg = I.getOperand(i: 2).getReg();
2419 const uint32_t Alignment = I.getOperand(i: 3).getImm();
2420 const Register MaskReg = I.getOperand(i: 4).getReg();
2421 const Register AlignmentReg = buildI32Constant(Val: Alignment, I);
2422 MachineBasicBlock &BB = *I.getParent();
2423
2424 auto MIB =
2425 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpMaskedScatterINTEL))
2426 .addUse(RegNo: PtrsReg)
2427 .addUse(RegNo: AlignmentReg)
2428 .addUse(RegNo: MaskReg)
2429 .addUse(RegNo: ValuesReg);
2430 MIB.constrainAllUses(TII, TRI, RBI);
2431 return true;
2432}
2433
2434bool SPIRVInstructionSelector::diagnoseUnsupported(const MachineInstr &I,
2435 const Twine &Msg) const {
2436 const Function &F = I.getMF()->getFunction();
2437 F.getContext().diagnose(
2438 DI: DiagnosticInfoUnsupported(F, Msg, I.getDebugLoc(), DS_Error));
2439 return false;
2440}
2441
2442bool SPIRVInstructionSelector::selectStackSave(Register ResVReg,
2443 SPIRVTypeInst ResType,
2444 MachineInstr &I) const {
2445 if (!STI.canUseExtension(E: SPIRV::Extension::SPV_INTEL_variable_length_array))
2446 return diagnoseUnsupported(
2447 I, Msg: "llvm.stacksave intrinsic: this instruction requires the following "
2448 "SPIR-V extension: SPV_INTEL_variable_length_array");
2449 MachineBasicBlock &BB = *I.getParent();
2450 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpSaveMemoryINTEL))
2451 .addDef(RegNo: ResVReg)
2452 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2453 .constrainAllUses(TII, TRI, RBI);
2454 return true;
2455}
2456
2457bool SPIRVInstructionSelector::selectStackRestore(MachineInstr &I) const {
2458 if (!STI.canUseExtension(E: SPIRV::Extension::SPV_INTEL_variable_length_array))
2459 return diagnoseUnsupported(
2460 I,
2461 Msg: "llvm.stackrestore intrinsic: this instruction requires the following "
2462 "SPIR-V extension: SPV_INTEL_variable_length_array");
2463 if (!I.getOperand(i: 0).isReg())
2464 return false;
2465 MachineBasicBlock &BB = *I.getParent();
2466 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpRestoreMemoryINTEL))
2467 .addUse(RegNo: I.getOperand(i: 0).getReg())
2468 .constrainAllUses(TII, TRI, RBI);
2469 return true;
2470}
2471
2472Register
2473SPIRVInstructionSelector::getOrCreateMemSetGlobal(MachineInstr &I) const {
2474 MachineIRBuilder MIRBuilder(I);
2475 assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
2476
2477 // TODO: check if we have such GV, add init, use buildGlobalVariable.
2478 unsigned Num = getIConstVal(ConstReg: I.getOperand(i: 2).getReg(), MRI);
2479 Function &CurFunction = GR.CurMF->getFunction();
2480 Type *LLVMArrTy =
2481 ArrayType::get(ElementType: IntegerType::get(C&: CurFunction.getContext(), NumBits: 8), NumElements: Num);
2482 GlobalVariable *GV = new GlobalVariable(*CurFunction.getParent(), LLVMArrTy,
2483 true, GlobalValue::InternalLinkage,
2484 Constant::getNullValue(Ty: LLVMArrTy));
2485
2486 Type *ValTy = Type::getInt8Ty(C&: I.getMF()->getFunction().getContext());
2487 Type *ArrTy = ArrayType::get(ElementType: ValTy, NumElements: Num);
2488 SPIRVTypeInst VarTy = GR.getOrCreateSPIRVPointerType(
2489 BaseType: ArrTy, MIRBuilder, SC: SPIRV::StorageClass::UniformConstant);
2490
2491 SPIRVTypeInst SpvArrTy = GR.getOrCreateSPIRVType(
2492 Type: ArrTy, MIRBuilder, AQ: SPIRV::AccessQualifier::None, EmitIR: false);
2493
2494 unsigned Val = getIConstVal(ConstReg: I.getOperand(i: 1).getReg(), MRI);
2495 Register Const = GR.getOrCreateConstIntArray(Val, Num, I, SpvType: SpvArrTy, TII);
2496
2497 Register VarReg = MRI->createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 64));
2498 // With SPV_KHR_untyped_pointers enabled, getOrCreateSPIRVPointerType returns
2499 // an untyped pointer type. An untyped pointer result type is only legal on
2500 // OpUntypedVariableKHR, not on OpVariable.
2501 // Pick the matching opcode/operands so the synthesized constant global is
2502 // valid SPIR-V.
2503 const bool IsUntyped = VarTy->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
2504 auto MIBVar = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
2505 MCID: TII.get(Opcode: IsUntyped ? SPIRV::OpUntypedVariableKHR
2506 : SPIRV::OpVariable))
2507 .addDef(RegNo: VarReg)
2508 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: VarTy))
2509 .addImm(Val: SPIRV::StorageClass::UniformConstant);
2510 if (IsUntyped)
2511 MIBVar.addUse(RegNo: GR.getSPIRVTypeID(SpirvType: SpvArrTy)); // Data Type
2512 MIBVar.addUse(RegNo: Const); // Initializer
2513 MIBVar.constrainAllUses(TII, TRI, RBI);
2514
2515 GR.add(V: GV, MI: MIBVar);
2516 GR.addGlobalObject(V: GV, MF: GR.CurMF, R: VarReg);
2517
2518 buildOpDecorate(Reg: VarReg, I, TII, Dec: SPIRV::Decoration::Constant, DecArgs: {});
2519 return VarReg;
2520}
2521
2522bool SPIRVInstructionSelector::selectCopyMemory(MachineInstr &I,
2523 Register SrcReg) const {
2524 MachineBasicBlock &BB = *I.getParent();
2525 Register DstReg = I.getOperand(i: 0).getReg();
2526 const bool IsLogical = STI.isLogicalSPIRV();
2527 if (IsLogical) {
2528 SPIRVTypeInst DstTy = GR.getSPIRVTypeForVReg(VReg: DstReg);
2529 SPIRVTypeInst SrcTy = GR.getSPIRVTypeForVReg(VReg: SrcReg);
2530 if (GR.getPointeeType(PtrType: DstTy) != GR.getPointeeType(PtrType: SrcTy))
2531 return diagnoseUnsupported(
2532 I, Msg: "OpCopyMemory requires operands to have the same type");
2533 uint64_t CopySize = getIConstVal(ConstReg: I.getOperand(i: 2).getReg(), MRI);
2534 SPIRVTypeInst PointeeTy = GR.getPointeeType(PtrType: DstTy);
2535 const Type *LLVMPointeeTy = GR.getTypeForSPIRVType(Ty: PointeeTy);
2536 if (!LLVMPointeeTy)
2537 return diagnoseUnsupported(
2538 I, Msg: "Unable to determine pointee type size for OpCopyMemory");
2539 const DataLayout &DL = I.getMF()->getFunction().getDataLayout();
2540 if (CopySize != DL.getTypeStoreSize(Ty: const_cast<Type *>(LLVMPointeeTy)))
2541 return diagnoseUnsupported(
2542 I, Msg: "OpCopyMemory requires the size to match the pointee type size");
2543 }
2544
2545 const unsigned Opcode =
2546 IsLogical ? SPIRV::OpCopyMemory : SPIRV::OpCopyMemorySized;
2547 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
2548 .addUse(RegNo: DstReg)
2549 .addUse(RegNo: SrcReg);
2550 if (!IsLogical)
2551 MIB.addUse(RegNo: I.getOperand(i: 2).getReg());
2552
2553 if (I.getNumMemOperands()) {
2554 MachineIRBuilder MIRBuilder(I);
2555 const MachineMemOperand *DstMemOp = *I.memoperands_begin();
2556 const Align DstAlign = DstMemOp->getAlign();
2557 Align SrcAlign = DstAlign;
2558 // Copies carry destination and source MMOs; memset carries only the
2559 // destination. Shader memory operands do not include alignment.
2560 if (I.getNumMemOperands() > 1 && !STI.isShader())
2561 SrcAlign = (*std::next(x: I.memoperands_begin()))->getAlign();
2562
2563 // A single mask applies to both pointers. SPIR-V 1.4 allows separate
2564 // destination and source masks, preserving their individual alignments.
2565 if (DstAlign != SrcAlign && STI.isAtLeastSPIRVVer(VerToCompareTo: VersionTuple(1, 4))) {
2566 // Preserve the existing flags and metadata on both accesses.
2567 addMemoryOperands(MemOp: DstMemOp, MIB, MIRBuilder, GR);
2568 addMemoryOperands(MemOp: DstMemOp, MIB, MIRBuilder, GR, AlignOverride: SrcAlign);
2569 } else {
2570 addMemoryOperands(MemOp: DstMemOp, MIB, MIRBuilder, GR,
2571 AlignOverride: std::min(a: DstAlign, b: SrcAlign));
2572 }
2573 }
2574 MIB.constrainAllUses(TII, TRI, RBI);
2575 return true;
2576}
2577
2578bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg,
2579 MachineInstr &I) const {
2580 // Zero-sized memcpy/memmove/memset are no-ops.
2581 Register SizeReg = I.getOperand(i: 2).getReg();
2582 if (MachineInstr *SizeDef = getDefInstrMaybeConstant(ConstReg&: SizeReg, MRI);
2583 SizeDef && SizeDef->getOpcode() == TargetOpcode::G_CONSTANT &&
2584 getIConstVal(ConstReg: SizeReg, MRI) == 0)
2585 return true;
2586
2587 Register SrcReg = I.getOperand(i: 1).getReg();
2588 if (I.getOpcode() == TargetOpcode::G_MEMSET ||
2589 I.getOpcode() == TargetOpcode::G_MEMSET_INLINE) {
2590 Register VarReg = getOrCreateMemSetGlobal(I);
2591 if (!VarReg.isValid())
2592 return false;
2593 Type *ValTy = Type::getInt8Ty(C&: I.getMF()->getFunction().getContext());
2594 SPIRVTypeInst SourceTy = GR.getOrCreateSPIRVPointerType(
2595 BaseType: ValTy, I, SC: SPIRV::StorageClass::UniformConstant);
2596 SrcReg = MRI->createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 64));
2597 if (!selectOpWithSrcs(ResVReg: SrcReg, ResType: SourceTy, I, Srcs: {VarReg}, Opcode: SPIRV::OpBitcast))
2598 return false;
2599 }
2600 if (!selectCopyMemory(I, SrcReg))
2601 return false;
2602 if (ResVReg.isValid() && ResVReg != I.getOperand(i: 0).getReg())
2603 if (!BuildCOPY(DestReg: ResVReg, SrcReg: I.getOperand(i: 0).getReg(), I))
2604 return false;
2605 return true;
2606}
2607
2608bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg,
2609 SPIRVTypeInst ResType,
2610 MachineInstr &I,
2611 unsigned NewOpcode,
2612 unsigned NegateOpcode) const {
2613 assert(I.hasOneMemOperand());
2614 const MachineMemOperand *MemOp = *I.memoperands_begin();
2615 uint32_t Scope = static_cast<uint32_t>(
2616 getMemScope(TT: STI.getTargetTriple(), Ctx&: GR.CurMF->getFunction().getContext(),
2617 Id: MemOp->getSyncScopeID()));
2618 Register ScopeReg = buildI32Constant(Val: Scope, I);
2619
2620 Register Ptr = I.getOperand(i: 1).getReg();
2621 uint32_t ScSem = static_cast<uint32_t>(
2622 getMemSemanticsForStorageClass(SC: GR.getPointerStorageClass(VReg: Ptr)));
2623 AtomicOrdering AO = MemOp->getSuccessOrdering();
2624 uint32_t OrderSem = static_cast<uint32_t>(getMemSemantics(Ord: AO));
2625 Register MemSemReg = buildI32Constant(
2626 Val: getMemSemanticsWithStorageClass(TT: STI.getTargetTriple(), OrderSem, StorageClassSem: ScSem),
2627 I);
2628
2629 Register ValueReg = I.getOperand(i: 2).getReg();
2630 if (NegateOpcode != 0) {
2631 // Translation with negative value operand is requested
2632 Register TmpReg = createVirtualRegister(SpvType: ResType, GR: &GR, MRI, MF: MRI->getMF());
2633 if (!selectOpWithSrcs(ResVReg: TmpReg, ResType, I, Srcs: {ValueReg}, Opcode: NegateOpcode))
2634 return false;
2635 ValueReg = TmpReg;
2636 }
2637
2638 if (ResType.isTypePtr()) {
2639 if (NewOpcode != SPIRV::OpAtomicExchange)
2640 return diagnoseUnsupported(
2641 I, Msg: "Lowering to SPIR-V of this atomic operation is not "
2642 "allowed for pointer types");
2643 if (!STI.isPhysicalSPIRV())
2644 return diagnoseUnsupported(
2645 I, Msg: "Lowering to SPIR-V of atomic exchange is only "
2646 "allowed for pointer types for physical addressing model");
2647 // If the exchanged value is a pointer type we convert the value operand to
2648 // an integer type of the same size as the pointer size using
2649 // OpConvertPtrToU, bitcast the Ptr parameter to pointer to integer type and
2650 // then generate OpAtomicExchange on integers. The integer result is
2651 // converted back to a pointer type using OpConvertUToPtr, similar to atomic
2652 // load and store.
2653 MachineIRBuilder MIRBuilder(I);
2654 SPIRV::StorageClass::StorageClass SC = GR.getPointerStorageClass(VReg: Ptr);
2655 return selectAtomicPtrValue(
2656 ResVReg, ResType, MIRBuilder, EmitAtomic: [&](SPIRVTypeInst IntType) {
2657 Register ValueAsInt = convertPtrToInt(PtrVal: ValueReg, MIRBuilder);
2658 Register CastedPtr = castPtrToPtrToInt(Ptr, SC, MIRBuilder);
2659 Register ExchangeResReg = createPtrSizedIntReg(MIRBuilder);
2660 MIRBuilder.buildInstr(Opcode: SPIRV::OpAtomicExchange)
2661 .addDef(RegNo: ExchangeResReg)
2662 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: IntType))
2663 .addUse(RegNo: CastedPtr)
2664 .addUse(RegNo: ScopeReg)
2665 .addUse(RegNo: MemSemReg)
2666 .addUse(RegNo: ValueAsInt)
2667 .constrainAllUses(TII, TRI, RBI);
2668 return ExchangeResReg;
2669 });
2670 }
2671
2672 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: NewOpcode))
2673 .addDef(RegNo: ResVReg)
2674 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2675 .addUse(RegNo: Ptr)
2676 .addUse(RegNo: ScopeReg)
2677 .addUse(RegNo: MemSemReg)
2678 .addUse(RegNo: ValueReg)
2679 .constrainAllUses(TII, TRI, RBI);
2680 return true;
2681}
2682
2683bool SPIRVInstructionSelector::selectUnmergeValues(MachineInstr &I) const {
2684 unsigned ArgI = I.getNumOperands() - 1;
2685 Register SrcReg =
2686 I.getOperand(i: ArgI).isReg() ? I.getOperand(i: ArgI).getReg() : Register(0);
2687 SPIRVTypeInst SrcType =
2688 SrcReg.isValid() ? GR.getSPIRVTypeForVReg(VReg: SrcReg) : nullptr;
2689 if (!SrcType || !isVectorType(SPVTy: SrcType))
2690 report_fatal_error(
2691 reason: "cannot select G_UNMERGE_VALUES with a non-vector argument");
2692
2693 SPIRVTypeInst ScalarType = GR.getScalarOrVectorComponentType(Type: SrcType);
2694 MachineBasicBlock &BB = *I.getParent();
2695 unsigned CurrentIndex = 0;
2696 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
2697 Register ResVReg = I.getOperand(i).getReg();
2698 SPIRVTypeInst ResType = GR.getSPIRVTypeForVReg(VReg: ResVReg);
2699 if (!ResType) {
2700 LLT ResLLT = MRI->getType(Reg: ResVReg);
2701 assert(ResLLT.isValid());
2702 if (ResLLT.isVector()) {
2703 ResType = GR.getOrCreateSPIRVVectorType(
2704 BaseType: ScalarType, NumElements: ResLLT.getNumElements(), I, TII);
2705 } else {
2706 ResType = ScalarType;
2707 }
2708 MRI->setRegClass(Reg: ResVReg, RC: GR.getRegClass(SpvType: ResType));
2709 GR.assignSPIRVTypeToVReg(Type: ResType, VReg: ResVReg, MF: *GR.CurMF);
2710 }
2711
2712 if (isVectorType(SPVTy: ResType)) {
2713 Register UndefReg = GR.getOrCreateUndef(I, SpvType: SrcType, TII);
2714 auto MIB =
2715 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpVectorShuffle))
2716 .addDef(RegNo: ResVReg)
2717 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2718 .addUse(RegNo: SrcReg)
2719 .addUse(RegNo: UndefReg);
2720 unsigned NumElements = GR.getScalarOrVectorComponentCount(Type: ResType);
2721 for (unsigned j = 0; j < NumElements; ++j) {
2722 MIB.addImm(Val: CurrentIndex + j);
2723 }
2724 CurrentIndex += NumElements;
2725 MIB.constrainAllUses(TII, TRI, RBI);
2726 } else {
2727 auto MIB =
2728 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpCompositeExtract))
2729 .addDef(RegNo: ResVReg)
2730 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2731 .addUse(RegNo: SrcReg)
2732 .addImm(Val: CurrentIndex);
2733 CurrentIndex++;
2734 MIB.constrainAllUses(TII, TRI, RBI);
2735 }
2736 }
2737 return true;
2738}
2739
2740bool SPIRVInstructionSelector::selectFence(MachineInstr &I) const {
2741 AtomicOrdering AO = AtomicOrdering(I.getOperand(i: 0).getImm());
2742 uint32_t ScSem = STI.isShader()
2743 ? SPIRV::MemorySemantics::UniformMemory |
2744 SPIRV::MemorySemantics::WorkgroupMemory |
2745 SPIRV::MemorySemantics::ImageMemory
2746 : SPIRV::MemorySemantics::WorkgroupMemory |
2747 SPIRV::MemorySemantics::CrossWorkgroupMemory |
2748 SPIRV::MemorySemantics::ImageMemory;
2749 uint32_t MemSem = getMemSemanticsWithStorageClass(
2750 TT: STI.getTargetTriple(), OrderSem: static_cast<uint32_t>(getMemSemantics(Ord: AO)), StorageClassSem: ScSem);
2751 Register MemSemReg = buildI32ConstantInEntryBlock(Val: MemSem, I);
2752 SyncScope::ID Ord = SyncScope::ID(I.getOperand(i: 1).getImm());
2753 uint32_t Scope = static_cast<uint32_t>(getMemScope(
2754 TT: STI.getTargetTriple(), Ctx&: GR.CurMF->getFunction().getContext(), Id: Ord));
2755 Register ScopeReg = buildI32ConstantInEntryBlock(Val: Scope, I);
2756 MachineBasicBlock &BB = *I.getParent();
2757 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpMemoryBarrier))
2758 .addUse(RegNo: ScopeReg)
2759 .addUse(RegNo: MemSemReg)
2760 .constrainAllUses(TII, TRI, RBI);
2761 return true;
2762}
2763
2764bool SPIRVInstructionSelector::selectOverflowArith(Register ResVReg,
2765 SPIRVTypeInst ResType,
2766 MachineInstr &I,
2767 unsigned Opcode) const {
2768 Type *ResTy = nullptr;
2769 StringRef ResName;
2770 if (!GR.findValueAttrs(Key: &I, Ty&: ResTy, Name&: ResName))
2771 return diagnoseUnsupported(
2772 I,
2773 Msg: "Not enough info to select the arithmetic with overflow instruction");
2774 if (!ResTy || !ResTy->isStructTy())
2775 return diagnoseUnsupported(I,
2776 Msg: "Expect struct type result for the arithmetic "
2777 "with overflow instruction");
2778 // "Result Type must be from OpTypeStruct. The struct must have two members,
2779 // and the two members must be the same type."
2780 Type *ResElemTy = cast<StructType>(Val: ResTy)->getElementType(N: 0);
2781 ResTy = StructType::get(elt1: ResElemTy, elts: ResElemTy);
2782 // Build SPIR-V types and constant(s) if needed.
2783 MachineIRBuilder MIRBuilder(I);
2784 SPIRVTypeInst StructType = GR.getOrCreateSPIRVType(
2785 Type: ResTy, MIRBuilder, AQ: SPIRV::AccessQualifier::ReadWrite, EmitIR: false);
2786 assert(I.getNumDefs() > 1 && "Not enought operands");
2787 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
2788 unsigned N = GR.getScalarOrVectorComponentCount(Type: ResType);
2789 if (N > 1 || (isVectorType(SPVTy: ResType) &&
2790 STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector)))
2791 BoolType = GR.getOrCreateSPIRVVectorType(BaseType: BoolType, NumElements: N, I, TII);
2792 Register BoolTypeReg = GR.getSPIRVTypeID(SpirvType: BoolType);
2793 Register ZeroReg = buildZerosVal(ResType, I);
2794 // A new virtual register to store the result struct.
2795 Register StructVReg = MRI->createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 64));
2796 MRI->setRegClass(Reg: StructVReg, RC: &SPIRV::IDRegClass);
2797 // Build the result name if needed.
2798 if (ResName.size() > 0)
2799 buildOpName(Target: StructVReg, Name: ResName, MIRBuilder);
2800 // Build the arithmetic with overflow instruction.
2801 MachineBasicBlock &BB = *I.getParent();
2802 auto MIB =
2803 BuildMI(BB, I: MIRBuilder.getInsertPt(), MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
2804 .addDef(RegNo: StructVReg)
2805 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: StructType));
2806 for (unsigned i = I.getNumDefs(); i < I.getNumOperands(); ++i)
2807 MIB.addUse(RegNo: I.getOperand(i).getReg());
2808 MIB.constrainAllUses(TII, TRI, RBI);
2809 // Build instructions to extract fields of the instruction's result.
2810 // A new virtual register to store the higher part of the result struct.
2811 Register HigherVReg = MRI->createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 64));
2812 MRI->setRegClass(Reg: HigherVReg, RC: &SPIRV::iIDRegClass);
2813 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
2814 auto MIB =
2815 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpCompositeExtract))
2816 .addDef(RegNo: i == 1 ? HigherVReg : I.getOperand(i).getReg())
2817 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2818 .addUse(RegNo: StructVReg)
2819 .addImm(Val: i);
2820 MIB.constrainAllUses(TII, TRI, RBI);
2821 }
2822 // Build boolean value from the higher part.
2823 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpINotEqual))
2824 .addDef(RegNo: I.getOperand(i: 1).getReg())
2825 .addUse(RegNo: BoolTypeReg)
2826 .addUse(RegNo: HigherVReg)
2827 .addUse(RegNo: ZeroReg)
2828 .constrainAllUses(TII, TRI, RBI);
2829 return true;
2830}
2831
2832bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg,
2833 SPIRVTypeInst ResType,
2834 MachineInstr &I) const {
2835 assert(isa<GIntrinsic>(I) &&
2836 "selectAtomicCmpXchg only handles the spv_cmpxchg intrinsic");
2837 Register Ptr = I.getOperand(i: 2).getReg();
2838 Register ScopeReg = I.getOperand(i: 5).getReg();
2839 Register MemSemEqReg = I.getOperand(i: 6).getReg();
2840 Register MemSemNeqReg = I.getOperand(i: 7).getReg();
2841 Register Cmp = I.getOperand(i: 3).getReg();
2842 Register Val = I.getOperand(i: 4).getReg();
2843 SPIRVTypeInst SpvValTy = GR.getSPIRVTypeForVReg(VReg: Val);
2844 Register ACmpRes = createVirtualRegister(SpvType: SpvValTy, GR: &GR, MRI, MF: *I.getMF());
2845 const DebugLoc &DL = I.getDebugLoc();
2846 BuildMI(BB&: *I.getParent(), I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpAtomicCompareExchange))
2847 .addDef(RegNo: ACmpRes)
2848 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: SpvValTy))
2849 .addUse(RegNo: Ptr)
2850 .addUse(RegNo: ScopeReg)
2851 .addUse(RegNo: MemSemEqReg)
2852 .addUse(RegNo: MemSemNeqReg)
2853 .addUse(RegNo: Val)
2854 .addUse(RegNo: Cmp)
2855 .constrainAllUses(TII, TRI, RBI);
2856 SPIRVTypeInst BoolTy = GR.getOrCreateSPIRVBoolType(I, TII);
2857 Register CmpSuccReg = createVirtualRegister(SpvType: BoolTy, GR: &GR, MRI, MF: *I.getMF());
2858 BuildMI(BB&: *I.getParent(), I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpIEqual))
2859 .addDef(RegNo: CmpSuccReg)
2860 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: BoolTy))
2861 .addUse(RegNo: ACmpRes)
2862 .addUse(RegNo: Cmp)
2863 .constrainAllUses(TII, TRI, RBI);
2864 Register TmpReg = createVirtualRegister(SpvType: ResType, GR: &GR, MRI, MF: *I.getMF());
2865 BuildMI(BB&: *I.getParent(), I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpCompositeInsert))
2866 .addDef(RegNo: TmpReg)
2867 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2868 .addUse(RegNo: ACmpRes)
2869 .addUse(RegNo: GR.getOrCreateUndef(I, SpvType: ResType, TII))
2870 .addImm(Val: 0)
2871 .constrainAllUses(TII, TRI, RBI);
2872 BuildMI(BB&: *I.getParent(), I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpCompositeInsert))
2873 .addDef(RegNo: ResVReg)
2874 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
2875 .addUse(RegNo: CmpSuccReg)
2876 .addUse(RegNo: TmpReg)
2877 .addImm(Val: 1)
2878 .constrainAllUses(TII, TRI, RBI);
2879 return true;
2880}
2881
2882static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) {
2883 switch (SC) {
2884 case SPIRV::StorageClass::DeviceOnlyINTEL:
2885 case SPIRV::StorageClass::HostOnlyINTEL:
2886 return true;
2887 default:
2888 return false;
2889 }
2890}
2891
2892// Returns true ResVReg is referred only from global vars and OpName's.
2893static bool isASCastInGVar(MachineRegisterInfo *MRI, Register ResVReg) {
2894 bool IsGRef = false;
2895 bool IsAllowedRefs =
2896 llvm::all_of(Range: MRI->use_instructions(Reg: ResVReg), P: [&IsGRef](auto const &It) {
2897 unsigned Opcode = It.getOpcode();
2898 if (Opcode == SPIRV::OpConstantComposite ||
2899 Opcode == SPIRV::OpSpecConstantComposite ||
2900 Opcode == SPIRV::OpVariable ||
2901 Opcode == SPIRV::OpUntypedVariableKHR ||
2902 isSpvIntrinsic(It, Intrinsic::spv_init_global))
2903 return IsGRef = true;
2904 return Opcode == SPIRV::OpName;
2905 });
2906 return IsAllowedRefs && IsGRef;
2907}
2908
2909Register SPIRVInstructionSelector::getUcharPtrTypeReg(
2910 MachineInstr &I, SPIRV::StorageClass::StorageClass SC) const {
2911 return GR.getSPIRVTypeID(SpirvType: GR.getOrCreateSPIRVPointerType(
2912 BaseType: Type::getInt8Ty(C&: I.getMF()->getFunction().getContext()), I, SC));
2913}
2914
2915MachineInstrBuilder
2916SPIRVInstructionSelector::buildSpecConstantOp(MachineInstr &I, Register Dest,
2917 Register Src, Register DestType,
2918 uint32_t Opcode) const {
2919 return BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
2920 MCID: TII.get(Opcode: SPIRV::OpSpecConstantOp))
2921 .addDef(RegNo: Dest)
2922 .addUse(RegNo: DestType)
2923 .addImm(Val: Opcode)
2924 .addUse(RegNo: Src);
2925}
2926
2927MachineInstrBuilder
2928SPIRVInstructionSelector::buildConstGenericPtr(MachineInstr &I, Register SrcPtr,
2929 SPIRVTypeInst SrcPtrTy) const {
2930 SPIRVTypeInst GenericPtrTy =
2931 GR.changePointerStorageClass(PtrType: SrcPtrTy, SC: SPIRV::StorageClass::Generic, I);
2932 Register Tmp = MRI->createVirtualRegister(RegClass: &SPIRV::pIDRegClass);
2933 MRI->setType(VReg: Tmp, Ty: LLT::pointer(AddressSpace: storageClassToAddressSpace(
2934 SC: SPIRV::StorageClass::Generic),
2935 SizeInBits: GR.getPointerSize()));
2936 MachineFunction *MF = I.getParent()->getParent();
2937 GR.assignSPIRVTypeToVReg(Type: GenericPtrTy, VReg: Tmp, MF: *MF);
2938 MachineInstrBuilder MIB = buildSpecConstantOp(
2939 I, Dest: Tmp, Src: SrcPtr, DestType: GR.getSPIRVTypeID(SpirvType: GenericPtrTy),
2940 Opcode: static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric));
2941 GR.add(Obj: MIB.getInstr(), MI: MIB);
2942 return MIB;
2943}
2944
2945// In SPIR-V address space casting can only happen to and from the Generic
2946// storage class. We can also only cast Workgroup, CrossWorkgroup, or Function
2947// pointers to and from Generic pointers. As such, we can convert e.g. from
2948// Workgroup to Function by going via a Generic pointer as an intermediary. All
2949// other combinations can only be done by a bitcast, and are probably not safe.
2950bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
2951 SPIRVTypeInst ResType,
2952 MachineInstr &I) const {
2953 MachineBasicBlock &BB = *I.getParent();
2954 const DebugLoc &DL = I.getDebugLoc();
2955
2956 Register SrcPtr = I.getOperand(i: 1).getReg();
2957 SPIRVTypeInst SrcPtrTy = GR.getSPIRVTypeForVReg(VReg: SrcPtr);
2958
2959 // don't generate a cast for a null that may be represented by OpTypeInt
2960 if (!SrcPtrTy || !SrcPtrTy.isPointer() || !ResType || !ResType.isPointer())
2961 return BuildCOPY(DestReg: ResVReg, SrcReg: SrcPtr, I);
2962
2963 SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(Type: SrcPtrTy);
2964 SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(Type: ResType);
2965
2966 if (isASCastInGVar(MRI, ResVReg)) {
2967 // AddrSpaceCast uses within OpVariable and OpConstantComposite instructions
2968 // are expressed by OpSpecConstantOp with an Opcode.
2969 // TODO: maybe insert a check whether the Kernel capability was declared and
2970 // so PtrCastToGeneric/GenericCastToPtr are available.
2971 unsigned SpecOpcode = [&]() -> unsigned {
2972 if (SrcSC == SPIRV::StorageClass::CodeSectionINTEL)
2973 return static_cast<uint32_t>(SPIRV::Opcode::Bitcast);
2974 if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SC: SrcSC))
2975 return static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric);
2976 if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SC: DstSC))
2977 return static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr);
2978 return 0u;
2979 }();
2980 // TODO: OpConstantComposite expects i8*, so we are forced to forget a
2981 // correct value of ResType and use general i8* instead. Maybe this should
2982 // be addressed in the emit-intrinsic step to infer a correct
2983 // OpConstantComposite type.
2984 if (SpecOpcode) {
2985 buildSpecConstantOp(I, Dest: ResVReg, Src: SrcPtr, DestType: getUcharPtrTypeReg(I, SC: DstSC),
2986 Opcode: SpecOpcode)
2987 .constrainAllUses(TII, TRI, RBI);
2988 } else if (isGenericCastablePtr(SC: SrcSC) && isGenericCastablePtr(SC: DstSC)) {
2989 MachineInstrBuilder MIB = buildConstGenericPtr(I, SrcPtr, SrcPtrTy);
2990 MIB.constrainAllUses(TII, TRI, RBI);
2991 buildSpecConstantOp(
2992 I, Dest: ResVReg, Src: MIB->getOperand(i: 0).getReg(), DestType: getUcharPtrTypeReg(I, SC: DstSC),
2993 Opcode: static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr))
2994 .constrainAllUses(TII, TRI, RBI);
2995 }
2996 return true;
2997 }
2998
2999 // don't generate a cast between identical storage classes
3000 if (SrcSC == DstSC)
3001 return BuildCOPY(DestReg: ResVReg, SrcReg: SrcPtr, I);
3002
3003 if ((SrcSC == SPIRV::StorageClass::Function &&
3004 DstSC == SPIRV::StorageClass::Private) ||
3005 (DstSC == SPIRV::StorageClass::Function &&
3006 SrcSC == SPIRV::StorageClass::Private))
3007 return BuildCOPY(DestReg: ResVReg, SrcReg: SrcPtr, I);
3008
3009 // Casting from an eligible pointer to Generic.
3010 if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SC: SrcSC))
3011 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpPtrCastToGeneric);
3012 // Casting from Generic to an eligible pointer.
3013 if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SC: DstSC))
3014 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpGenericCastToPtr);
3015 // Casting between 2 eligible pointers using Generic as an intermediary.
3016 if (isGenericCastablePtr(SC: SrcSC) && isGenericCastablePtr(SC: DstSC)) {
3017 SPIRVTypeInst GenericPtrTy =
3018 GR.changePointerStorageClass(PtrType: SrcPtrTy, SC: SPIRV::StorageClass::Generic, I);
3019 Register Tmp = createVirtualRegister(SpvType: GenericPtrTy, GR: &GR, MRI, MF: MRI->getMF());
3020 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpPtrCastToGeneric))
3021 .addDef(RegNo: Tmp)
3022 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: GenericPtrTy))
3023 .addUse(RegNo: SrcPtr)
3024 .constrainAllUses(TII, TRI, RBI);
3025 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpGenericCastToPtr))
3026 .addDef(RegNo: ResVReg)
3027 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3028 .addUse(RegNo: Tmp)
3029 .constrainAllUses(TII, TRI, RBI);
3030 return true;
3031 }
3032
3033 // Check if instructions from the SPV_INTEL_usm_storage_classes extension may
3034 // be applied
3035 if (isUSMStorageClass(SC: SrcSC) && DstSC == SPIRV::StorageClass::CrossWorkgroup)
3036 return selectUnOp(ResVReg, ResType, I,
3037 Opcode: SPIRV::OpPtrCastToCrossWorkgroupINTEL);
3038 if (SrcSC == SPIRV::StorageClass::CrossWorkgroup && isUSMStorageClass(SC: DstSC))
3039 return selectUnOp(ResVReg, ResType, I,
3040 Opcode: SPIRV::OpCrossWorkgroupCastToPtrINTEL);
3041 if (isUSMStorageClass(SC: SrcSC) && DstSC == SPIRV::StorageClass::Generic)
3042 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpPtrCastToGeneric);
3043 if (SrcSC == SPIRV::StorageClass::Generic && isUSMStorageClass(SC: DstSC))
3044 return selectUnOp(ResVReg, ResType, I, Opcode: SPIRV::OpGenericCastToPtr);
3045
3046 // Bitcast for pointers requires that the address spaces must match
3047 return false;
3048}
3049
3050// G_PTRMASK - Apply a bitmask to a pointer value.
3051// Result = Ptr & Mask
3052// We need to convert the pointer to an integer, perform the AND operation,
3053// and convert back to a pointer.
3054bool SPIRVInstructionSelector::selectPtrMask(Register ResVReg,
3055 SPIRVTypeInst ResType,
3056 MachineInstr &I) const {
3057 if (STI.isLogicalSPIRV())
3058 return diagnoseUnsupported(
3059 I, Msg: "G_PTRMASK is not supported with logical SPIR-V");
3060 MachineBasicBlock &BB = *I.getParent();
3061 MachineFunction &MF = *BB.getParent();
3062 const DebugLoc &DL = I.getDebugLoc();
3063
3064 Register PtrReg = I.getOperand(i: 1).getReg();
3065 Register MaskReg = I.getOperand(i: 2).getReg();
3066
3067 SPIRVTypeInst MaskType = GR.getSPIRVTypeForVReg(VReg: MaskReg);
3068
3069 // Convert pointer to integer.
3070 Register PtrAsInt = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: MaskType));
3071 GR.assignSPIRVTypeToVReg(Type: MaskType, VReg: PtrAsInt, MF);
3072
3073 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpConvertPtrToU))
3074 .addDef(RegNo: PtrAsInt)
3075 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: MaskType))
3076 .addUse(RegNo: PtrReg)
3077 .constrainAllUses(TII, TRI, RBI);
3078
3079 // Perform bitwise AND.
3080 Register MaskedInt = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: MaskType));
3081 GR.assignSPIRVTypeToVReg(Type: MaskType, VReg: MaskedInt, MF);
3082
3083 unsigned AndOpcode = GR.getScalarOrVectorComponentCount(Type: MaskType) > 1
3084 ? SPIRV::OpBitwiseAndV
3085 : SPIRV::OpBitwiseAndS;
3086
3087 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: AndOpcode))
3088 .addDef(RegNo: MaskedInt)
3089 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: MaskType))
3090 .addUse(RegNo: PtrAsInt)
3091 .addUse(RegNo: MaskReg)
3092 .constrainAllUses(TII, TRI, RBI);
3093
3094 // Convert integer back to pointer.
3095 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpConvertUToPtr))
3096 .addDef(RegNo: ResVReg)
3097 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3098 .addUse(RegNo: MaskedInt)
3099 .constrainAllUses(TII, TRI, RBI);
3100
3101 return true;
3102}
3103
3104static unsigned getFCmpOpcode(unsigned PredNum) {
3105 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
3106 switch (Pred) {
3107 case CmpInst::FCMP_OEQ:
3108 return SPIRV::OpFOrdEqual;
3109 case CmpInst::FCMP_OGE:
3110 return SPIRV::OpFOrdGreaterThanEqual;
3111 case CmpInst::FCMP_OGT:
3112 return SPIRV::OpFOrdGreaterThan;
3113 case CmpInst::FCMP_OLE:
3114 return SPIRV::OpFOrdLessThanEqual;
3115 case CmpInst::FCMP_OLT:
3116 return SPIRV::OpFOrdLessThan;
3117 case CmpInst::FCMP_ONE:
3118 return SPIRV::OpFOrdNotEqual;
3119 case CmpInst::FCMP_ORD:
3120 return SPIRV::OpOrdered;
3121 case CmpInst::FCMP_UEQ:
3122 return SPIRV::OpFUnordEqual;
3123 case CmpInst::FCMP_UGE:
3124 return SPIRV::OpFUnordGreaterThanEqual;
3125 case CmpInst::FCMP_UGT:
3126 return SPIRV::OpFUnordGreaterThan;
3127 case CmpInst::FCMP_ULE:
3128 return SPIRV::OpFUnordLessThanEqual;
3129 case CmpInst::FCMP_ULT:
3130 return SPIRV::OpFUnordLessThan;
3131 case CmpInst::FCMP_UNE:
3132 return SPIRV::OpFUnordNotEqual;
3133 case CmpInst::FCMP_UNO:
3134 return SPIRV::OpUnordered;
3135 default:
3136 llvm_unreachable("Unknown predicate type for FCmp");
3137 }
3138}
3139
3140static unsigned getICmpOpcode(unsigned PredNum) {
3141 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
3142 switch (Pred) {
3143 case CmpInst::ICMP_EQ:
3144 return SPIRV::OpIEqual;
3145 case CmpInst::ICMP_NE:
3146 return SPIRV::OpINotEqual;
3147 case CmpInst::ICMP_SGE:
3148 return SPIRV::OpSGreaterThanEqual;
3149 case CmpInst::ICMP_SGT:
3150 return SPIRV::OpSGreaterThan;
3151 case CmpInst::ICMP_SLE:
3152 return SPIRV::OpSLessThanEqual;
3153 case CmpInst::ICMP_SLT:
3154 return SPIRV::OpSLessThan;
3155 case CmpInst::ICMP_UGE:
3156 return SPIRV::OpUGreaterThanEqual;
3157 case CmpInst::ICMP_UGT:
3158 return SPIRV::OpUGreaterThan;
3159 case CmpInst::ICMP_ULE:
3160 return SPIRV::OpULessThanEqual;
3161 case CmpInst::ICMP_ULT:
3162 return SPIRV::OpULessThan;
3163 default:
3164 llvm_unreachable("Unknown predicate type for ICmp");
3165 }
3166}
3167
3168static unsigned getPtrCmpOpcode(unsigned Pred) {
3169 switch (static_cast<CmpInst::Predicate>(Pred)) {
3170 case CmpInst::ICMP_EQ:
3171 return SPIRV::OpPtrEqual;
3172 case CmpInst::ICMP_NE:
3173 return SPIRV::OpPtrNotEqual;
3174 default:
3175 llvm_unreachable("Unknown predicate type for pointer comparison");
3176 }
3177}
3178
3179// Return the logical operation, or abort if none exists.
3180static unsigned getBoolCmpOpcode(unsigned PredNum) {
3181 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
3182 switch (Pred) {
3183 case CmpInst::ICMP_EQ:
3184 return SPIRV::OpLogicalEqual;
3185 case CmpInst::ICMP_NE:
3186 return SPIRV::OpLogicalNotEqual;
3187 default:
3188 llvm_unreachable("Unknown predicate type for Bool comparison");
3189 }
3190}
3191
3192static APFloat getZeroFP(const Type *LLVMFloatTy) {
3193 if (!LLVMFloatTy)
3194 return APFloat::getZero(Sem: APFloat::IEEEsingle());
3195 switch (LLVMFloatTy->getScalarType()->getTypeID()) {
3196 case Type::HalfTyID:
3197 return APFloat::getZero(Sem: APFloat::IEEEhalf());
3198 case Type::BFloatTyID:
3199 return APFloat::getZero(Sem: APFloat::BFloat());
3200 default:
3201 case Type::FloatTyID:
3202 return APFloat::getZero(Sem: APFloat::IEEEsingle());
3203 case Type::DoubleTyID:
3204 return APFloat::getZero(Sem: APFloat::IEEEdouble());
3205 }
3206}
3207
3208static APFloat getOneFP(const Type *LLVMFloatTy) {
3209 if (!LLVMFloatTy)
3210 return APFloat::getOne(Sem: APFloat::IEEEsingle());
3211 switch (LLVMFloatTy->getScalarType()->getTypeID()) {
3212 case Type::HalfTyID:
3213 return APFloat::getOne(Sem: APFloat::IEEEhalf());
3214 case Type::BFloatTyID:
3215 return APFloat::getOne(Sem: APFloat::BFloat());
3216 default:
3217 case Type::FloatTyID:
3218 return APFloat::getOne(Sem: APFloat::IEEEsingle());
3219 case Type::DoubleTyID:
3220 return APFloat::getOne(Sem: APFloat::IEEEdouble());
3221 }
3222}
3223
3224bool SPIRVInstructionSelector::selectAnyOrAll(Register ResVReg,
3225 SPIRVTypeInst ResType,
3226 MachineInstr &I,
3227 unsigned OpAnyOrAll) const {
3228 assert(I.getNumOperands() == 3);
3229 assert(I.getOperand(2).isReg());
3230 MachineBasicBlock &BB = *I.getParent();
3231 Register InputRegister = I.getOperand(i: 2).getReg();
3232 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(VReg: InputRegister);
3233
3234 assert(InputType && "VReg has no type assigned");
3235
3236 bool IsBoolTy = GR.isScalarOrVectorOfType(VReg: InputRegister, TypeOpcode: SPIRV::OpTypeBool);
3237 if (IsBoolTy && !isVectorType(SPVTy: InputType)) {
3238 assert(ResVReg == I.getOperand(0).getReg());
3239 return BuildCOPY(DestReg: ResVReg, SrcReg: InputRegister, I);
3240 }
3241
3242 bool IsFloatTy = GR.isScalarOrVectorOfType(VReg: InputRegister, TypeOpcode: SPIRV::OpTypeFloat);
3243 unsigned SpirvNotEqualId =
3244 IsFloatTy ? SPIRV::OpFOrdNotEqual : SPIRV::OpINotEqual;
3245 SPIRVTypeInst SpvBoolScalarTy = GR.getOrCreateSPIRVBoolType(I, TII);
3246 SPIRVTypeInst SpvBoolTy = SpvBoolScalarTy;
3247 Register NotEqualReg = ResVReg;
3248
3249 if (isVectorType(SPVTy: InputType)) {
3250 NotEqualReg =
3251 IsBoolTy ? InputRegister
3252 : createVirtualRegister(SpvType: SpvBoolTy, GR: &GR, MRI, MF: MRI->getMF());
3253 const unsigned NumElts = GR.getScalarOrVectorComponentCount(Type: InputType);
3254 SpvBoolTy = GR.getOrCreateSPIRVVectorType(BaseType: SpvBoolTy, NumElements: NumElts, I, TII);
3255 }
3256
3257 if (!IsBoolTy) {
3258 Register ConstZeroReg =
3259 IsFloatTy ? buildZerosValF(ResType: InputType, I) : buildZerosVal(ResType: InputType, I);
3260
3261 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SpirvNotEqualId))
3262 .addDef(RegNo: NotEqualReg)
3263 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: SpvBoolTy))
3264 .addUse(RegNo: InputRegister)
3265 .addUse(RegNo: ConstZeroReg)
3266 .constrainAllUses(TII, TRI, RBI);
3267 }
3268
3269 if (isVectorType(SPVTy: InputType))
3270 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: OpAnyOrAll))
3271 .addDef(RegNo: ResVReg)
3272 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: SpvBoolScalarTy))
3273 .addUse(RegNo: NotEqualReg)
3274 .constrainAllUses(TII, TRI, RBI);
3275 return true;
3276}
3277
3278bool SPIRVInstructionSelector::selectAll(Register ResVReg,
3279 SPIRVTypeInst ResType,
3280 MachineInstr &I) const {
3281 return selectAnyOrAll(ResVReg, ResType, I, OpAnyOrAll: SPIRV::OpAll);
3282}
3283
3284bool SPIRVInstructionSelector::selectAny(Register ResVReg,
3285 SPIRVTypeInst ResType,
3286 MachineInstr &I) const {
3287 return selectAnyOrAll(ResVReg, ResType, I, OpAnyOrAll: SPIRV::OpAny);
3288}
3289
3290// Select the OpDot instruction for the given float dot
3291bool SPIRVInstructionSelector::selectFloatDot(Register ResVReg,
3292 SPIRVTypeInst ResType,
3293 MachineInstr &I) const {
3294 assert(I.getNumOperands() == 4);
3295 assert(I.getOperand(2).isReg());
3296 assert(I.getOperand(3).isReg());
3297
3298 [[maybe_unused]] SPIRVTypeInst VecType =
3299 GR.getSPIRVTypeForVReg(VReg: I.getOperand(i: 2).getReg());
3300
3301 assert(((VecType->getOpcode() == SPIRV::OpTypeVector &&
3302 GR.getScalarOrVectorComponentCount(VecType) > 1) ||
3303 VecType->getOpcode() == SPIRV::OpTypeVectorIdEXT) &&
3304 "dot product requires either a vector of at least 2 components or"
3305 " the SPV_EXT_long vector extension.");
3306
3307 [[maybe_unused]] SPIRVTypeInst EltType =
3308 GR.getScalarOrVectorComponentType(Type: VecType);
3309
3310 assert(EltType->getOpcode() == SPIRV::OpTypeFloat);
3311
3312 MachineBasicBlock &BB = *I.getParent();
3313 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpDot))
3314 .addDef(RegNo: ResVReg)
3315 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3316 .addUse(RegNo: I.getOperand(i: 2).getReg())
3317 .addUse(RegNo: I.getOperand(i: 3).getReg())
3318 .constrainAllUses(TII, TRI, RBI);
3319 return true;
3320}
3321
3322bool SPIRVInstructionSelector::selectIntegerDot(Register ResVReg,
3323 SPIRVTypeInst ResType,
3324 MachineInstr &I,
3325 bool Signed) const {
3326 assert(I.getNumOperands() == 4);
3327 assert(I.getOperand(2).isReg());
3328 assert(I.getOperand(3).isReg());
3329 MachineBasicBlock &BB = *I.getParent();
3330
3331 auto DotOp = Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
3332 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: DotOp))
3333 .addDef(RegNo: ResVReg)
3334 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3335 .addUse(RegNo: I.getOperand(i: 2).getReg())
3336 .addUse(RegNo: I.getOperand(i: 3).getReg())
3337 .constrainAllUses(TII, TRI, RBI);
3338 return true;
3339}
3340
3341// Since pre-1.6 SPIRV has no integer dot implementation,
3342// expand by piecewise multiplying and adding the results
3343bool SPIRVInstructionSelector::selectIntegerDotExpansion(
3344 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3345 assert(I.getNumOperands() == 4);
3346 assert(I.getOperand(2).isReg());
3347 assert(I.getOperand(3).isReg());
3348 MachineBasicBlock &BB = *I.getParent();
3349
3350 // Multiply the vectors, then sum the results
3351 Register Vec0 = I.getOperand(i: 2).getReg();
3352 Register Vec1 = I.getOperand(i: 3).getReg();
3353 Register TmpVec = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
3354 SPIRVTypeInst VecType = GR.getSPIRVTypeForVReg(VReg: Vec0);
3355
3356 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpIMulV))
3357 .addDef(RegNo: TmpVec)
3358 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: VecType))
3359 .addUse(RegNo: Vec0)
3360 .addUse(RegNo: Vec1)
3361 .constrainAllUses(TII, TRI, RBI);
3362
3363 assert(((VecType->getOpcode() == SPIRV::OpTypeVector &&
3364 GR.getScalarOrVectorComponentCount(VecType) > 1) ||
3365 VecType->getOpcode() == SPIRV::OpTypeVectorIdEXT) &&
3366 "dot product requires either a vector of at least 2 components "
3367 "or the SPV_EXT_long_vector extension.");
3368
3369 Register Res = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
3370 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpCompositeExtract))
3371 .addDef(RegNo: Res)
3372 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3373 .addUse(RegNo: TmpVec)
3374 .addImm(Val: 0)
3375 .constrainAllUses(TII, TRI, RBI);
3376
3377 for (unsigned i = 1; i < GR.getScalarOrVectorComponentCount(Type: VecType); i++) {
3378 Register Elt = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
3379
3380 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpCompositeExtract))
3381 .addDef(RegNo: Elt)
3382 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3383 .addUse(RegNo: TmpVec)
3384 .addImm(Val: i)
3385 .constrainAllUses(TII, TRI, RBI);
3386
3387 Register Sum = i < GR.getScalarOrVectorComponentCount(Type: VecType) - 1
3388 ? MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType))
3389 : ResVReg;
3390
3391 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpIAddS))
3392 .addDef(RegNo: Sum)
3393 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3394 .addUse(RegNo: Res)
3395 .addUse(RegNo: Elt)
3396 .constrainAllUses(TII, TRI, RBI);
3397 Res = Sum;
3398 }
3399
3400 return true;
3401}
3402
3403bool SPIRVInstructionSelector::selectOpIsInf(Register ResVReg,
3404 SPIRVTypeInst ResType,
3405 MachineInstr &I) const {
3406 MachineBasicBlock &BB = *I.getParent();
3407 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpIsInf))
3408 .addDef(RegNo: ResVReg)
3409 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3410 .addUse(RegNo: I.getOperand(i: 2).getReg())
3411 .constrainAllUses(TII, TRI, RBI);
3412 return true;
3413}
3414
3415bool SPIRVInstructionSelector::selectOpIsNan(Register ResVReg,
3416 SPIRVTypeInst ResType,
3417 MachineInstr &I) const {
3418 MachineBasicBlock &BB = *I.getParent();
3419 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpIsNan))
3420 .addDef(RegNo: ResVReg)
3421 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3422 .addUse(RegNo: I.getOperand(i: 2).getReg())
3423 .constrainAllUses(TII, TRI, RBI);
3424 return true;
3425}
3426
3427bool SPIRVInstructionSelector::selectOpIsFinite(Register ResVReg,
3428 SPIRVTypeInst ResType,
3429 MachineInstr &I) const {
3430 // OpIsFinite requires Kernel capability; emulate with OpIsInf & OpIsNan
3431 MachineBasicBlock &BB = *I.getParent();
3432 Register Src = I.getOperand(i: 2).getReg();
3433 Register TypeID = GR.getSPIRVTypeID(SpirvType: ResType);
3434 const DebugLoc &DL = I.getDebugLoc();
3435
3436 if (!STI.isShader()) {
3437 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpIsFinite))
3438 .addDef(RegNo: ResVReg)
3439 .addUse(RegNo: TypeID)
3440 .addUse(RegNo: Src)
3441 .constrainAllUses(TII, TRI, RBI);
3442 return true;
3443 }
3444
3445 Register IsInfReg = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
3446 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpIsInf))
3447 .addDef(RegNo: IsInfReg)
3448 .addUse(RegNo: TypeID)
3449 .addUse(RegNo: Src)
3450 .constrainAllUses(TII, TRI, RBI);
3451
3452 Register IsNanReg = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
3453 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpIsNan))
3454 .addDef(RegNo: IsNanReg)
3455 .addUse(RegNo: TypeID)
3456 .addUse(RegNo: Src)
3457 .constrainAllUses(TII, TRI, RBI);
3458
3459 Register OrReg = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
3460 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpLogicalOr))
3461 .addDef(RegNo: OrReg)
3462 .addUse(RegNo: TypeID)
3463 .addUse(RegNo: IsInfReg)
3464 .addUse(RegNo: IsNanReg)
3465 .constrainAllUses(TII, TRI, RBI);
3466
3467 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpLogicalNot))
3468 .addDef(RegNo: ResVReg)
3469 .addUse(RegNo: TypeID)
3470 .addUse(RegNo: OrReg)
3471 .constrainAllUses(TII, TRI, RBI);
3472 return true;
3473}
3474
3475bool SPIRVInstructionSelector::selectOpIsNormal(Register ResVReg,
3476 SPIRVTypeInst ResType,
3477 MachineInstr &I) const {
3478 MachineBasicBlock &BB = *I.getParent();
3479 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpIsNormal))
3480 .addDef(RegNo: ResVReg)
3481 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3482 .addUse(RegNo: I.getOperand(i: 2).getReg())
3483 .constrainAllUses(TII, TRI, RBI);
3484 return true;
3485}
3486
3487template <bool Signed>
3488bool SPIRVInstructionSelector::selectDot4AddPacked(Register ResVReg,
3489 SPIRVTypeInst ResType,
3490 MachineInstr &I) const {
3491 assert(I.getNumOperands() == 5);
3492 assert(I.getOperand(2).isReg());
3493 assert(I.getOperand(3).isReg());
3494 assert(I.getOperand(4).isReg());
3495 MachineBasicBlock &BB = *I.getParent();
3496
3497 Register Acc = I.getOperand(i: 2).getReg();
3498 Register X = I.getOperand(i: 3).getReg();
3499 Register Y = I.getOperand(i: 4).getReg();
3500
3501 auto DotOp = Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
3502 Register Dot = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
3503 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: DotOp))
3504 .addDef(RegNo: Dot)
3505 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3506 .addUse(RegNo: X)
3507 .addUse(RegNo: Y);
3508 MIB.addImm(Val: SPIRV::BuiltIn::PackedVectorFormat4x8Bit);
3509 MIB.constrainAllUses(TII, TRI, RBI);
3510
3511 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpIAddS))
3512 .addDef(RegNo: ResVReg)
3513 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3514 .addUse(RegNo: Dot)
3515 .addUse(RegNo: Acc)
3516 .constrainAllUses(TII, TRI, RBI);
3517 return true;
3518}
3519
3520// Since pre-1.6 SPIRV has no DotProductInput4x8BitPacked implementation,
3521// extract the elements of the packed inputs, multiply them and add the result
3522// to the accumulator.
3523template <bool Signed>
3524bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
3525 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3526 assert(I.getNumOperands() == 5);
3527 assert(I.getOperand(2).isReg());
3528 assert(I.getOperand(3).isReg());
3529 assert(I.getOperand(4).isReg());
3530 MachineBasicBlock &BB = *I.getParent();
3531
3532 Register Acc = I.getOperand(i: 2).getReg();
3533 Register X = I.getOperand(i: 3).getReg();
3534 Register Y = I.getOperand(i: 4).getReg();
3535
3536 SPIRVTypeInst EltType = GR.getOrCreateSPIRVIntegerType(BitWidth: 8, I, TII);
3537 auto ExtractOp =
3538 Signed ? SPIRV::OpBitFieldSExtract : SPIRV::OpBitFieldUExtract;
3539
3540 bool ZeroAsNull = !STI.isShader();
3541 // Extract the i8 element, multiply and add it to the accumulator
3542 for (unsigned i = 0; i < 4; i++) {
3543 // A[i]
3544 Register AElt = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
3545 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: ExtractOp))
3546 .addDef(RegNo: AElt)
3547 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3548 .addUse(RegNo: X)
3549 .addUse(RegNo: GR.getOrCreateConstInt(Val: i * 8, I, SpvType: EltType, TII, ZeroAsNull))
3550 .addUse(RegNo: GR.getOrCreateConstInt(Val: 8, I, SpvType: EltType, TII, ZeroAsNull))
3551 .constrainAllUses(TII, TRI, RBI);
3552
3553 // B[i]
3554 Register BElt = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
3555 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: ExtractOp))
3556 .addDef(RegNo: BElt)
3557 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3558 .addUse(RegNo: Y)
3559 .addUse(RegNo: GR.getOrCreateConstInt(Val: i * 8, I, SpvType: EltType, TII, ZeroAsNull))
3560 .addUse(RegNo: GR.getOrCreateConstInt(Val: 8, I, SpvType: EltType, TII, ZeroAsNull))
3561 .constrainAllUses(TII, TRI, RBI);
3562
3563 // A[i] * B[i]
3564 Register Mul = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
3565 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpIMulS))
3566 .addDef(RegNo: Mul)
3567 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3568 .addUse(RegNo: AElt)
3569 .addUse(RegNo: BElt)
3570 .constrainAllUses(TII, TRI, RBI);
3571
3572 // Discard 24 highest-bits so that stored i32 register is i8 equivalent
3573 Register MaskMul = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
3574 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: ExtractOp))
3575 .addDef(RegNo: MaskMul)
3576 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3577 .addUse(RegNo: Mul)
3578 .addUse(RegNo: GR.getOrCreateConstInt(Val: 0, I, SpvType: EltType, TII, ZeroAsNull))
3579 .addUse(RegNo: GR.getOrCreateConstInt(Val: 8, I, SpvType: EltType, TII, ZeroAsNull))
3580 .constrainAllUses(TII, TRI, RBI);
3581
3582 // Acc = Acc + A[i] * B[i]
3583 Register Sum =
3584 i < 3 ? MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass) : ResVReg;
3585 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpIAddS))
3586 .addDef(RegNo: Sum)
3587 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3588 .addUse(RegNo: Acc)
3589 .addUse(RegNo: MaskMul)
3590 .constrainAllUses(TII, TRI, RBI);
3591
3592 Acc = Sum;
3593 }
3594
3595 return true;
3596}
3597
3598/// Transform saturate(x) to clamp(x, 0.0f, 1.0f) as SPIRV
3599/// does not have a saturate builtin.
3600bool SPIRVInstructionSelector::selectSaturate(Register ResVReg,
3601 SPIRVTypeInst ResType,
3602 MachineInstr &I) const {
3603 assert(I.getNumOperands() == 3);
3604 assert(I.getOperand(2).isReg());
3605 MachineBasicBlock &BB = *I.getParent();
3606 Register VZero = buildZerosValF(ResType, I);
3607 Register VOne = buildOnesValF(ResType, I);
3608
3609 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpExtInst))
3610 .addDef(RegNo: ResVReg)
3611 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3612 .addImm(Val: static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
3613 .addImm(Val: GL::FClamp)
3614 .addUse(RegNo: I.getOperand(i: 2).getReg())
3615 .addUse(RegNo: VZero)
3616 .addUse(RegNo: VOne)
3617 .constrainAllUses(TII, TRI, RBI);
3618 return true;
3619}
3620
3621bool SPIRVInstructionSelector::selectSign(Register ResVReg,
3622 SPIRVTypeInst ResType,
3623 MachineInstr &I) const {
3624 assert(I.getNumOperands() == 3);
3625 assert(I.getOperand(2).isReg());
3626 MachineBasicBlock &BB = *I.getParent();
3627 Register InputRegister = I.getOperand(i: 2).getReg();
3628 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(VReg: InputRegister);
3629 auto &DL = I.getDebugLoc();
3630
3631 if (!InputType)
3632 return diagnoseUnsupported(I, Msg: "Input Type could not be determined.");
3633
3634 bool IsFloatTy = GR.isScalarOrVectorOfType(VReg: InputRegister, TypeOpcode: SPIRV::OpTypeFloat);
3635
3636 unsigned SignBitWidth = GR.getScalarOrVectorBitWidth(Type: InputType);
3637 unsigned ResBitWidth = GR.getScalarOrVectorBitWidth(Type: ResType);
3638
3639 bool NeedsConversion = IsFloatTy || SignBitWidth != ResBitWidth;
3640
3641 auto SignOpcode = IsFloatTy ? GL::FSign : GL::SSign;
3642 Register SignReg = NeedsConversion
3643 ? MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass)
3644 : ResVReg;
3645
3646 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpExtInst))
3647 .addDef(RegNo: SignReg)
3648 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: InputType))
3649 .addImm(Val: static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
3650 .addImm(Val: SignOpcode)
3651 .addUse(RegNo: InputRegister)
3652 .constrainAllUses(TII, TRI, RBI);
3653
3654 if (NeedsConversion) {
3655 auto ConvertOpcode = IsFloatTy ? SPIRV::OpConvertFToS : SPIRV::OpSConvert;
3656 BuildMI(BB&: *I.getParent(), I, MIMD: DL, MCID: TII.get(Opcode: ConvertOpcode))
3657 .addDef(RegNo: ResVReg)
3658 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3659 .addUse(RegNo: SignReg)
3660 .constrainAllUses(TII, TRI, RBI);
3661 }
3662
3663 return true;
3664}
3665
3666bool SPIRVInstructionSelector::selectWaveOpInst(Register ResVReg,
3667 SPIRVTypeInst ResType,
3668 MachineInstr &I,
3669 unsigned Opcode) const {
3670 MachineBasicBlock &BB = *I.getParent();
3671 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
3672
3673 auto BMI = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
3674 .addDef(RegNo: ResVReg)
3675 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3676 .addUse(RegNo: GR.getOrCreateConstInt(Val: SPIRV::Scope::Subgroup, I,
3677 SpvType: IntTy, TII, ZeroAsNull: !STI.isShader()));
3678
3679 for (unsigned J = 2; J < I.getNumOperands(); J++) {
3680 BMI.addUse(RegNo: I.getOperand(i: J).getReg());
3681 }
3682
3683 BMI.constrainAllUses(TII, TRI, RBI);
3684 return true;
3685}
3686
3687bool SPIRVInstructionSelector::selectBarrierInst(MachineInstr &I,
3688 unsigned Scope,
3689 unsigned MemSem,
3690 bool WithGroupSync) const {
3691 auto BarrierType =
3692 WithGroupSync ? SPIRV::OpControlBarrier : SPIRV::OpMemoryBarrier;
3693
3694 MemSem |= SPIRV::MemorySemantics::AcquireRelease;
3695
3696 assert(((Scope != SPIRV::Scope::Workgroup) ||
3697 ((MemSem & SPIRV::MemorySemantics::WorkgroupMemory) > 0)) &&
3698 "Workgroup Scope must set WorkGroupMemory semantic "
3699 "in Barrier instruction");
3700
3701 assert(((Scope != SPIRV::Scope::Device) ||
3702 ((MemSem & SPIRV::MemorySemantics::UniformMemory) > 0 &&
3703 (MemSem & SPIRV::MemorySemantics::ImageMemory) > 0)) &&
3704 "Device Scope must set UniformMemory and ImageMemory semantic "
3705 "in Barrier instruction");
3706
3707 MachineBasicBlock &BB = *I.getParent();
3708 auto MI = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: BarrierType));
3709
3710 // OpControlBarrier needs to also set Execution Scope
3711 if (WithGroupSync) {
3712 Register ExecReg = buildI32Constant(Val: SPIRV::Scope::Workgroup, I);
3713 MI.addUse(RegNo: ExecReg);
3714 }
3715
3716 Register ScopeReg = buildI32Constant(Val: Scope, I);
3717 Register MemSemReg = buildI32Constant(Val: MemSem, I);
3718
3719 MI.addUse(RegNo: ScopeReg).addUse(RegNo: MemSemReg).constrainAllUses(TII, TRI, RBI);
3720 return true;
3721}
3722
3723bool SPIRVInstructionSelector::selectWaveActiveCountBits(
3724 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3725
3726 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
3727 SPIRVTypeInst BallotType = GR.getOrCreateSPIRVVectorType(BaseType: IntTy, NumElements: 4, I, TII);
3728 Register BallotReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: BallotType));
3729 if (!selectWaveOpInst(ResVReg: BallotReg, ResType: BallotType, I,
3730 Opcode: SPIRV::OpGroupNonUniformBallot))
3731 return false;
3732
3733 MachineBasicBlock &BB = *I.getParent();
3734 BuildMI(BB, I, MIMD: I.getDebugLoc(),
3735 MCID: TII.get(Opcode: SPIRV::OpGroupNonUniformBallotBitCount))
3736 .addDef(RegNo: ResVReg)
3737 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3738 .addUse(RegNo: GR.getOrCreateConstInt(Val: SPIRV::Scope::Subgroup, I, SpvType: IntTy, TII,
3739 ZeroAsNull: !STI.isShader()))
3740 .addImm(Val: SPIRV::GroupOperation::Reduce)
3741 .addUse(RegNo: BallotReg)
3742 .constrainAllUses(TII, TRI, RBI);
3743
3744 return true;
3745}
3746
3747bool SPIRVInstructionSelector::selectWaveActiveAllEqual(Register ResVReg,
3748 SPIRVTypeInst ResType,
3749 MachineInstr &I) const {
3750 MachineBasicBlock &BB = *I.getParent();
3751 const DebugLoc &DL = I.getDebugLoc();
3752
3753 // Input to the intrinsic
3754 Register InputReg = I.getOperand(i: 2).getReg();
3755 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(VReg: InputReg);
3756
3757 // Determine if input is vector
3758 unsigned NumElems = GR.getScalarOrVectorComponentCount(Type: InputType);
3759 bool IsVector = NumElems > 1 ||
3760 (InputType->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
3761 STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector));
3762
3763 // Determine element types
3764 SPIRVTypeInst ElemInputType = GR.getScalarOrVectorComponentType(Type: InputType);
3765 SPIRVTypeInst ElemBoolType = GR.getScalarOrVectorComponentType(Type: ResType);
3766
3767 // Subgroup scope constant
3768 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
3769 Register ScopeConst = GR.getOrCreateConstInt(Val: SPIRV::Scope::Subgroup, I, SpvType: IntTy,
3770 TII, ZeroAsNull: !STI.isShader());
3771
3772 // Scalar case
3773 if (!IsVector) {
3774 return selectWaveOpInst(ResVReg, ResType: ElemBoolType, I,
3775 Opcode: SPIRV::OpGroupNonUniformAllEqual);
3776 }
3777
3778 // Vector case
3779 SmallVector<Register, 4> ElementResults;
3780 ElementResults.reserve(N: NumElems);
3781
3782 for (unsigned Idx = 0; Idx < NumElems; ++Idx) {
3783 // Extract element
3784 Register ElemInput = InputReg;
3785 Register Extracted =
3786 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ElemInputType));
3787
3788 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpCompositeExtract))
3789 .addDef(RegNo: Extracted)
3790 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ElemInputType))
3791 .addUse(RegNo: InputReg)
3792 .addImm(Val: Idx)
3793 .constrainAllUses(TII, TRI, RBI);
3794
3795 ElemInput = Extracted;
3796
3797 // Emit per-element AllEqual
3798 Register ElemResult =
3799 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ElemBoolType));
3800
3801 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpGroupNonUniformAllEqual))
3802 .addDef(RegNo: ElemResult)
3803 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ElemBoolType))
3804 .addUse(RegNo: ScopeConst)
3805 .addUse(RegNo: ElemInput)
3806 .constrainAllUses(TII, TRI, RBI);
3807
3808 ElementResults.push_back(Elt: ElemResult);
3809 }
3810
3811 // Reconstruct vector<bool>
3812 auto MIB = BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpCompositeConstruct))
3813 .addDef(RegNo: ResVReg)
3814 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
3815 for (Register R : ElementResults)
3816 MIB.addUse(RegNo: R);
3817
3818 MIB.constrainAllUses(TII, TRI, RBI);
3819
3820 return true;
3821}
3822
3823bool SPIRVInstructionSelector::selectWavePrefixBitCount(Register ResVReg,
3824 SPIRVTypeInst ResType,
3825 MachineInstr &I) const {
3826
3827 assert(I.getNumOperands() == 3);
3828
3829 auto Op = I.getOperand(i: 2);
3830 assert(Op.isReg());
3831
3832 MachineBasicBlock &BB = *I.getParent();
3833 DebugLoc DL = I.getDebugLoc();
3834
3835 Register InputRegister = Op.getReg();
3836 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(VReg: InputRegister);
3837
3838 if (!InputType)
3839 return diagnoseUnsupported(I, Msg: "Input Type could not be determined.");
3840
3841 if (InputType->getOpcode() != SPIRV::OpTypeBool)
3842 return diagnoseUnsupported(I, Msg: "WavePrefixBitCount requires boolean input");
3843
3844 // Types
3845 SPIRVTypeInst Int32Ty = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
3846
3847 // Ballot result type: vector<uint32>
3848 // Match DXC: %v4uint for Subgroup size
3849 SPIRVTypeInst BallotTy = GR.getOrCreateSPIRVVectorType(BaseType: Int32Ty, NumElements: 4, I, TII);
3850
3851 // Create a vreg for the ballot result
3852 Register BallotVReg = MRI->createVirtualRegister(RegClass: &SPIRV::IDRegClass);
3853
3854 // 1. OpGroupNonUniformBallot
3855 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpGroupNonUniformBallot))
3856 .addDef(RegNo: BallotVReg)
3857 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: BallotTy))
3858 .addUse(RegNo: GR.getOrCreateConstInt(Val: SPIRV::Scope::Subgroup, I, SpvType: Int32Ty, TII))
3859 .addUse(RegNo: InputRegister)
3860 .constrainAllUses(TII, TRI, RBI);
3861
3862 // 2. OpGroupNonUniformBallotBitCount
3863 BuildMI(BB, I, MIMD: DL, MCID: TII.get(Opcode: SPIRV::OpGroupNonUniformBallotBitCount))
3864 .addDef(RegNo: ResVReg)
3865 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3866 .addUse(RegNo: GR.getOrCreateConstInt(Val: SPIRV::Scope::Subgroup, I, SpvType: Int32Ty, TII))
3867 .addImm(Val: SPIRV::GroupOperation::ExclusiveScan)
3868 .addUse(RegNo: BallotVReg)
3869 .constrainAllUses(TII, TRI, RBI);
3870
3871 return true;
3872}
3873
3874bool SPIRVInstructionSelector::selectWaveReduceMax(Register ResVReg,
3875 SPIRVTypeInst ResType,
3876 MachineInstr &I,
3877 bool IsUnsigned) const {
3878 return selectWaveReduce(
3879 ResVReg, ResType, I, IsUnsigned,
3880 PickOpcode: [&](Register InputRegister, bool IsUnsigned) {
3881 const bool IsFloatTy =
3882 GR.isScalarOrVectorOfType(VReg: InputRegister, TypeOpcode: SPIRV::OpTypeFloat);
3883 const auto IntOp = IsUnsigned ? SPIRV::OpGroupNonUniformUMax
3884 : SPIRV::OpGroupNonUniformSMax;
3885 return IsFloatTy ? SPIRV::OpGroupNonUniformFMax : IntOp;
3886 });
3887}
3888
3889bool SPIRVInstructionSelector::selectWaveReduceMin(Register ResVReg,
3890 SPIRVTypeInst ResType,
3891 MachineInstr &I,
3892 bool IsUnsigned) const {
3893 return selectWaveReduce(
3894 ResVReg, ResType, I, IsUnsigned,
3895 PickOpcode: [&](Register InputRegister, bool IsUnsigned) {
3896 const bool IsFloatTy =
3897 GR.isScalarOrVectorOfType(VReg: InputRegister, TypeOpcode: SPIRV::OpTypeFloat);
3898 const auto IntOp = IsUnsigned ? SPIRV::OpGroupNonUniformUMin
3899 : SPIRV::OpGroupNonUniformSMin;
3900 return IsFloatTy ? SPIRV::OpGroupNonUniformFMin : IntOp;
3901 });
3902}
3903
3904bool SPIRVInstructionSelector::selectWaveReduceSum(Register ResVReg,
3905 SPIRVTypeInst ResType,
3906 MachineInstr &I) const {
3907 return selectWaveReduce(ResVReg, ResType, I, /*IsUnsigned*/ false,
3908 PickOpcode: [&](Register InputRegister, bool IsUnsigned) {
3909 bool IsFloatTy = GR.isScalarOrVectorOfType(
3910 VReg: InputRegister, TypeOpcode: SPIRV::OpTypeFloat);
3911 return IsFloatTy ? SPIRV::OpGroupNonUniformFAdd
3912 : SPIRV::OpGroupNonUniformIAdd;
3913 });
3914}
3915
3916bool SPIRVInstructionSelector::selectWaveReduceProduct(Register ResVReg,
3917 SPIRVTypeInst ResType,
3918 MachineInstr &I) const {
3919 return selectWaveReduce(ResVReg, ResType, I, /*IsUnsigned*/ false,
3920 PickOpcode: [&](Register InputRegister, bool IsUnsigned) {
3921 bool IsFloatTy = GR.isScalarOrVectorOfType(
3922 VReg: InputRegister, TypeOpcode: SPIRV::OpTypeFloat);
3923 return IsFloatTy ? SPIRV::OpGroupNonUniformFMul
3924 : SPIRV::OpGroupNonUniformIMul;
3925 });
3926}
3927
3928template <typename PickOpcodeFn>
3929bool SPIRVInstructionSelector::selectWaveReduce(
3930 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, bool IsUnsigned,
3931 PickOpcodeFn &&PickOpcode) const {
3932 assert(I.getNumOperands() == 3);
3933 assert(I.getOperand(2).isReg());
3934 MachineBasicBlock &BB = *I.getParent();
3935 Register InputRegister = I.getOperand(i: 2).getReg();
3936 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(VReg: InputRegister);
3937
3938 if (!InputType)
3939 return diagnoseUnsupported(I, Msg: "Input Type could not be determined.");
3940
3941 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
3942 const unsigned Opcode = PickOpcode(InputRegister, IsUnsigned);
3943 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
3944 .addDef(RegNo: ResVReg)
3945 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
3946 .addUse(RegNo: GR.getOrCreateConstInt(Val: SPIRV::Scope::Subgroup, I, SpvType: IntTy, TII,
3947 ZeroAsNull: !STI.isShader()))
3948 .addImm(Val: SPIRV::GroupOperation::Reduce)
3949 .addUse(RegNo: I.getOperand(i: 2).getReg())
3950 .constrainAllUses(TII, TRI, RBI);
3951 return true;
3952}
3953
3954bool SPIRVInstructionSelector::selectWaveReduceOp(Register ResVReg,
3955 SPIRVTypeInst ResType,
3956 MachineInstr &I,
3957 unsigned Opcode) const {
3958 return selectWaveReduce(
3959 ResVReg, ResType, I, IsUnsigned: false,
3960 PickOpcode: [&](Register InputRegister, bool IsUnsigned) { return Opcode; });
3961}
3962
3963bool SPIRVInstructionSelector::selectWaveExclusiveScanSum(
3964 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3965 return selectWaveExclusiveScan(ResVReg, ResType, I, /*IsUnsigned*/ false,
3966 PickOpcode: [&](Register InputRegister, bool IsUnsigned) {
3967 bool IsFloatTy = GR.isScalarOrVectorOfType(
3968 VReg: InputRegister, TypeOpcode: SPIRV::OpTypeFloat);
3969 return IsFloatTy
3970 ? SPIRV::OpGroupNonUniformFAdd
3971 : SPIRV::OpGroupNonUniformIAdd;
3972 });
3973}
3974
3975bool SPIRVInstructionSelector::selectWaveExclusiveScanProduct(
3976 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3977 return selectWaveExclusiveScan(ResVReg, ResType, I, /*IsUnsigned*/ false,
3978 PickOpcode: [&](Register InputRegister, bool IsUnsigned) {
3979 bool IsFloatTy = GR.isScalarOrVectorOfType(
3980 VReg: InputRegister, TypeOpcode: SPIRV::OpTypeFloat);
3981 return IsFloatTy
3982 ? SPIRV::OpGroupNonUniformFMul
3983 : SPIRV::OpGroupNonUniformIMul;
3984 });
3985}
3986
3987template <typename PickOpcodeFn>
3988bool SPIRVInstructionSelector::selectWaveExclusiveScan(
3989 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, bool IsUnsigned,
3990 PickOpcodeFn &&PickOpcode) const {
3991 assert(I.getNumOperands() == 3);
3992 assert(I.getOperand(2).isReg());
3993 MachineBasicBlock &BB = *I.getParent();
3994 Register InputRegister = I.getOperand(i: 2).getReg();
3995 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(VReg: InputRegister);
3996
3997 if (!InputType)
3998 return diagnoseUnsupported(I, Msg: "Input Type could not be determined.");
3999
4000 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
4001 const unsigned Opcode = PickOpcode(InputRegister, IsUnsigned);
4002 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
4003 .addDef(RegNo: ResVReg)
4004 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
4005 .addUse(RegNo: GR.getOrCreateConstInt(Val: SPIRV::Scope::Subgroup, I, SpvType: IntTy, TII,
4006 ZeroAsNull: !STI.isShader()))
4007 .addImm(Val: SPIRV::GroupOperation::ExclusiveScan)
4008 .addUse(RegNo: I.getOperand(i: 2).getReg())
4009 .constrainAllUses(TII, TRI, RBI);
4010 return true;
4011}
4012
4013bool SPIRVInstructionSelector::selectQuadSwap(Register ResVReg,
4014 SPIRVTypeInst ResType,
4015 MachineInstr &I,
4016 unsigned Direction) const {
4017 assert(I.getNumOperands() == 3);
4018 assert(I.getOperand(2).isReg());
4019 MachineBasicBlock &BB = *I.getParent();
4020 Register InputRegister = I.getOperand(i: 2).getReg();
4021
4022 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
4023 bool ZeroAsNull = !STI.isShader();
4024 Register DirectionReg =
4025 GR.getOrCreateConstInt(Val: Direction, I, SpvType: IntTy, TII, ZeroAsNull);
4026 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpGroupNonUniformQuadSwap))
4027 .addDef(RegNo: ResVReg)
4028 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
4029 .addUse(RegNo: GR.getOrCreateConstInt(Val: SPIRV::Scope::Subgroup, I, SpvType: IntTy, TII,
4030 ZeroAsNull))
4031 .addUse(RegNo: InputRegister)
4032 .addUse(RegNo: DirectionReg)
4033 .constrainAllUses(TII, TRI, RBI);
4034 return true;
4035}
4036
4037bool SPIRVInstructionSelector::selectBitreverseViaI32(Register ResVReg,
4038 SPIRVTypeInst ResType,
4039 MachineInstr &I,
4040 Register Op) const {
4041 SPIRVTypeInst Int32Type = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
4042 const unsigned BitWidth = GR.getScalarOrVectorBitWidth(Type: ResType);
4043 Register ShiftConst =
4044 GR.getOrCreateConstInt(Val: 32 - BitWidth, I, SpvType: Int32Type, TII);
4045 unsigned ShiftOp = SPIRV::OpShiftRightLogicalS;
4046
4047 const unsigned N = GR.getScalarOrVectorComponentCount(Type: ResType);
4048 const unsigned ExtendOpcode = GR.isScalarOrVectorSigned(Type: ResType)
4049 ? SPIRV::OpSConvert
4050 : SPIRV::OpUConvert;
4051
4052 if (N > 1 || (ResType->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
4053 STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector))) {
4054 Int32Type = GR.getOrCreateSPIRVVectorType(BaseType: Int32Type, NumElements: N, I, TII);
4055 ShiftOp = SPIRV::OpShiftRightLogicalV;
4056
4057 // Vector shifts require a composite constant
4058 const Register CompositeReg =
4059 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: Int32Type));
4060 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
4061 MCID: TII.get(Opcode: SPIRV::OpConstantComposite))
4062 .addDef(RegNo: CompositeReg)
4063 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: Int32Type));
4064 for (unsigned It = 0; It < N; ++It)
4065 MIB.addUse(RegNo: ShiftConst);
4066 MIB.constrainAllUses(TII, TRI, RBI);
4067
4068 ShiftConst = CompositeReg;
4069 }
4070
4071 // Converts the input to i32 (or vector of i32)
4072 Register ExtReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: Int32Type));
4073 if (!selectOpWithSrcs(ResVReg: ExtReg, ResType: Int32Type, I, Srcs: {Op}, Opcode: ExtendOpcode))
4074 return false;
4075
4076 // Perform bitreverse on the i32 value
4077 Register BitrevReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: Int32Type));
4078 if (!selectBitreverseNative(ResVReg: BitrevReg, ResType: Int32Type, I, Op: ExtReg))
4079 return false;
4080
4081 // Shift the bit-reversed value to get the final result.
4082 Register ShiftReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: Int32Type));
4083 if (!selectOpWithSrcs(ResVReg: ShiftReg, ResType: Int32Type, I, Srcs: {BitrevReg, ShiftConst},
4084 Opcode: ShiftOp))
4085 return false;
4086
4087 // Finally, convert the result back.
4088 return selectOpWithSrcs(ResVReg, ResType, I, Srcs: {ShiftReg}, Opcode: ExtendOpcode);
4089}
4090
4091bool SPIRVInstructionSelector::handle64BitOverflow(
4092 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
4093 unsigned int Opcode,
4094 std::function<bool(Register, SPIRVTypeInst, MachineInstr &, Register,
4095 unsigned)>
4096 CallbackFunction) const {
4097
4098 SPIRVTypeInst BaseType = GR.retrieveScalarOrVectorIntType(Type: ResType);
4099 assert(BaseType->getOpcode() == SPIRV::OpTypeInt &&
4100 "handle64BitOverflow should only be used for integer types");
4101 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(Type: ResType);
4102 assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops");
4103
4104 MachineIRBuilder MIRBuilder(I);
4105 SPIRVTypeInst I64Type = GR.getOrCreateSPIRVIntegerType(BitWidth: 64, MIRBuilder);
4106 SPIRVTypeInst I64x2Type =
4107 GR.getOrCreateSPIRVVectorType(BaseType: I64Type, NumElements: 2, MIRBuilder, EmitIR: false);
4108 SPIRVTypeInst Vec2ResType =
4109 GR.getOrCreateSPIRVVectorType(BaseType, NumElements: 2, MIRBuilder, EmitIR: false);
4110
4111 std::vector<Register> PartialRegs;
4112
4113 unsigned CurrentComponent = 0;
4114 for (; CurrentComponent + 1 < ComponentCount; CurrentComponent += 2) {
4115 Register PopCountResult =
4116 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: I64x2Type));
4117
4118 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
4119 MCID: TII.get(Opcode: SPIRV::OpVectorShuffle))
4120 .addDef(RegNo: PopCountResult)
4121 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: I64x2Type))
4122 .addUse(RegNo: SrcReg)
4123 .addUse(RegNo: SrcReg)
4124 .addImm(Val: CurrentComponent)
4125 .addImm(Val: CurrentComponent + 1);
4126
4127 MIB.constrainAllUses(TII, TRI, RBI);
4128
4129 Register SubVecReg =
4130 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: Vec2ResType));
4131
4132 if (!CallbackFunction(SubVecReg, Vec2ResType, I, PopCountResult, Opcode))
4133 return false;
4134
4135 PartialRegs.push_back(x: SubVecReg);
4136 }
4137 // On odd component counts we need to handle one more component
4138 if (CurrentComponent != ComponentCount) {
4139 bool ZeroAsNull = !STI.isShader();
4140 Register FinalElemReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: I64Type));
4141 Register ConstIntLastIdx = GR.getOrCreateConstInt(
4142 Val: ComponentCount - 1, I, SpvType: BaseType, TII, ZeroAsNull);
4143
4144 if (!selectOpWithSrcs(ResVReg: FinalElemReg, ResType: I64Type, I, Srcs: {SrcReg, ConstIntLastIdx},
4145 Opcode: SPIRV::OpVectorExtractDynamic))
4146 return false;
4147
4148 Register FinalElemResReg =
4149 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: BaseType));
4150
4151 if (!CallbackFunction(FinalElemResReg, BaseType, I, FinalElemReg, Opcode))
4152 return false;
4153
4154 PartialRegs.push_back(x: FinalElemResReg);
4155 }
4156 // Join all the resulting registers back into the return type in order
4157 // (ie i32x2, i32x2, i32x1 -> i32x5)
4158 return selectOpWithSrcs(ResVReg, ResType, I, Srcs: PartialRegs,
4159 Opcode: SPIRV::OpCompositeConstruct);
4160}
4161
4162bool SPIRVInstructionSelector::selectBitreverse64(Register ResVReg,
4163 SPIRVTypeInst ResType,
4164 MachineInstr &I,
4165 Register SrcReg) const {
4166 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(Type: ResType);
4167 if (ComponentCount > 2)
4168 return handle64BitOverflow(
4169 ResVReg, ResType, I, SrcReg, Opcode: SPIRV::OpBitReverse,
4170 CallbackFunction: [this](Register R, SPIRVTypeInst T, MachineInstr &I, Register S,
4171 unsigned O) { return this->selectBitreverse64(ResVReg: R, ResType: T, I, SrcReg: S); });
4172
4173 MachineIRBuilder MIRBuilder(I);
4174
4175 SPIRVTypeInst I32Type = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, MIRBuilder);
4176 SPIRVTypeInst VecI32Type = GR.getOrCreateSPIRVVectorType(
4177 BaseType: I32Type, NumElements: 2 * ComponentCount, MIRBuilder, /*IsSigned=*/EmitIR: false);
4178
4179 // Converts 64 bit into and array of 32 bit, containing 2 elements.
4180 Register Vec32 = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: VecI32Type));
4181 if (!selectOpWithSrcs(ResVReg: Vec32, ResType: VecI32Type, I, Srcs: {SrcReg}, Opcode: SPIRV::OpBitcast))
4182 return false;
4183
4184 // Apply bitreverse on each 32 bit lane
4185 Register Reverse32 = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: VecI32Type));
4186 if (!selectBitreverseNative(ResVReg: Reverse32, ResType: VecI32Type, I, Op: Vec32))
4187 return false;
4188
4189 // Reversing a 64-bit value = reverse each 32-bit half AND swap them,
4190 // so the old High word becomes lane 0 (low) and old Low becomes lane 1
4191 // (high).
4192 Register SwappedVec = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: VecI32Type));
4193 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
4194 MCID: TII.get(Opcode: SPIRV::OpVectorShuffle))
4195 .addDef(RegNo: SwappedVec)
4196 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: VecI32Type))
4197 .addUse(RegNo: Reverse32)
4198 .addUse(RegNo: Reverse32);
4199 for (unsigned J = 0; J < ComponentCount; ++J) {
4200 MIB.addImm(Val: 2 * J + 1);
4201 MIB.addImm(Val: 2 * J);
4202 }
4203 MIB.constrainAllUses(TII, TRI, RBI);
4204
4205 // Groups 32 bit vector back to 64 bit scalar.
4206 return selectOpWithSrcs(ResVReg, ResType, I, Srcs: {SwappedVec}, Opcode: SPIRV::OpBitcast);
4207}
4208
4209bool SPIRVInstructionSelector::selectBitreverseNative(Register ResVReg,
4210 SPIRVTypeInst ResType,
4211 MachineInstr &I,
4212 Register Op) const {
4213 MachineBasicBlock &BB = *I.getParent();
4214 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpBitReverse))
4215 .addDef(RegNo: ResVReg)
4216 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
4217 .addUse(RegNo: Op)
4218 .constrainAllUses(TII, TRI, RBI);
4219 return true;
4220}
4221
4222bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
4223 SPIRVTypeInst ResType,
4224 MachineInstr &I) const {
4225 Register OpReg = I.getOperand(i: 1).getReg();
4226
4227 // TODO: Fix shader behavior in case of VK_KHR_maintenance9 extension is set
4228 if (STI.isShader()) {
4229 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(VReg: OpReg);
4230 switch (GR.getScalarOrVectorBitWidth(Type: OpType)) {
4231 case 8:
4232 case 16:
4233 case 24:
4234 return selectBitreverseViaI32(ResVReg, ResType, I, Op: OpReg);
4235 case 32:
4236 return selectBitreverseNative(ResVReg, ResType, I, Op: OpReg);
4237 case 64:
4238 return selectBitreverse64(ResVReg, ResType, I, SrcReg: OpReg);
4239 }
4240 return SPIRVInstructionSelector::diagnoseUnsupported(
4241 I, Msg: "G_BITREVERSE only support 16,32,64 bits.");
4242 }
4243
4244 if (STI.canUseExtension(E: SPIRV::Extension::SPV_KHR_bit_instructions))
4245 return selectBitreverseNative(ResVReg, ResType, I, Op: OpReg);
4246
4247 // Expansion bitreverse using bit manipulation operations
4248 // Algo: https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel
4249 const unsigned BitWidth = GR.getScalarOrVectorBitWidth(Type: ResType);
4250 // TODO: add support for any bit width and bitwidth more than 64.
4251 if (BitWidth > 64 || !isPowerOf2_32(Value: BitWidth))
4252 return false;
4253
4254 const unsigned N = GR.getScalarOrVectorComponentCount(Type: ResType);
4255
4256 unsigned AndOp = SPIRV::OpBitwiseAndS;
4257 unsigned OrOp = SPIRV::OpBitwiseOrS;
4258 unsigned ShlOp = SPIRV::OpShiftLeftLogicalS;
4259 unsigned ShrOp = SPIRV::OpShiftRightLogicalS;
4260 if (N > 1 || (ResType->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
4261 STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector))) {
4262 AndOp = SPIRV::OpBitwiseAndV;
4263 OrOp = SPIRV::OpBitwiseOrV;
4264 ShlOp = SPIRV::OpShiftLeftLogicalV;
4265 ShrOp = SPIRV::OpShiftRightLogicalV;
4266 }
4267
4268 // Helper, one swap per step: ((input>>shift)&mask)|((input&mask)<<shift),
4269 // RPN: input shift >> mask & input mask & shift << |
4270 auto SwapBits = [&](const Register Input, const uint64_t Mask,
4271 const unsigned Shift) -> Register {
4272 auto CreateConst = [&](const uint64_t Value) -> Register {
4273 if (N == 1 &&
4274 (ResType->getOpcode() != SPIRV::OpTypeVectorIdEXT ||
4275 !STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector)))
4276 return GR.getOrCreateConstInt(
4277 Val: Value, I, SpvType: GR.retrieveScalarOrVectorIntType(Type: ResType), TII);
4278 return GR.getOrCreateConstVector(Val: Value, I, SpvType: ResType, TII);
4279 };
4280
4281 Register MaskReg = CreateConst(Mask);
4282 Register ShiftReg = CreateConst(Shift);
4283 Register T1 = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
4284 Register T2 = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
4285 Register T3 = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
4286 Register T4 = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
4287 Register Result = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
4288
4289 if (!selectOpWithSrcs(ResVReg: T1, ResType, I, Srcs: {Input, ShiftReg}, Opcode: ShrOp) ||
4290 !selectOpWithSrcs(ResVReg: T2, ResType, I, Srcs: {T1, MaskReg}, Opcode: AndOp) ||
4291 !selectOpWithSrcs(ResVReg: T3, ResType, I, Srcs: {Input, MaskReg}, Opcode: AndOp) ||
4292 !selectOpWithSrcs(ResVReg: T4, ResType, I, Srcs: {T3, ShiftReg}, Opcode: ShlOp) ||
4293 !selectOpWithSrcs(ResVReg: Result, ResType, I, Srcs: {T2, T4}, Opcode: OrOp))
4294 return Register();
4295
4296 return Result;
4297 };
4298
4299 unsigned Shift = BitWidth;
4300 Register Result = OpReg;
4301 uint64_t Mask = ~0ull;
4302 while ((Shift >>= 1) > 0) {
4303 Mask ^= (Mask << Shift);
4304 Result = SwapBits(Result, Mask, Shift);
4305 if (!Result.isValid())
4306 return false;
4307 }
4308
4309 return BuildCOPY(DestReg: ResVReg, SrcReg: Result, I);
4310}
4311
4312bool SPIRVInstructionSelector::selectFreeze(Register ResVReg,
4313 SPIRVTypeInst ResType,
4314 MachineInstr &I) const {
4315 assert(I.getOperand(0).isReg() && I.getOperand(1).isReg() &&
4316 "G_FREEZE must define and use a register");
4317 Register OpReg = I.getOperand(i: 1).getReg();
4318
4319 // With SPV_KHR_poison_freeze, lower `freeze` to OpFreezeKHR.
4320 if (STI.canUseExtension(E: SPIRV::Extension::SPV_KHR_poison_freeze)) {
4321 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpFreezeKHR))
4322 .addDef(RegNo: ResVReg)
4323 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
4324 .addUse(RegNo: OpReg)
4325 .constrainAllUses(TII, TRI, RBI);
4326 return true;
4327 }
4328
4329 // There is no way to implement `freeze` correctly without support on SPIR-V
4330 // standard side, but we may at least address a simple (static) case when
4331 // undef/poison value presence is obvious. The main benefit of even
4332 // incomplete `freeze` support is preventing of translation from crashing due
4333 // to lack of support on legalization and instruction selection steps.
4334 if (MachineInstr *Def = MRI->getVRegDef(Reg: OpReg)) {
4335 if (Def->getOpcode() == TargetOpcode::COPY)
4336 Def = MRI->getVRegDef(Reg: Def->getOperand(i: 1).getReg());
4337 Register Reg;
4338 switch (Def->getOpcode()) {
4339 case SPIRV::ASSIGN_TYPE:
4340 if (MachineInstr *AssignToDef =
4341 MRI->getVRegDef(Reg: Def->getOperand(i: 1).getReg())) {
4342 if (AssignToDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
4343 Reg = Def->getOperand(i: 2).getReg();
4344 }
4345 break;
4346 case SPIRV::OpUndef:
4347 Reg = Def->getOperand(i: 1).getReg();
4348 break;
4349 }
4350 unsigned DestOpCode;
4351 if (Reg.isValid()) {
4352 DestOpCode = SPIRV::OpConstantNull;
4353 LLVM_DEBUG(dbgs() << "SPV_KHR_poison_freeze is not enabled. freeze of a "
4354 "static undef/poison lowered to OpConstantNull\n");
4355 } else {
4356 DestOpCode = TargetOpcode::COPY;
4357 Reg = OpReg;
4358 LLVM_DEBUG(dbgs() << "SPV_KHR_poison_freeze is not enabled. freeze "
4359 "skipped, lowered as a copy of the operand\n");
4360 }
4361 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: DestOpCode))
4362 .addDef(RegNo: I.getOperand(i: 0).getReg())
4363 .addUse(RegNo: Reg)
4364 .constrainAllUses(TII, TRI, RBI);
4365 return true;
4366 }
4367 return false;
4368}
4369
4370bool SPIRVInstructionSelector::selectBuildVector(Register ResVReg,
4371 SPIRVTypeInst ResType,
4372 MachineInstr &I) const {
4373 unsigned N = 0;
4374 if (isVectorType(SPVTy: ResType))
4375 N = GR.getScalarOrVectorComponentCount(Type: ResType);
4376 else if (ResType->getOpcode() == SPIRV::OpTypeArray)
4377 N = getArrayComponentCount(MRI, ResType);
4378 else
4379 report_fatal_error(reason: "Cannot select G_BUILD_VECTOR with a non-vector result");
4380 if (I.getNumExplicitOperands() - I.getNumExplicitDefs() != N)
4381 report_fatal_error(reason: "G_BUILD_VECTOR and the result type are inconsistent");
4382
4383 // check if we may construct a constant vector
4384 bool IsConst = true;
4385 for (unsigned i = I.getNumExplicitDefs();
4386 i < I.getNumExplicitOperands() && IsConst; ++i)
4387 if (!isConstReg(MRI, OpReg: I.getOperand(i).getReg()))
4388 IsConst = false;
4389
4390 if (!IsConst && (N < 2 && ResType->getOpcode() != SPIRV::OpTypeVectorIdEXT))
4391 return diagnoseUnsupported(
4392 I, Msg: "There must be at least two constituent operands in a vector");
4393
4394 MRI->setRegClass(Reg: ResVReg, RC: GR.getRegClass(SpvType: ResType));
4395
4396 bool IsNullVector = IsConst && !STI.isShader();
4397 for (unsigned i = I.getNumExplicitDefs();
4398 i < I.getNumExplicitOperands() && IsNullVector; ++i) {
4399 MachineInstr *Def = getDef(MO: I.getOperand(i), MRI);
4400 IsNullVector = Def && isNullOrNullSplat(MI: *Def, MRI: *MRI);
4401 }
4402
4403 if (IsNullVector) {
4404 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpConstantNull))
4405 .addDef(RegNo: ResVReg)
4406 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
4407 .constrainAllUses(TII, TRI, RBI);
4408 return true;
4409 }
4410
4411 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
4412 MCID: TII.get(Opcode: IsConst ? SPIRV::OpConstantComposite
4413 : SPIRV::OpCompositeConstruct))
4414 .addDef(RegNo: ResVReg)
4415 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
4416 for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i)
4417 MIB.addUse(RegNo: I.getOperand(i).getReg());
4418 MIB.constrainAllUses(TII, TRI, RBI);
4419 return true;
4420}
4421
4422bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg,
4423 SPIRVTypeInst ResType,
4424 MachineInstr &I) const {
4425 unsigned N = 0;
4426 if (isVectorType(SPVTy: ResType))
4427 N = GR.getScalarOrVectorComponentCount(Type: ResType);
4428 else if (ResType->getOpcode() == SPIRV::OpTypeArray)
4429 N = getArrayComponentCount(MRI, ResType);
4430 else
4431 report_fatal_error(reason: "Cannot select G_SPLAT_VECTOR with a non-vector result");
4432
4433 unsigned OpIdx = I.getNumExplicitDefs();
4434 if (!I.getOperand(i: OpIdx).isReg())
4435 report_fatal_error(reason: "Unexpected argument in G_SPLAT_VECTOR");
4436
4437 // check if we may construct a constant vector
4438 Register OpReg = I.getOperand(i: OpIdx).getReg();
4439 bool IsConst = isConstReg(MRI, OpReg);
4440
4441 if (!IsConst && (N < 2 && ResType->getOpcode() != SPIRV::OpTypeVectorIdEXT))
4442 return diagnoseUnsupported(
4443 I, Msg: "There must be at least two constituent operands in a vector");
4444
4445 MRI->setRegClass(Reg: ResVReg, RC: GR.getRegClass(SpvType: ResType));
4446 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
4447 MCID: TII.get(Opcode: IsConst ? SPIRV::OpConstantComposite
4448 : SPIRV::OpCompositeConstruct))
4449 .addDef(RegNo: ResVReg)
4450 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
4451 for (unsigned i = 0; i < N; ++i)
4452 MIB.addUse(RegNo: OpReg);
4453 MIB.constrainAllUses(TII, TRI, RBI);
4454 return true;
4455}
4456
4457bool SPIRVInstructionSelector::selectConcatVectors(Register ResVReg,
4458 SPIRVTypeInst ResType,
4459 MachineInstr &I) const {
4460 // Implement G_CONCAT_VECTORS using OpCompositeConstruct, which allows vector
4461 // constituents that share the result's component type to be
4462 // concatenated in operand order.
4463 if (!isVectorType(SPVTy: ResType))
4464 report_fatal_error(
4465 reason: "Cannot select G_CONCAT_VECTORS with a non-vector result");
4466
4467 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
4468 MCID: TII.get(Opcode: SPIRV::OpCompositeConstruct))
4469 .addDef(RegNo: ResVReg)
4470 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
4471 for (unsigned OpIdx = I.getNumExplicitDefs();
4472 OpIdx < I.getNumExplicitOperands(); ++OpIdx)
4473 MIB.addUse(RegNo: I.getOperand(i: OpIdx).getReg());
4474 MIB.constrainAllUses(TII, TRI, RBI);
4475 return true;
4476}
4477
4478bool SPIRVInstructionSelector::selectDiscard(Register ResVReg,
4479 SPIRVTypeInst ResType,
4480 MachineInstr &I) const {
4481
4482 unsigned Opcode;
4483 MachineBasicBlock &BB = *I.getParent();
4484
4485 if (STI.canUseExtension(
4486 E: SPIRV::Extension::SPV_EXT_demote_to_helper_invocation) ||
4487 STI.isAtLeastSPIRVVer(VerToCompareTo: llvm::VersionTuple(1, 6))) {
4488 Opcode = SPIRV::OpDemoteToHelperInvocation;
4489 } else {
4490 Opcode = SPIRV::OpKill;
4491 // OpKill must be the last operation of any basic block.
4492 for (MachineInstr &ToErase : make_early_inc_range(
4493 Range: make_range(x: std::next(x: I.getIterator()), y: BB.instr_end()))) {
4494 GR.invalidateMachineInstr(MI: &ToErase);
4495 ToErase.eraseFromParent();
4496 }
4497 }
4498
4499 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
4500 .constrainAllUses(TII, TRI, RBI);
4501 return true;
4502}
4503
4504bool SPIRVInstructionSelector::selectCmp(Register ResVReg,
4505 SPIRVTypeInst ResType, unsigned CmpOpc,
4506 MachineInstr &I) const {
4507 Register Cmp0 = I.getOperand(i: 2).getReg();
4508 Register Cmp1 = I.getOperand(i: 3).getReg();
4509 assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() ==
4510 GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() &&
4511 "CMP operands should have the same type");
4512 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: CmpOpc))
4513 .addDef(RegNo: ResVReg)
4514 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
4515 .addUse(RegNo: Cmp0)
4516 .addUse(RegNo: Cmp1)
4517 .setMIFlags(I.getFlags())
4518 .constrainAllUses(TII, TRI, RBI);
4519 return true;
4520}
4521
4522bool SPIRVInstructionSelector::selectICmp(Register ResVReg,
4523 SPIRVTypeInst ResType,
4524 MachineInstr &I) const {
4525 auto Pred = I.getOperand(i: 1).getPredicate();
4526 unsigned CmpOpc;
4527
4528 Register CmpOperand = I.getOperand(i: 2).getReg();
4529 SPIRVTypeInst CmpOperandType = GR.getSPIRVTypeForVReg(VReg: CmpOperand);
4530 bool IsPtrCmp = CmpOperandType && CmpOperandType.isPointer();
4531 if (IsPtrCmp) {
4532 CmpOpc = getPtrCmpOpcode(Pred);
4533 // OpPtrEqual/OpPtrNotEqual require both operands to share an identical
4534 // pointer type. If they are not OpBitcast is inserted.
4535 Register Op1 = I.getOperand(i: 3).getReg();
4536 SPIRVTypeInst Ty0 = GR.getSPIRVTypeForVReg(VReg: CmpOperand);
4537 if (Ty0 != GR.getSPIRVTypeForVReg(VReg: Op1)) {
4538 Register NewOp1 = createVirtualRegister(SpvType: Ty0, GR: &GR, MRI, MF: MRI->getMF());
4539 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpBitcast))
4540 .addDef(RegNo: NewOp1)
4541 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: Ty0))
4542 .addUse(RegNo: Op1)
4543 .constrainAllUses(TII, TRI, RBI);
4544 I.getOperand(i: 3).setReg(NewOp1);
4545 }
4546 } else if (GR.isScalarOrVectorOfType(VReg: CmpOperand, TypeOpcode: SPIRV::OpTypeBool))
4547 CmpOpc = getBoolCmpOpcode(PredNum: Pred);
4548 else
4549 CmpOpc = getICmpOpcode(PredNum: Pred);
4550 return selectCmp(ResVReg, ResType, CmpOpc, I);
4551}
4552
4553Register
4554SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I,
4555 SPIRVTypeInst ResType) const {
4556 Type *LLVMTy = IntegerType::get(C&: GR.CurMF->getFunction().getContext(), NumBits: 32);
4557 SPIRVTypeInst SpvI32Ty =
4558 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
4559 // Find a constant in DT or build a new one.
4560 auto ConstInt = ConstantInt::get(Ty: LLVMTy, V: Val);
4561 Register NewReg = GR.find(V: ConstInt, MF: GR.CurMF);
4562 if (!NewReg.isValid()) {
4563 NewReg = MRI->createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 64));
4564 MachineBasicBlock &BB = *I.getParent();
4565 MachineInstr *MI =
4566 Val == 0
4567 ? BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpConstantNull))
4568 .addDef(RegNo: NewReg)
4569 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: SpvI32Ty))
4570 : BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpConstantI))
4571 .addDef(RegNo: NewReg)
4572 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: SpvI32Ty))
4573 .addImm(Val: APInt(32, Val).getZExtValue());
4574 constrainSelectedInstRegOperands(I&: *MI, TII, TRI, RBI);
4575 GR.add(V: ConstInt, MI);
4576 }
4577 return NewReg;
4578}
4579
4580// Like buildI32Constant, but always inserts the constant definition in the
4581// entry block so it dominates all uses regardless of block ordering.
4582Register SPIRVInstructionSelector::buildI32ConstantInEntryBlock(
4583 uint32_t Val, MachineInstr &I, SPIRVTypeInst ResType) const {
4584 Type *LLVMTy = IntegerType::get(C&: GR.CurMF->getFunction().getContext(), NumBits: 32);
4585 SPIRVTypeInst SpvI32Ty =
4586 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
4587 auto *ConstInt = ConstantInt::get(Ty: LLVMTy, V: Val);
4588 Register NewReg = GR.find(V: ConstInt, MF: GR.CurMF);
4589 if (!NewReg.isValid()) {
4590 NewReg = MRI->createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 64));
4591 auto InsertIt = getOpVariableMBBIt(MF&: *I.getMF());
4592 MachineBasicBlock &EntryBB = *InsertIt->getParent();
4593 MachineInstr *MI = nullptr;
4594 Register TypeReg = GR.getSPIRVTypeID(SpirvType: SpvI32Ty);
4595 DebugLoc DbgLoc = I.getDebugLoc();
4596 if (Val == 0) {
4597 MI = BuildMI(BB&: EntryBB, I: InsertIt, MIMD: DbgLoc, MCID: TII.get(Opcode: SPIRV::OpConstantNull))
4598 .addDef(RegNo: NewReg)
4599 .addUse(RegNo: TypeReg);
4600 } else {
4601 uint64_t ImmVal = APInt(32, Val).getZExtValue();
4602 MI = BuildMI(BB&: EntryBB, I: InsertIt, MIMD: DbgLoc, MCID: TII.get(Opcode: SPIRV::OpConstantI))
4603 .addDef(RegNo: NewReg)
4604 .addUse(RegNo: TypeReg)
4605 .addImm(Val: ImmVal);
4606 }
4607 constrainSelectedInstRegOperands(I&: *MI, TII, TRI, RBI);
4608 GR.add(V: ConstInt, MI);
4609 }
4610 return NewReg;
4611}
4612
4613bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
4614 SPIRVTypeInst ResType,
4615 MachineInstr &I) const {
4616 auto Pred = I.getOperand(i: 1).getPredicate();
4617 // OpOrdered and OpUnordered require the Kernel capability. For shaders,
4618 // express them as uno(a, b) = isnan(a) || isnan(b), ord(a, b) = !uno(a, b).
4619 if (STI.isShader() &&
4620 (Pred == CmpInst::FCMP_ORD || Pred == CmpInst::FCMP_UNO)) {
4621 MachineBasicBlock &BB = *I.getParent();
4622 Register ResTypeID = GR.getSPIRVTypeID(SpirvType: ResType);
4623 Register IsNan[2];
4624 for (unsigned Idx = 0; Idx < 2; ++Idx) {
4625 IsNan[Idx] = createVirtualRegister(SpvType: ResType, GR: &GR, MRI, MF: *I.getMF());
4626 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpIsNan))
4627 .addDef(RegNo: IsNan[Idx])
4628 .addUse(RegNo: ResTypeID)
4629 .addUse(RegNo: I.getOperand(i: 2 + Idx).getReg())
4630 .constrainAllUses(TII, TRI, RBI);
4631 }
4632 Register UnoReg =
4633 Pred == CmpInst::FCMP_UNO
4634 ? ResVReg
4635 : createVirtualRegister(SpvType: ResType, GR: &GR, MRI, MF: *I.getMF());
4636 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpLogicalOr))
4637 .addDef(RegNo: UnoReg)
4638 .addUse(RegNo: ResTypeID)
4639 .addUse(RegNo: IsNan[0])
4640 .addUse(RegNo: IsNan[1])
4641 .constrainAllUses(TII, TRI, RBI);
4642 if (Pred == CmpInst::FCMP_ORD)
4643 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpLogicalNot))
4644 .addDef(RegNo: ResVReg)
4645 .addUse(RegNo: ResTypeID)
4646 .addUse(RegNo: UnoReg)
4647 .constrainAllUses(TII, TRI, RBI);
4648 return true;
4649 }
4650 unsigned CmpOp = getFCmpOpcode(PredNum: Pred);
4651 return selectCmp(ResVReg, ResType, CmpOpc: CmpOp, I);
4652}
4653
4654bool SPIRVInstructionSelector::selectExp10(Register ResVReg,
4655 SPIRVTypeInst ResType,
4656 MachineInstr &I) const {
4657 if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::OpenCL_std)) {
4658 return selectExtInst(ResVReg, ResType, I, CLInst: CL::exp10);
4659 }
4660
4661 if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::GLSL_std_450)) {
4662 /// There is no exp10 in GLSL. Use exp10(x) = exp2(x * log2(10)) instead
4663 /// log2(10) ~= 3.3219280948874l
4664
4665 if (!isVectorType(SPVTy: ResType) && !ResType.isAnyTypeFloat())
4666 return false;
4667
4668 MachineIRBuilder MIRBuilder(I);
4669
4670 SPIRVTypeInst SpirvScalarType = GR.getScalarOrVectorComponentType(Type: ResType);
4671
4672 // Match the literal precision to the scalar type so the OpConstant
4673 // literal does not contain non-zero high-order bits that would fail
4674 // SPIR-V validation when the type is narrower than 32 bits (e.g. half).
4675 APFloat ConstVal(3.3219280948873623);
4676 bool LosesInfo;
4677 ConstVal.convert(
4678 ToSemantics: getZeroFP(LLVMFloatTy: GR.getTypeForSPIRVType(Ty: SpirvScalarType)).getSemantics(),
4679 RM: APFloat::rmNearestTiesToEven, losesInfo: &LosesInfo);
4680 Register ConstReg =
4681 GR.buildConstantFP(Val: ConstVal, MIRBuilder, SpvType: SpirvScalarType);
4682 Register ArgReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
4683 auto Opcode =
4684 isVectorType(SPVTy: ResType) ? SPIRV::OpVectorTimesScalar : SPIRV::OpFMulS;
4685
4686 if (!selectOpWithSrcs(ResVReg: ArgReg, ResType, I,
4687 Srcs: {I.getOperand(i: 1).getReg(), ConstReg}, Opcode))
4688 return false;
4689 if (!selectExtInst(ResVReg, ResType, I,
4690 Insts: {{SPIRV::InstructionSet::GLSL_std_450, GL::Exp2}}, setMIFlags: false,
4691 useMISrc: false, SrcRegs: {ArgReg}))
4692 return false;
4693
4694 return true;
4695 }
4696
4697 return false;
4698}
4699
4700Register SPIRVInstructionSelector::buildZerosVal(SPIRVTypeInst ResType,
4701 MachineInstr &I) const {
4702 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
4703 bool ZeroAsNull = !STI.isShader();
4704 if (isVectorType(SPVTy: ResType))
4705 return GR.getOrCreateConstVector(Val: 0UL, I, SpvType: ResType, TII, ZeroAsNull);
4706 return GR.getOrCreateConstInt(Val: 0, I, SpvType: ResType, TII, ZeroAsNull);
4707}
4708
4709bool SPIRVInstructionSelector::isScalarOrVectorIntConstantZero(
4710 Register Reg) const {
4711 SPIRVTypeInst Type = GR.getSPIRVTypeForVReg(VReg: Reg);
4712 if (!Type)
4713 return false;
4714 SPIRVTypeInst CompType = GR.getScalarOrVectorComponentType(Type);
4715 if (!CompType || CompType->getOpcode() != SPIRV::OpTypeInt)
4716 return false;
4717
4718 auto IsZero = [this](Register Reg) {
4719 MachineInstr *Def = getDefInstrMaybeConstant(ConstReg&: Reg, MRI);
4720 if (!Def)
4721 return false;
4722
4723 if (Def->getOpcode() == SPIRV::OpConstantNull)
4724 return true;
4725
4726 if (Def->getOpcode() == TargetOpcode::G_CONSTANT ||
4727 Def->getOpcode() == SPIRV::OpConstantI)
4728 return getIConstVal(ConstReg: Reg, MRI) == 0;
4729
4730 return false;
4731 };
4732
4733 if (IsZero(Reg))
4734 return true;
4735
4736 MachineInstr *Def = MRI->getVRegDef(Reg);
4737 if (!Def)
4738 return false;
4739
4740 if (Def->getOpcode() == TargetOpcode::G_BUILD_VECTOR ||
4741 (Def->getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS &&
4742 cast<GIntrinsic>(Val: Def)->getIntrinsicID() ==
4743 Intrinsic::spv_const_composite)) {
4744 unsigned StartOp = Def->getOpcode() == TargetOpcode::G_BUILD_VECTOR ? 1 : 2;
4745 for (unsigned i = StartOp; i < Def->getNumOperands(); ++i) {
4746 if (!IsZero(Def->getOperand(i).getReg()))
4747 return false;
4748 }
4749 return true;
4750 }
4751
4752 return false;
4753}
4754
4755Register SPIRVInstructionSelector::buildZerosValF(SPIRVTypeInst ResType,
4756 MachineInstr &I) const {
4757 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
4758 bool ZeroAsNull = !STI.isShader();
4759 APFloat VZero = getZeroFP(LLVMFloatTy: GR.getTypeForSPIRVType(Ty: ResType));
4760 if (isVectorType(SPVTy: ResType))
4761 return GR.getOrCreateConstVector(Val: VZero, I, SpvType: ResType, TII, ZeroAsNull);
4762 return GR.getOrCreateConstFP(Val: VZero, I, SpvType: ResType, TII, ZeroAsNull);
4763}
4764
4765Register SPIRVInstructionSelector::buildOnesValF(SPIRVTypeInst ResType,
4766 MachineInstr &I) const {
4767 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
4768 bool ZeroAsNull = !STI.isShader();
4769 APFloat VOne = getOneFP(LLVMFloatTy: GR.getTypeForSPIRVType(Ty: ResType));
4770 if (isVectorType(SPVTy: ResType))
4771 return GR.getOrCreateConstVector(Val: VOne, I, SpvType: ResType, TII, ZeroAsNull);
4772 return GR.getOrCreateConstFP(Val: VOne, I, SpvType: ResType, TII, ZeroAsNull);
4773}
4774
4775Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
4776 SPIRVTypeInst ResType,
4777 MachineInstr &I) const {
4778 unsigned BitWidth = GR.getScalarOrVectorBitWidth(Type: ResType);
4779 APInt One =
4780 AllOnes ? APInt::getAllOnes(numBits: BitWidth) : APInt::getOneBitSet(numBits: BitWidth, BitNo: 0);
4781 if (isVectorType(SPVTy: ResType))
4782 return GR.getOrCreateConstVector(Val: One, I, SpvType: ResType, TII);
4783 return GR.getOrCreateConstInt(Val: One, I, SpvType: ResType, TII);
4784}
4785
4786Register SPIRVInstructionSelector::buildVectorSplat(Register ScalarReg,
4787 unsigned NumElts,
4788 MachineInstr &I) const {
4789 SPIRVTypeInst VecType = GR.getOrCreateSPIRVVectorType(
4790 BaseType: GR.getSPIRVTypeForVReg(VReg: ScalarReg), NumElements: NumElts, I, TII);
4791 Register SplatReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: VecType));
4792 GR.assignSPIRVTypeToVReg(Type: VecType, VReg: SplatReg, MF: MRI->getMF());
4793 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
4794 MCID: TII.get(Opcode: SPIRV::OpCompositeConstruct))
4795 .addDef(RegNo: SplatReg)
4796 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: VecType));
4797 for (unsigned J = 0; J < NumElts; ++J)
4798 MIB.addUse(RegNo: ScalarReg);
4799 MIB.constrainAllUses(TII, TRI, RBI);
4800 return SplatReg;
4801}
4802
4803bool SPIRVInstructionSelector::selectSelect(Register ResVReg,
4804 SPIRVTypeInst ResType,
4805 MachineInstr &I) const {
4806 Register SelectFirstArg = I.getOperand(i: 2).getReg();
4807 Register SelectSecondArg = I.getOperand(i: 3).getReg();
4808 assert(ResType == GR.getSPIRVTypeForVReg(SelectFirstArg) &&
4809 ResType == GR.getSPIRVTypeForVReg(SelectSecondArg));
4810
4811 bool IsFloatTy =
4812 GR.isScalarOrVectorOfType(VReg: SelectFirstArg, TypeOpcode: SPIRV::OpTypeFloat);
4813 bool IsPtrTy =
4814 GR.isScalarOrVectorOfType(VReg: SelectFirstArg, TypeOpcode: SPIRV::OpTypePointer);
4815
4816 Register CondReg = I.getOperand(i: 1).getReg();
4817 bool IsScalarBool = GR.isScalarOfType(VReg: CondReg, TypeOpcode: SPIRV::OpTypeBool);
4818 unsigned Opcode;
4819 if (isVectorType(SPVTy: GR.getSPIRVTypeForVReg(VReg: SelectFirstArg))) {
4820 // Before SPIR-V 1.4, the condition of an OpSelect with a vector result
4821 // must be a vector of Booleans with the same number of components, while
4822 // LLVM IR also allows a scalar i1 condition. Splat it in that case.
4823 if (IsScalarBool && !STI.isAtLeastSPIRVVer(VerToCompareTo: VersionTuple(1, 4))) {
4824 unsigned NumElts = GR.getScalarOrVectorComponentCount(Type: ResType);
4825 CondReg = buildVectorSplat(ScalarReg: CondReg, NumElts, I);
4826 IsScalarBool = false;
4827 }
4828 if (IsFloatTy) {
4829 Opcode = IsScalarBool ? SPIRV::OpSelectVFSCond : SPIRV::OpSelectVFVCond;
4830 } else if (IsPtrTy) {
4831 Opcode = IsScalarBool ? SPIRV::OpSelectVPSCond : SPIRV::OpSelectVPVCond;
4832 } else {
4833 Opcode = IsScalarBool ? SPIRV::OpSelectVISCond : SPIRV::OpSelectVIVCond;
4834 }
4835 } else {
4836 assert(IsScalarBool && "OpSelect with a scalar result requires a scalar "
4837 "boolean condition");
4838 if (IsFloatTy) {
4839 Opcode = SPIRV::OpSelectSFSCond;
4840 } else if (IsPtrTy) {
4841 Opcode = SPIRV::OpSelectSPSCond;
4842 } else {
4843 Opcode = SPIRV::OpSelectSISCond;
4844 }
4845 }
4846 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
4847 .addDef(RegNo: ResVReg)
4848 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
4849 .addUse(RegNo: CondReg)
4850 .addUse(RegNo: SelectFirstArg)
4851 .addUse(RegNo: SelectSecondArg)
4852 .constrainAllUses(TII, TRI, RBI);
4853 return true;
4854}
4855
4856// This function is used to extend a bool or a vector of bools into an integer
4857// or vector of integers.
4858bool SPIRVInstructionSelector::selectBoolToInt(Register ResVReg,
4859 SPIRVTypeInst ResType,
4860 Register BooleanVReg,
4861 MachineInstr &InsertAt,
4862 bool IsSigned) const {
4863 // To extend a bool, we need to use OpSelect between constants.
4864 Register ZeroReg = buildZerosVal(ResType, I&: InsertAt);
4865 Register OneReg = buildOnesVal(AllOnes: IsSigned, ResType, I&: InsertAt);
4866 bool IsScalarBool = GR.isScalarOfType(VReg: BooleanVReg, TypeOpcode: SPIRV::OpTypeBool);
4867 unsigned Opcode =
4868 IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond;
4869 BuildMI(BB&: *InsertAt.getParent(), I&: InsertAt, MIMD: InsertAt.getDebugLoc(),
4870 MCID: TII.get(Opcode))
4871 .addDef(RegNo: ResVReg)
4872 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
4873 .addUse(RegNo: BooleanVReg)
4874 .addUse(RegNo: OneReg)
4875 .addUse(RegNo: ZeroReg)
4876 .constrainAllUses(TII, TRI, RBI);
4877 return true;
4878}
4879
4880bool SPIRVInstructionSelector::selectIToF(Register ResVReg,
4881 SPIRVTypeInst ResType,
4882 MachineInstr &I, bool IsSigned,
4883 unsigned Opcode) const {
4884 Register SrcReg = I.getOperand(i: 1).getReg();
4885 // We can convert bool value directly to float type without OpConvert*ToF,
4886 // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
4887 if (GR.isScalarOrVectorOfType(VReg: I.getOperand(i: 1).getReg(), TypeOpcode: SPIRV::OpTypeBool)) {
4888 unsigned BitWidth = GR.getScalarOrVectorBitWidth(Type: ResType);
4889 SPIRVTypeInst TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII);
4890 if (isVectorType(SPVTy: ResType)) {
4891 const unsigned NumElts = GR.getScalarOrVectorComponentCount(Type: ResType);
4892 TmpType = GR.getOrCreateSPIRVVectorType(BaseType: TmpType, NumElements: NumElts, I, TII);
4893 }
4894 SrcReg = createVirtualRegister(SpvType: TmpType, GR: &GR, MRI, MF: MRI->getMF());
4895 selectBoolToInt(ResVReg: SrcReg, ResType: TmpType, BooleanVReg: I.getOperand(i: 1).getReg(), InsertAt&: I, IsSigned);
4896 }
4897 return selectOpWithSrcs(ResVReg, ResType, I, Srcs: {SrcReg}, Opcode);
4898}
4899
4900bool SPIRVInstructionSelector::selectExt(Register ResVReg,
4901 SPIRVTypeInst ResType, MachineInstr &I,
4902 bool IsSigned) const {
4903 Register SrcReg = I.getOperand(i: 1).getReg();
4904 if (GR.isScalarOrVectorOfType(VReg: SrcReg, TypeOpcode: SPIRV::OpTypeBool))
4905 return selectBoolToInt(ResVReg, ResType, BooleanVReg: I.getOperand(i: 1).getReg(), InsertAt&: I,
4906 IsSigned);
4907
4908 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(VReg: SrcReg);
4909 if (ResType == SrcType)
4910 return BuildCOPY(DestReg: ResVReg, SrcReg, I);
4911
4912 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
4913 return selectUnOp(ResVReg, ResType, I, Opcode);
4914}
4915
4916bool SPIRVInstructionSelector::selectSUCmp(Register ResVReg,
4917 SPIRVTypeInst ResType,
4918 MachineInstr &I,
4919 bool IsSigned) const {
4920 MachineIRBuilder MIRBuilder(I);
4921 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
4922 MachineBasicBlock &BB = *I.getParent();
4923 // Ensure we have bool.
4924 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
4925 unsigned N = GR.getScalarOrVectorComponentCount(Type: ResType);
4926 if (N > 1 || (ResType->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
4927 STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector)))
4928 BoolType = GR.getOrCreateSPIRVVectorType(BaseType: BoolType, NumElements: N, I, TII);
4929 Register BoolTypeReg = GR.getSPIRVTypeID(SpirvType: BoolType);
4930 // Build less-than-equal and less-than.
4931 Register IsLessEqReg =
4932 createVirtualRegister(SpvType: BoolType, GR: &GR, MRI, MF: MIRBuilder.getMF());
4933 BuildMI(BB, I, MIMD: I.getDebugLoc(),
4934 MCID: TII.get(Opcode: IsSigned ? SPIRV::OpSLessThanEqual : SPIRV::OpULessThanEqual))
4935 .addDef(RegNo: IsLessEqReg)
4936 .addUse(RegNo: BoolTypeReg)
4937 .addUse(RegNo: I.getOperand(i: 1).getReg())
4938 .addUse(RegNo: I.getOperand(i: 2).getReg())
4939 .constrainAllUses(TII, TRI, RBI);
4940 Register IsLessReg =
4941 createVirtualRegister(SpvType: BoolType, GR: &GR, MRI, MF: MIRBuilder.getMF());
4942 BuildMI(BB, I, MIMD: I.getDebugLoc(),
4943 MCID: TII.get(Opcode: IsSigned ? SPIRV::OpSLessThan : SPIRV::OpULessThan))
4944 .addDef(RegNo: IsLessReg)
4945 .addUse(RegNo: BoolTypeReg)
4946 .addUse(RegNo: I.getOperand(i: 1).getReg())
4947 .addUse(RegNo: I.getOperand(i: 2).getReg())
4948 .constrainAllUses(TII, TRI, RBI);
4949 // Build selects.
4950 Register ResTypeReg = GR.getSPIRVTypeID(SpirvType: ResType);
4951 Register NegOneOrZeroReg =
4952 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
4953 MRI->setType(VReg: NegOneOrZeroReg, Ty: LLT::scalar(SizeInBits: 64));
4954 GR.assignSPIRVTypeToVReg(Type: ResType, VReg: NegOneOrZeroReg, MF: MIRBuilder.getMF());
4955 unsigned SelectOpcode =
4956 (N > 1 || (ResType->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
4957 STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector)))
4958 ? SPIRV::OpSelectVIVCond
4959 : SPIRV::OpSelectSISCond;
4960 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SelectOpcode))
4961 .addDef(RegNo: NegOneOrZeroReg)
4962 .addUse(RegNo: ResTypeReg)
4963 .addUse(RegNo: IsLessReg)
4964 .addUse(RegNo: buildOnesVal(AllOnes: true, ResType, I)) // -1
4965 .addUse(RegNo: buildZerosVal(ResType, I))
4966 .constrainAllUses(TII, TRI, RBI);
4967 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SelectOpcode))
4968 .addDef(RegNo: ResVReg)
4969 .addUse(RegNo: ResTypeReg)
4970 .addUse(RegNo: IsLessEqReg)
4971 .addUse(RegNo: NegOneOrZeroReg) // -1 or 0
4972 .addUse(RegNo: buildOnesVal(AllOnes: false, ResType, I))
4973 .constrainAllUses(TII, TRI, RBI);
4974 return true;
4975}
4976
4977bool SPIRVInstructionSelector::selectIntToBool(Register IntReg,
4978 Register ResVReg,
4979 MachineInstr &I,
4980 SPIRVTypeInst IntTy,
4981 SPIRVTypeInst BoolTy) const {
4982 // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
4983 Register BitIntReg = createVirtualRegister(SpvType: IntTy, GR: &GR, MRI, MF: MRI->getMF());
4984 unsigned Opcode =
4985 isVectorType(SPVTy: IntTy) ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
4986 Register Zero = buildZerosVal(ResType: IntTy, I);
4987 Register One = buildOnesVal(AllOnes: false, ResType: IntTy, I);
4988 MachineBasicBlock &BB = *I.getParent();
4989 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
4990 .addDef(RegNo: BitIntReg)
4991 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: IntTy))
4992 .addUse(RegNo: IntReg)
4993 .addUse(RegNo: One)
4994 .constrainAllUses(TII, TRI, RBI);
4995 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpINotEqual))
4996 .addDef(RegNo: ResVReg)
4997 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: BoolTy))
4998 .addUse(RegNo: BitIntReg)
4999 .addUse(RegNo: Zero)
5000 .constrainAllUses(TII, TRI, RBI);
5001 return true;
5002}
5003
5004bool SPIRVInstructionSelector::selectTrunc(Register ResVReg,
5005 SPIRVTypeInst ResType,
5006 MachineInstr &I) const {
5007 Register IntReg = I.getOperand(i: 1).getReg();
5008 const SPIRVTypeInst ArgType = GR.getSPIRVTypeForVReg(VReg: IntReg);
5009 if (GR.isScalarOrVectorOfType(VReg: ResVReg, TypeOpcode: SPIRV::OpTypeBool))
5010 return selectIntToBool(IntReg, ResVReg, I, IntTy: ArgType, BoolTy: ResType);
5011 if (ArgType == ResType)
5012 return BuildCOPY(DestReg: ResVReg, SrcReg: IntReg, I);
5013 bool IsSigned = GR.isScalarOrVectorSigned(Type: ResType);
5014 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
5015 return selectUnOp(ResVReg, ResType, I, Opcode);
5016}
5017
5018bool SPIRVInstructionSelector::selectConst(Register ResVReg,
5019 SPIRVTypeInst ResType,
5020 MachineInstr &I) const {
5021 unsigned Opcode = I.getOpcode();
5022 unsigned TpOpcode = ResType->getOpcode();
5023 Register Reg;
5024 if (ResType.isPointer() || TpOpcode == SPIRV::OpTypeEvent) {
5025 assert(Opcode == TargetOpcode::G_CONSTANT &&
5026 I.getOperand(1).getCImm()->isZero());
5027 MachineBasicBlock &DepMBB = I.getMF()->front();
5028 MachineIRBuilder MIRBuilder(DepMBB, DepMBB.getFirstNonPHI());
5029 Reg = GR.getOrCreateConstNullPtr(MIRBuilder, SpvType: ResType);
5030 } else if (TpOpcode == SPIRV::OpTypeVectorIdEXT) {
5031 // We ended up here coming from a splat on a <1 x T> type, which
5032 // IRTranslator translated into a scalar, so we have to restore the
5033 // vectorness.
5034 assert(GR.getScalarOrVectorComponentCount(ResType) == 1 &&
5035 "Expected <1 x T> Vector!");
5036 if (Opcode == TargetOpcode::G_FCONSTANT)
5037 Reg = GR.getOrCreateConstVector(Val: I.getOperand(i: 1).getFPImm()->getValue(), I,
5038 SpvType: ResType, TII);
5039 else // We handle vector of pointer here as well.
5040 Reg = GR.getOrCreateConstVector(Val: I.getOperand(i: 1).getCImm()->getValue(), I,
5041 SpvType: ResType, TII);
5042 } else if (Opcode == TargetOpcode::G_FCONSTANT) {
5043 Reg = GR.getOrCreateConstFP(Val: I.getOperand(i: 1).getFPImm()->getValue(), I,
5044 SpvType: ResType, TII, ZeroAsNull: !STI.isShader());
5045
5046 } else {
5047 Reg = GR.getOrCreateConstInt(Val: I.getOperand(i: 1).getCImm()->getValue(), I,
5048 SpvType: ResType, TII, ZeroAsNull: !STI.isShader());
5049 }
5050 return Reg == ResVReg ? true : BuildCOPY(DestReg: ResVReg, SrcReg: Reg, I);
5051}
5052
5053bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg,
5054 SPIRVTypeInst ResType,
5055 MachineInstr &I) const {
5056 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpUndef))
5057 .addDef(RegNo: ResVReg)
5058 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5059 .constrainAllUses(TII, TRI, RBI);
5060 return true;
5061}
5062
5063bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg,
5064 SPIRVTypeInst ResType,
5065 MachineInstr &I) const {
5066 MachineBasicBlock &BB = *I.getParent();
5067 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpCompositeInsert))
5068 .addDef(RegNo: ResVReg)
5069 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5070 // object to insert
5071 .addUse(RegNo: I.getOperand(i: 3).getReg())
5072 // composite to insert into
5073 .addUse(RegNo: I.getOperand(i: 2).getReg());
5074 for (unsigned i = 4; i < I.getNumOperands(); i++)
5075 MIB.addImm(Val: foldImm(MO: I.getOperand(i), MRI));
5076 MIB.constrainAllUses(TII, TRI, RBI);
5077 return true;
5078}
5079
5080bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg,
5081 SPIRVTypeInst ResType,
5082 MachineInstr &I) const {
5083 Type *MaybeResTy = nullptr;
5084 StringRef ResName;
5085 if (GR.findValueAttrs(Key: &I, Ty&: MaybeResTy, Name&: ResName) &&
5086 MaybeResTy != GR.getTypeForSPIRVType(Ty: ResType)) {
5087 assert((!MaybeResTy || MaybeResTy->isAggregateType()) &&
5088 "Expected aggregate type for extractv instruction");
5089 ResType = GR.getOrCreateSPIRVType(Type: MaybeResTy, I,
5090 AQ: SPIRV::AccessQualifier::ReadWrite, EmitIR: false);
5091 GR.assignSPIRVTypeToVReg(Type: ResType, VReg: ResVReg, MF: *I.getMF());
5092 }
5093 MachineBasicBlock &BB = *I.getParent();
5094 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpCompositeExtract))
5095 .addDef(RegNo: ResVReg)
5096 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5097 .addUse(RegNo: I.getOperand(i: 2).getReg());
5098 for (unsigned i = 3; i < I.getNumOperands(); i++)
5099 MIB.addImm(Val: foldImm(MO: I.getOperand(i), MRI));
5100 MIB.constrainAllUses(TII, TRI, RBI);
5101 return true;
5102}
5103
5104bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg,
5105 SPIRVTypeInst ResType,
5106 MachineInstr &I) const {
5107 if (getImm(MO: I.getOperand(i: 4), MRI))
5108 return selectInsertVal(ResVReg, ResType, I);
5109 MachineBasicBlock &BB = *I.getParent();
5110 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpVectorInsertDynamic))
5111 .addDef(RegNo: ResVReg)
5112 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5113 .addUse(RegNo: I.getOperand(i: 2).getReg())
5114 .addUse(RegNo: I.getOperand(i: 3).getReg())
5115 .addUse(RegNo: I.getOperand(i: 4).getReg())
5116 .constrainAllUses(TII, TRI, RBI);
5117 return true;
5118}
5119
5120bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg,
5121 SPIRVTypeInst ResType,
5122 MachineInstr &I) const {
5123 if (getImm(MO: I.getOperand(i: 3), MRI))
5124 return selectExtractVal(ResVReg, ResType, I);
5125 MachineBasicBlock &BB = *I.getParent();
5126 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpVectorExtractDynamic))
5127 .addDef(RegNo: ResVReg)
5128 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5129 .addUse(RegNo: I.getOperand(i: 2).getReg())
5130 .addUse(RegNo: I.getOperand(i: 3).getReg())
5131 .constrainAllUses(TII, TRI, RBI);
5132 return true;
5133}
5134
5135bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
5136 SPIRVTypeInst ResType,
5137 MachineInstr &I) const {
5138 const bool IsGEPInBounds = I.getOperand(i: 2).getImm();
5139 // Pointers to opaque types stay typed even with the extension on, so emit the
5140 // untyped variant only when the result is actually an untyped pointer.
5141 const bool UseUntypedPointers =
5142 ResType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
5143
5144 // Determine the opcode based on pointer type and bounds checking.
5145 // When using untyped pointers, use OpUntyped*AccessChainKHR variants.
5146 unsigned Opcode;
5147 if (UseUntypedPointers) {
5148 if (STI.isLogicalSPIRV()) {
5149 Opcode = IsGEPInBounds ? SPIRV::OpUntypedInBoundsAccessChainKHR
5150 : SPIRV::OpUntypedAccessChainKHR;
5151 } else {
5152 Opcode = IsGEPInBounds ? SPIRV::OpUntypedInBoundsPtrAccessChainKHR
5153 : SPIRV::OpUntypedPtrAccessChainKHR;
5154 }
5155 } else {
5156 // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator
5157 // only relies on PtrAccessChain, so we'll try not to deviate. For Vulkan
5158 // however, we have to use Op[InBounds]AccessChain.
5159 // FIXME: fix llvm-spirv.
5160 if (STI.isLogicalSPIRV()) {
5161 Opcode =
5162 IsGEPInBounds ? SPIRV::OpInBoundsAccessChain : SPIRV::OpAccessChain;
5163 } else {
5164 Opcode = IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
5165 : SPIRV::OpPtrAccessChain;
5166 }
5167 }
5168
5169 Register BaseReg = I.getOperand(i: 3).getReg();
5170 auto Res = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
5171 .addDef(RegNo: ResVReg)
5172 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
5173
5174 // For untyped access chains, we need to add the base type operand.
5175 if (UseUntypedPointers) {
5176 // Get the element type from the base pointer register.
5177 // For untyped pointers, this was stored when processing
5178 // spv_assign_ptr_type.
5179 SPIRVTypeInst BaseType = GR.getUntypedPtrElementType(Reg: BaseReg);
5180 if (!BaseType) {
5181 // Otherwise try the pointee type for mixed typed-pointer usage.
5182 SPIRVTypeInst BasePtrType = GR.getSPIRVTypeForVReg(VReg: BaseReg);
5183 BaseType = BasePtrType ? GR.getPointeeType(PtrType: BasePtrType) : nullptr;
5184 }
5185 if (!BaseType) {
5186 // The base may be a not-yet-selected global. Read its value type from
5187 // the defining G_GLOBAL_VALUE, following copies.
5188 Register DefReg = BaseReg;
5189 MachineInstr *Def = MRI->getVRegDef(Reg: DefReg);
5190 while (Def && Def->getOpcode() == TargetOpcode::COPY &&
5191 Def->getOperand(i: 1).isReg())
5192 Def = MRI->getVRegDef(Reg: Def->getOperand(i: 1).getReg());
5193 if (Def && Def->getOpcode() == TargetOpcode::G_GLOBAL_VALUE)
5194 if (const auto *GVar =
5195 dyn_cast<GlobalVariable>(Val: Def->getOperand(i: 1).getGlobal()))
5196 BaseType = GR.getOrCreateSPIRVType(Type: GVar->getValueType(), I,
5197 AQ: SPIRV::AccessQualifier::ReadWrite,
5198 /*EmitIR=*/false);
5199 }
5200 if (!BaseType)
5201 return diagnoseUnsupported(
5202 I, Msg: "could not deduce the base type of an untyped access chain");
5203 Res.addUse(RegNo: GR.getSPIRVTypeID(SpirvType: BaseType));
5204 }
5205
5206 // Object to get a pointer to.
5207 Res.addUse(RegNo: BaseReg);
5208
5209 const bool IsAccessChainOpcode =
5210 (Opcode == SPIRV::OpAccessChain ||
5211 Opcode == SPIRV::OpInBoundsAccessChain ||
5212 Opcode == SPIRV::OpUntypedAccessChainKHR ||
5213 Opcode == SPIRV::OpUntypedInBoundsAccessChainKHR);
5214
5215 assert((!IsAccessChainOpcode || (getImm(I.getOperand(4), MRI) &&
5216 foldImm(I.getOperand(4), MRI) == 0)) &&
5217 "Cannot translate GEP to OpAccessChain.");
5218
5219 // Adding indices.
5220 const unsigned StartingIndex = IsAccessChainOpcode ? 5 : 4;
5221 for (unsigned i = StartingIndex; i < I.getNumExplicitOperands(); ++i)
5222 Res.addUse(RegNo: I.getOperand(i).getReg());
5223 Res.constrainAllUses(TII, TRI, RBI);
5224
5225 // IRTranslator doesn't like <1 x T> vectors, and treats them as scalars. This
5226 // creates an information loss issue, and also broken code where a
5227 // OpCompositeExtract is applied to the scalar return of an OpPtrAccessChain,
5228 // when it was meant to be applied to the OpCompositeInsert created <1 x T>.
5229 // TODO: should we also re-create the index <1 x T>?
5230 if (MRI->hasOneUse(RegNo: ResVReg)) {
5231 MachineInstr &Extract = *MRI->use_instr_begin(RegNo: ResVReg);
5232 if (Extract.getOpcode() == SPIRV::OpCompositeExtract) {
5233 SPIRVTypeInst V = GR.getOrCreateSPIRVVectorType(BaseType: ResType, NumElements: 1, I&: Extract, TII);
5234 // We cannot use GlobalRegistry::getOrCreateUndef directly here because it
5235 // tries to use UndefVal::get, which does not work for TypedPointerType,
5236 // which we can get here if we're dealing with <1 x T*>.
5237 Register Tmp = createVirtualRegister(SpvType: V, GR: &GR, MRI, MF: *I.getMF());
5238 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpUndef))
5239 .addDef(RegNo: Tmp)
5240 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: V))
5241 .constrainAllUses(TII, TRI, RBI);
5242 Register InsertReg = createVirtualRegister(SpvType: V, GR: &GR, MRI, MF: *I.getMF());
5243 BuildMI(BB&: *I.getParent(), I&: Extract, MIMD: Extract.getDebugLoc(),
5244 MCID: TII.get(Opcode: SPIRV::OpCompositeInsert))
5245 .addDef(RegNo: InsertReg)
5246 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: V))
5247 .addUse(RegNo: ResVReg)
5248 .addUse(RegNo: Tmp)
5249 .addImm(Val: 0)
5250 .constrainAllUses(TII, TRI, RBI);
5251 Extract.substituteRegister(FromReg: ResVReg, ToReg: InsertReg, SubIdx: 0, RegInfo: TRI);
5252 }
5253 }
5254 return true;
5255}
5256
5257// Maybe wrap a value into OpSpecConstantOp
5258bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
5259 MachineInstr &I, SmallVector<Register> &CompositeArgs) const {
5260 unsigned Lim = I.getNumExplicitOperands();
5261 for (unsigned i = I.getNumExplicitDefs() + 1; i < Lim; ++i) {
5262 Register OpReg = I.getOperand(i).getReg();
5263 MachineInstr *OpDefine = MRI->getVRegDef(Reg: OpReg);
5264 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(VReg: OpReg);
5265 if (!OpDefine || !OpType || isConstReg(MRI, OpDef: OpDefine) ||
5266 OpDefine->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
5267 OpDefine->getOpcode() == TargetOpcode::G_INTTOPTR ||
5268 GR.isAggregateType(Type: OpType)) {
5269 // The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed
5270 // by selectAddrSpaceCast(), and G_INTTOPTR is processed by selectUnOp()
5271 CompositeArgs.push_back(Elt: OpReg);
5272 continue;
5273 }
5274 MachineFunction *MF = I.getMF();
5275 Register WrapReg = GR.find(MI: OpDefine, MF);
5276 if (WrapReg.isValid()) {
5277 CompositeArgs.push_back(Elt: WrapReg);
5278 continue;
5279 }
5280 SPIRVTypeInst WrapType = OpType;
5281 if (OpType->getOpcode() == SPIRV::OpTypePointer &&
5282 GR.getPointerStorageClass(Type: OpType) ==
5283 SPIRV::StorageClass::CodeSectionINTEL) {
5284 WrapType = GR.changePointerStorageClass(PtrType: OpType,
5285 SC: SPIRV::StorageClass::Function, I);
5286 }
5287 WrapReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: WrapType));
5288 CompositeArgs.push_back(Elt: WrapReg);
5289 // Decorate the wrapper register and generate a new instruction
5290 MRI->setType(VReg: WrapReg, Ty: LLT::pointer(AddressSpace: 0, SizeInBits: 64));
5291 GR.assignSPIRVTypeToVReg(Type: WrapType, VReg: WrapReg, MF: *MF);
5292 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
5293 MCID: TII.get(Opcode: SPIRV::OpSpecConstantOp))
5294 .addDef(RegNo: WrapReg)
5295 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: WrapType))
5296 .addImm(Val: static_cast<uint32_t>(SPIRV::Opcode::Bitcast))
5297 .addUse(RegNo: OpReg);
5298 GR.add(Obj: OpDefine, MI: MIB);
5299 MIB.constrainAllUses(TII, TRI, RBI);
5300 }
5301 return true;
5302}
5303
5304bool SPIRVInstructionSelector::selectDerivativeInst(
5305 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
5306 const unsigned DPdOpCode) const {
5307 // TODO: This should check specifically for Fragment Execution Model, but STI
5308 // doesn't provide that information yet. See #167562
5309 if (!errorIfInstrOutsideShader(I))
5310 return false;
5311
5312 // If the arg/result types are half then we need to wrap the instr in
5313 // conversions to float
5314 // This case occurs because a half arg/result is legal in HLSL but not spirv.
5315 Register SrcReg = I.getOperand(i: 2).getReg();
5316 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(VReg: SrcReg);
5317 unsigned BitWidth = std::min(a: GR.getScalarOrVectorBitWidth(Type: SrcType),
5318 b: GR.getScalarOrVectorBitWidth(Type: ResType));
5319 if (BitWidth == 32)
5320 return BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: DPdOpCode))
5321 .addDef(RegNo: ResVReg)
5322 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5323 .addUse(RegNo: I.getOperand(i: 2).getReg());
5324
5325 MachineIRBuilder MIRBuilder(I);
5326 unsigned componentCount = GR.getScalarOrVectorComponentCount(Type: SrcType);
5327 SPIRVTypeInst F32ConvertTy = GR.getOrCreateSPIRVFloatType(BitWidth: 32, I, TII);
5328 if (componentCount != 1)
5329 F32ConvertTy = GR.getOrCreateSPIRVVectorType(BaseType: F32ConvertTy, NumElements: componentCount,
5330 MIRBuilder, EmitIR: false);
5331
5332 const TargetRegisterClass *RegClass = GR.getRegClass(SpvType: SrcType);
5333 Register ConvertToVReg = MRI->createVirtualRegister(RegClass);
5334 Register DpdOpVReg = MRI->createVirtualRegister(RegClass);
5335
5336 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpFConvert))
5337 .addDef(RegNo: ConvertToVReg)
5338 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: F32ConvertTy))
5339 .addUse(RegNo: SrcReg)
5340 .constrainAllUses(TII, TRI, RBI);
5341 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: DPdOpCode))
5342 .addDef(RegNo: DpdOpVReg)
5343 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: F32ConvertTy))
5344 .addUse(RegNo: ConvertToVReg)
5345 .constrainAllUses(TII, TRI, RBI);
5346 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpFConvert))
5347 .addDef(RegNo: ResVReg)
5348 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5349 .addUse(RegNo: DpdOpVReg)
5350 .constrainAllUses(TII, TRI, RBI);
5351 return true;
5352}
5353
5354bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
5355 SPIRVTypeInst ResType,
5356 MachineInstr &I) const {
5357 MachineBasicBlock &BB = *I.getParent();
5358 Intrinsic::ID IID = cast<GIntrinsic>(Val&: I).getIntrinsicID();
5359 switch (IID) {
5360 case Intrinsic::spv_load:
5361 return selectLoad(ResVReg, ResType, I);
5362 case Intrinsic::spv_atomic_load:
5363 return selectAtomicLoad(ResVReg, ResType, I);
5364 case Intrinsic::spv_store:
5365 return selectStore(I);
5366 case Intrinsic::spv_atomic_store:
5367 return selectAtomicStore(I);
5368 case Intrinsic::spv_extractv:
5369 return selectExtractVal(ResVReg, ResType, I);
5370 case Intrinsic::spv_insertv:
5371 return selectInsertVal(ResVReg, ResType, I);
5372 case Intrinsic::spv_extractelt:
5373 return selectExtractElt(ResVReg, ResType, I);
5374 case Intrinsic::spv_insertelt:
5375 return selectInsertElt(ResVReg, ResType, I);
5376 case Intrinsic::spv_gep:
5377 return selectGEP(ResVReg, ResType, I);
5378 case Intrinsic::spv_bitcast: {
5379 Register OpReg = I.getOperand(i: 2).getReg();
5380 SPIRVTypeInst OpType =
5381 OpReg.isValid() ? GR.getSPIRVTypeForVReg(VReg: OpReg) : nullptr;
5382 if (!GR.isBitcastCompatible(Type1: ResType, Type2: OpType))
5383 report_fatal_error(reason: "incompatible result and operand types in a bitcast");
5384 return selectOpWithSrcs(ResVReg, ResType, I, Srcs: {OpReg}, Opcode: SPIRV::OpBitcast);
5385 }
5386 case Intrinsic::spv_unref_global:
5387 case Intrinsic::spv_init_global: {
5388 MachineInstr *MI = MRI->getVRegDef(Reg: I.getOperand(i: 1).getReg());
5389 MachineInstr *Init = I.getNumExplicitOperands() > 2
5390 ? MRI->getVRegDef(Reg: I.getOperand(i: 2).getReg())
5391 : nullptr;
5392 assert(MI);
5393 Register GVarVReg = MI->getOperand(i: 0).getReg();
5394 if (!selectGlobalValue(ResVReg: GVarVReg, I&: *MI, Init))
5395 return false;
5396 // We violate SSA form by inserting OpVariable and still having a gMIR
5397 // instruction %vreg = G_GLOBAL_VALUE @gvar. We need to fix this by erasing
5398 // the duplicated definition.
5399 if (MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
5400 GR.invalidateMachineInstr(MI);
5401 MI->eraseFromParent();
5402 }
5403 return true;
5404 }
5405 case Intrinsic::spv_undef: {
5406 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpUndef))
5407 .addDef(RegNo: ResVReg)
5408 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
5409 MIB.constrainAllUses(TII, TRI, RBI);
5410 return true;
5411 }
5412 case Intrinsic::spv_poison:
5413 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpPoisonKHR))
5414 .addDef(RegNo: ResVReg)
5415 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5416 .constrainAllUses(TII, TRI, RBI);
5417 return true;
5418 case Intrinsic::spv_freeze:
5419 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpFreezeKHR))
5420 .addDef(RegNo: ResVReg)
5421 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5422 .addUse(RegNo: I.getOperand(i: 2).getReg())
5423 .constrainAllUses(TII, TRI, RBI);
5424 return true;
5425 case Intrinsic::spv_named_boolean_spec_constant: {
5426 auto Opcode = I.getOperand(i: 3).getImm() ? SPIRV::OpSpecConstantTrue
5427 : SPIRV::OpSpecConstantFalse;
5428
5429 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
5430 .addDef(RegNo: I.getOperand(i: 0).getReg())
5431 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
5432 MIB.constrainAllUses(TII, TRI, RBI);
5433 unsigned SpecId = I.getOperand(i: 2).getImm();
5434 buildOpDecorate(Reg: I.getOperand(i: 0).getReg(), I&: *++MIB->getIterator(), TII,
5435 Dec: SPIRV::Decoration::SpecId, DecArgs: {SpecId});
5436
5437 return true;
5438 }
5439 case Intrinsic::spv_const_composite: {
5440 // If no values are attached, the composite is null constant.
5441 bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
5442 SmallVector<Register> CompositeArgs;
5443 MRI->setRegClass(Reg: ResVReg, RC: GR.getRegClass(SpvType: ResType));
5444
5445 // skip type MD node we already used when generated assign.type for this
5446 if (!IsNull) {
5447 if (!wrapIntoSpecConstantOp(I, CompositeArgs))
5448 return false;
5449 std::function<bool(Register)> HasSpecConstOperand =
5450 [&](Register Reg) -> bool {
5451 MachineInstr *Def = MRI->getVRegDef(Reg);
5452 if (!Def)
5453 return false;
5454 if (!isConstReg(MRI, OpDef: Def))
5455 return true;
5456 // Recurse into not-yet-selected spv_const_composite intrinsics
5457 // to detect transitive spec constant operands.
5458 if (isSpvIntrinsic(MI: *Def, IntrinsicID: Intrinsic::spv_const_composite)) {
5459 for (unsigned J = Def->getNumExplicitDefs() + 1;
5460 J < Def->getNumExplicitOperands(); ++J) {
5461 if (Def->getOperand(i: J).isReg() &&
5462 HasSpecConstOperand(Def->getOperand(i: J).getReg()))
5463 return true;
5464 }
5465 }
5466 return false;
5467 };
5468 bool HasSpecConst = llvm::any_of(Range&: CompositeArgs, P: HasSpecConstOperand);
5469 unsigned CompositeOpc = HasSpecConst ? SPIRV::OpSpecConstantComposite
5470 : SPIRV::OpConstantComposite;
5471 unsigned ContinuedOpc = HasSpecConst
5472 ? SPIRV::OpSpecConstantCompositeContinuedINTEL
5473 : SPIRV::OpConstantCompositeContinuedINTEL;
5474 MachineIRBuilder MIR(I);
5475 SmallVector<MachineInstr *, 4> Instructions = createContinuedInstructions(
5476 MIRBuilder&: MIR, Opcode: CompositeOpc, MinWC: 3, ContinuedOpcode: ContinuedOpc, Args: CompositeArgs, ReturnRegister: ResVReg,
5477 TypeID: GR.getSPIRVTypeID(SpirvType: ResType));
5478 for (auto *Instr : Instructions) {
5479 Instr->setDebugLoc(I.getDebugLoc());
5480 constrainSelectedInstRegOperands(I&: *Instr, TII, TRI, RBI);
5481 }
5482 return true;
5483 } else {
5484 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpConstantNull))
5485 .addDef(RegNo: ResVReg)
5486 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
5487 MIB.constrainAllUses(TII, TRI, RBI);
5488 return true;
5489 }
5490 }
5491 case Intrinsic::spv_assign_name: {
5492 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpName));
5493 MIB.addUse(RegNo: I.getOperand(i: I.getNumExplicitDefs() + 1).getReg());
5494 for (unsigned i = I.getNumExplicitDefs() + 2;
5495 i < I.getNumExplicitOperands(); ++i) {
5496 MIB.addImm(Val: I.getOperand(i).getImm());
5497 }
5498 MIB.constrainAllUses(TII, TRI, RBI);
5499 return true;
5500 }
5501 case Intrinsic::spv_switch: {
5502 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpSwitch));
5503 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
5504 if (I.getOperand(i).isReg())
5505 MIB.addReg(RegNo: I.getOperand(i).getReg());
5506 else if (I.getOperand(i).isCImm())
5507 addNumImm(Imm: I.getOperand(i).getCImm()->getValue(), MIB);
5508 else if (I.getOperand(i).isMBB())
5509 MIB.addMBB(MBB: I.getOperand(i).getMBB());
5510 else
5511 llvm_unreachable("Unexpected OpSwitch operand");
5512 }
5513 MIB.constrainAllUses(TII, TRI, RBI);
5514 return true;
5515 }
5516 case Intrinsic::spv_loop_merge: {
5517 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpLoopMerge));
5518 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
5519 if (I.getOperand(i).isMBB())
5520 MIB.addMBB(MBB: I.getOperand(i).getMBB());
5521 else
5522 MIB.addImm(Val: foldImm(MO: I.getOperand(i), MRI));
5523 }
5524 MIB.constrainAllUses(TII, TRI, RBI);
5525 return true;
5526 }
5527 case Intrinsic::spv_loop_control_intel: {
5528 auto MIB =
5529 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpLoopControlINTEL));
5530 for (unsigned J = 1; J < I.getNumExplicitOperands(); ++J)
5531 MIB.addImm(Val: foldImm(MO: I.getOperand(i: J), MRI));
5532 MIB.constrainAllUses(TII, TRI, RBI);
5533 return true;
5534 }
5535 case Intrinsic::spv_selection_merge: {
5536 auto MIB =
5537 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpSelectionMerge));
5538 assert(I.getOperand(1).isMBB() &&
5539 "operand 1 to spv_selection_merge must be a basic block");
5540 MIB.addMBB(MBB: I.getOperand(i: 1).getMBB());
5541 MIB.addImm(Val: getSelectionOperandForImm(Imm: I.getOperand(i: 2).getImm()));
5542 MIB.constrainAllUses(TII, TRI, RBI);
5543 return true;
5544 }
5545 case Intrinsic::spv_cmpxchg:
5546 return selectAtomicCmpXchg(ResVReg, ResType, I);
5547 case Intrinsic::spv_unreachable:
5548 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpUnreachable))
5549 .constrainAllUses(TII, TRI, RBI);
5550 return true;
5551 case Intrinsic::spv_abort:
5552 return selectAbort(I);
5553 case Intrinsic::spv_alloca:
5554 return selectFrameIndex(ResVReg, ResType, I);
5555 case Intrinsic::spv_alloca_array:
5556 return selectAllocaArray(ResVReg, ResType, I);
5557 case Intrinsic::spv_assume:
5558 if (STI.canUseExtension(E: SPIRV::Extension::SPV_KHR_expect_assume)) {
5559 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpAssumeTrueKHR))
5560 .addUse(RegNo: I.getOperand(i: 1).getReg())
5561 .constrainAllUses(TII, TRI, RBI);
5562 return true;
5563 }
5564 break;
5565 case Intrinsic::spv_expect:
5566 if (STI.canUseExtension(E: SPIRV::Extension::SPV_KHR_expect_assume)) {
5567 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpExpectKHR))
5568 .addDef(RegNo: ResVReg)
5569 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5570 .addUse(RegNo: I.getOperand(i: 2).getReg())
5571 .addUse(RegNo: I.getOperand(i: 3).getReg())
5572 .constrainAllUses(TII, TRI, RBI);
5573 return true;
5574 }
5575 break;
5576 case Intrinsic::arithmetic_fence:
5577 if (STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_arithmetic_fence)) {
5578 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpArithmeticFenceEXT))
5579 .addDef(RegNo: ResVReg)
5580 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5581 .addUse(RegNo: I.getOperand(i: 2).getReg())
5582 .constrainAllUses(TII, TRI, RBI);
5583 return true;
5584 } else
5585 return BuildCOPY(DestReg: ResVReg, SrcReg: I.getOperand(i: 2).getReg(), I);
5586 break;
5587 case Intrinsic::spv_thread_id:
5588 // The HLSL SV_DispatchThreadID semantic is lowered to llvm.spv.thread.id
5589 // intrinsic in LLVM IR for SPIR-V backend.
5590 //
5591 // In SPIR-V backend, llvm.spv.thread.id is now correctly translated to a
5592 // `GlobalInvocationId` builtin variable
5593 return loadVec3BuiltinInputID(BuiltInValue: SPIRV::BuiltIn::GlobalInvocationId, ResVReg,
5594 ResType, I);
5595 case Intrinsic::spv_thread_id_in_group:
5596 // The HLSL SV_GroupThreadId semantic is lowered to
5597 // llvm.spv.thread.id.in.group intrinsic in LLVM IR for SPIR-V backend.
5598 //
5599 // In SPIR-V backend, llvm.spv.thread.id.in.group is now correctly
5600 // translated to a `LocalInvocationId` builtin variable
5601 return loadVec3BuiltinInputID(BuiltInValue: SPIRV::BuiltIn::LocalInvocationId, ResVReg,
5602 ResType, I);
5603 case Intrinsic::spv_group_id:
5604 // The HLSL SV_GroupId semantic is lowered to
5605 // llvm.spv.group.id intrinsic in LLVM IR for SPIR-V backend.
5606 //
5607 // In SPIR-V backend, llvm.spv.group.id is now translated to a `WorkgroupId`
5608 // builtin variable
5609 return loadVec3BuiltinInputID(BuiltInValue: SPIRV::BuiltIn::WorkgroupId, ResVReg, ResType,
5610 I);
5611 case Intrinsic::spv_flattened_thread_id_in_group:
5612 // The HLSL SV_GroupIndex semantic is lowered to
5613 // llvm.spv.flattened.thread.id.in.group() intrinsic in LLVM IR for SPIR-V
5614 // backend.
5615 //
5616 // In SPIR-V backend, llvm.spv.flattened.thread.id.in.group is translated to
5617 // a `LocalInvocationIndex` builtin variable
5618 return loadBuiltinInputID(BuiltInValue: SPIRV::BuiltIn::LocalInvocationIndex, ResVReg,
5619 ResType, I);
5620 case Intrinsic::spv_workgroup_size:
5621 return loadVec3BuiltinInputID(BuiltInValue: SPIRV::BuiltIn::WorkgroupSize, ResVReg,
5622 ResType, I);
5623 case Intrinsic::spv_global_size:
5624 return loadVec3BuiltinInputID(BuiltInValue: SPIRV::BuiltIn::GlobalSize, ResVReg, ResType,
5625 I);
5626 case Intrinsic::spv_global_offset:
5627 return loadVec3BuiltinInputID(BuiltInValue: SPIRV::BuiltIn::GlobalOffset, ResVReg,
5628 ResType, I);
5629 case Intrinsic::spv_num_workgroups:
5630 return loadVec3BuiltinInputID(BuiltInValue: SPIRV::BuiltIn::NumWorkgroups, ResVReg,
5631 ResType, I);
5632 case Intrinsic::spv_subgroup_size:
5633 return loadBuiltinInputID(BuiltInValue: SPIRV::BuiltIn::SubgroupSize, ResVReg, ResType,
5634 I);
5635 case Intrinsic::spv_num_subgroups:
5636 return loadBuiltinInputID(BuiltInValue: SPIRV::BuiltIn::NumSubgroups, ResVReg, ResType,
5637 I);
5638 case Intrinsic::spv_subgroup_id:
5639 return loadBuiltinInputID(BuiltInValue: SPIRV::BuiltIn::SubgroupId, ResVReg, ResType, I);
5640 case Intrinsic::spv_subgroup_local_invocation_id:
5641 return loadBuiltinInputID(BuiltInValue: SPIRV::BuiltIn::SubgroupLocalInvocationId,
5642 ResVReg, ResType, I);
5643 case Intrinsic::spv_subgroup_max_size:
5644 return loadBuiltinInputID(BuiltInValue: SPIRV::BuiltIn::SubgroupMaxSize, ResVReg, ResType,
5645 I);
5646 case Intrinsic::spv_fdot:
5647 return selectFloatDot(ResVReg, ResType, I);
5648 case Intrinsic::spv_udot:
5649 case Intrinsic::spv_sdot:
5650 if (STI.canUseExtension(E: SPIRV::Extension::SPV_KHR_integer_dot_product) ||
5651 STI.isAtLeastSPIRVVer(VerToCompareTo: VersionTuple(1, 6)))
5652 return selectIntegerDot(ResVReg, ResType, I,
5653 /*Signed=*/IID == Intrinsic::spv_sdot);
5654 return selectIntegerDotExpansion(ResVReg, ResType, I);
5655 case Intrinsic::spv_dot4add_i8packed:
5656 if (STI.canUseExtension(E: SPIRV::Extension::SPV_KHR_integer_dot_product) ||
5657 STI.isAtLeastSPIRVVer(VerToCompareTo: VersionTuple(1, 6)))
5658 return selectDot4AddPacked<true>(ResVReg, ResType, I);
5659 return selectDot4AddPackedExpansion<true>(ResVReg, ResType, I);
5660 case Intrinsic::spv_dot4add_u8packed:
5661 if (STI.canUseExtension(E: SPIRV::Extension::SPV_KHR_integer_dot_product) ||
5662 STI.isAtLeastSPIRVVer(VerToCompareTo: VersionTuple(1, 6)))
5663 return selectDot4AddPacked<false>(ResVReg, ResType, I);
5664 return selectDot4AddPackedExpansion<false>(ResVReg, ResType, I);
5665 case Intrinsic::spv_all:
5666 return selectAll(ResVReg, ResType, I);
5667 case Intrinsic::spv_any:
5668 return selectAny(ResVReg, ResType, I);
5669 case Intrinsic::spv_distance:
5670 return selectExtInst(ResVReg, ResType, I, CLInst: CL::distance, GLInst: GL::Distance);
5671 case Intrinsic::spv_lerp:
5672 return selectExtInst(ResVReg, ResType, I, CLInst: CL::mix, GLInst: GL::FMix);
5673 case Intrinsic::spv_length:
5674 return selectExtInst(ResVReg, ResType, I, CLInst: CL::length, GLInst: GL::Length);
5675 case Intrinsic::spv_degrees:
5676 return selectExtInst(ResVReg, ResType, I, CLInst: CL::degrees, GLInst: GL::Degrees);
5677 case Intrinsic::spv_faceforward:
5678 return selectExtInst(ResVReg, ResType, I, GLInst: GL::FaceForward);
5679 case Intrinsic::spv_frac:
5680 return selectExtInst(ResVReg, ResType, I, CLInst: CL::fract, GLInst: GL::Fract);
5681 case Intrinsic::spv_isinf:
5682 return selectOpIsInf(ResVReg, ResType, I);
5683 case Intrinsic::spv_isnan:
5684 return selectOpIsNan(ResVReg, ResType, I);
5685 case Intrinsic::spv_isfinite:
5686 return selectOpIsFinite(ResVReg, ResType, I);
5687 case Intrinsic::spv_isnormal:
5688 return selectOpIsNormal(ResVReg, ResType, I);
5689 case Intrinsic::spv_normalize:
5690 return selectExtInst(ResVReg, ResType, I, CLInst: CL::normalize, GLInst: GL::Normalize);
5691 case Intrinsic::spv_refract:
5692 return selectExtInst(ResVReg, ResType, I, GLInst: GL::Refract);
5693 case Intrinsic::spv_reflect:
5694 return selectExtInst(ResVReg, ResType, I, GLInst: GL::Reflect);
5695 case Intrinsic::spv_rsqrt:
5696 return selectExtInst(ResVReg, ResType, I, CLInst: CL::rsqrt, GLInst: GL::InverseSqrt);
5697 case Intrinsic::spv_sign:
5698 return selectSign(ResVReg, ResType, I);
5699 case Intrinsic::spv_smoothstep:
5700 return selectExtInst(ResVReg, ResType, I, CLInst: CL::smoothstep, GLInst: GL::SmoothStep);
5701 case Intrinsic::spv_firstbituhigh: // There is no CL equivalent of FindUMsb
5702 return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/false);
5703 case Intrinsic::spv_firstbitshigh: // There is no CL equivalent of FindSMsb
5704 return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/true);
5705 case Intrinsic::spv_firstbitlow: // There is no CL equivlent of FindILsb
5706 return selectFirstBitLow(ResVReg, ResType, I);
5707 case Intrinsic::spv_all_memory_barrier:
5708 return selectBarrierInst(I, Scope: SPIRV::Scope::Device,
5709 MemSem: SPIRV::MemorySemantics::UniformMemory |
5710 SPIRV::MemorySemantics::ImageMemory |
5711 SPIRV::MemorySemantics::WorkgroupMemory,
5712 /*WithGroupSync*/ false);
5713 case Intrinsic::spv_all_memory_barrier_with_group_sync:
5714 return selectBarrierInst(I, Scope: SPIRV::Scope::Device,
5715 MemSem: SPIRV::MemorySemantics::UniformMemory |
5716 SPIRV::MemorySemantics::ImageMemory |
5717 SPIRV::MemorySemantics::WorkgroupMemory,
5718 /*WithGroupSync*/ true);
5719 case Intrinsic::spv_device_memory_barrier:
5720 return selectBarrierInst(I, Scope: SPIRV::Scope::Device,
5721 MemSem: SPIRV::MemorySemantics::UniformMemory |
5722 SPIRV::MemorySemantics::ImageMemory,
5723 /*WithGroupSync*/ false);
5724 case Intrinsic::spv_device_memory_barrier_with_group_sync:
5725 return selectBarrierInst(I, Scope: SPIRV::Scope::Device,
5726 MemSem: SPIRV::MemorySemantics::UniformMemory |
5727 SPIRV::MemorySemantics::ImageMemory,
5728 /*WithGroupSync*/ true);
5729 case Intrinsic::spv_group_memory_barrier:
5730 return selectBarrierInst(I, Scope: SPIRV::Scope::Workgroup,
5731 MemSem: SPIRV::MemorySemantics::WorkgroupMemory,
5732 /*WithGroupSync*/ false);
5733 case Intrinsic::spv_group_memory_barrier_with_group_sync:
5734 return selectBarrierInst(I, Scope: SPIRV::Scope::Workgroup,
5735 MemSem: SPIRV::MemorySemantics::WorkgroupMemory,
5736 /*WithGroupSync*/ true);
5737 case Intrinsic::spv_generic_cast_to_ptr_explicit: {
5738 Register PtrReg = I.getOperand(i: I.getNumExplicitDefs() + 1).getReg();
5739 SPIRV::StorageClass::StorageClass ResSC =
5740 GR.getPointerStorageClass(Type: ResType);
5741 if (!isGenericCastablePtr(SC: ResSC))
5742 return diagnoseUnsupported(I, Msg: "The target storage class is not castable "
5743 "from the Generic storage class");
5744 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpGenericCastToPtrExplicit))
5745 .addDef(RegNo: ResVReg)
5746 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
5747 .addUse(RegNo: PtrReg)
5748 .addImm(Val: ResSC)
5749 .constrainAllUses(TII, TRI, RBI);
5750 return true;
5751 }
5752 case Intrinsic::spv_lifetime_start:
5753 case Intrinsic::spv_lifetime_end: {
5754 unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
5755 : SPIRV::OpLifetimeStop;
5756 int64_t Size = I.getOperand(i: I.getNumExplicitDefs() + 1).getImm();
5757 Register PtrReg = I.getOperand(i: I.getNumExplicitDefs() + 2).getReg();
5758 if (Size == -1)
5759 Size = 0;
5760 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: Op))
5761 .addUse(RegNo: PtrReg)
5762 .addImm(Val: Size)
5763 .constrainAllUses(TII, TRI, RBI);
5764 return true;
5765 }
5766 case Intrinsic::spv_saturate:
5767 return selectSaturate(ResVReg, ResType, I);
5768 case Intrinsic::spv_nclamp:
5769 return selectExtInst(ResVReg, ResType, I, CLInst: CL::fclamp, GLInst: GL::NClamp);
5770 case Intrinsic::spv_uclamp:
5771 return selectExtInst(ResVReg, ResType, I, CLInst: CL::u_clamp, GLInst: GL::UClamp);
5772 case Intrinsic::spv_sclamp:
5773 return selectExtInst(ResVReg, ResType, I, CLInst: CL::s_clamp, GLInst: GL::SClamp);
5774 case Intrinsic::spv_subgroup_prefix_bit_count:
5775 return selectWavePrefixBitCount(ResVReg, ResType, I);
5776 case Intrinsic::spv_wave_active_countbits:
5777 return selectWaveActiveCountBits(ResVReg, ResType, I);
5778 case Intrinsic::spv_wave_all_equal:
5779 return selectWaveActiveAllEqual(ResVReg, ResType, I);
5780 case Intrinsic::spv_wave_all:
5781 return selectWaveOpInst(ResVReg, ResType, I, Opcode: SPIRV::OpGroupNonUniformAll);
5782 case Intrinsic::spv_wave_any:
5783 return selectWaveOpInst(ResVReg, ResType, I, Opcode: SPIRV::OpGroupNonUniformAny);
5784 case Intrinsic::spv_subgroup_ballot:
5785 return selectWaveOpInst(ResVReg, ResType, I,
5786 Opcode: SPIRV::OpGroupNonUniformBallot);
5787 case Intrinsic::spv_wave_is_first_lane:
5788 return selectWaveOpInst(ResVReg, ResType, I, Opcode: SPIRV::OpGroupNonUniformElect);
5789 case Intrinsic::spv_wave_reduce_or:
5790 return selectWaveReduceOp(ResVReg, ResType, I,
5791 Opcode: SPIRV::OpGroupNonUniformBitwiseOr);
5792 case Intrinsic::spv_wave_reduce_xor:
5793 return selectWaveReduceOp(ResVReg, ResType, I,
5794 Opcode: SPIRV::OpGroupNonUniformBitwiseXor);
5795 case Intrinsic::spv_wave_reduce_and:
5796 return selectWaveReduceOp(ResVReg, ResType, I,
5797 Opcode: SPIRV::OpGroupNonUniformBitwiseAnd);
5798 case Intrinsic::spv_wave_reduce_umax:
5799 return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ true);
5800 case Intrinsic::spv_wave_reduce_max:
5801 return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ false);
5802 case Intrinsic::spv_wave_reduce_umin:
5803 return selectWaveReduceMin(ResVReg, ResType, I, /*IsUnsigned*/ true);
5804 case Intrinsic::spv_wave_reduce_min:
5805 return selectWaveReduceMin(ResVReg, ResType, I, /*IsUnsigned*/ false);
5806 case Intrinsic::spv_wave_reduce_sum:
5807 return selectWaveReduceSum(ResVReg, ResType, I);
5808 case Intrinsic::spv_wave_product:
5809 return selectWaveReduceProduct(ResVReg, ResType, I);
5810 case Intrinsic::spv_wave_readlane:
5811 return selectWaveOpInst(ResVReg, ResType, I,
5812 Opcode: SPIRV::OpGroupNonUniformShuffle);
5813 case Intrinsic::spv_wave_readlane_first:
5814 return selectWaveOpInst(ResVReg, ResType, I,
5815 Opcode: SPIRV::OpGroupNonUniformBroadcastFirst);
5816 case Intrinsic::spv_wave_prefix_sum:
5817 return selectWaveExclusiveScanSum(ResVReg, ResType, I);
5818 case Intrinsic::spv_wave_prefix_product:
5819 return selectWaveExclusiveScanProduct(ResVReg, ResType, I);
5820 case Intrinsic::spv_quad_read_across_x: {
5821 return selectQuadSwap(ResVReg, ResType, I, /*Direction*/ 0);
5822 }
5823 case Intrinsic::spv_quad_read_across_y: {
5824 return selectQuadSwap(ResVReg, ResType, I, /*Direction*/ 1);
5825 }
5826 case Intrinsic::spv_quad_read_across_diagonal: {
5827 return selectQuadSwap(ResVReg, ResType, I, /*Direction*/ 2);
5828 }
5829 case Intrinsic::spv_radians:
5830 return selectExtInst(ResVReg, ResType, I, CLInst: CL::radians, GLInst: GL::Radians);
5831 // Discard intrinsics which we do not expect to actually represent code after
5832 // lowering or intrinsics which are not implemented but should not crash when
5833 // found in a customer's LLVM IR input.
5834 case Intrinsic::instrprof_increment:
5835 case Intrinsic::instrprof_increment_step:
5836 case Intrinsic::instrprof_value_profile:
5837 break;
5838 // Discard internal intrinsics.
5839 case Intrinsic::spv_value_md:
5840 break;
5841 case Intrinsic::spv_resource_handlefrombinding: {
5842 return selectHandleFromBinding(ResVReg, ResType, I);
5843 }
5844 case Intrinsic::spv_resource_counterhandlefrombinding:
5845 return selectCounterHandleFromBinding(ResVReg, ResType, I);
5846 case Intrinsic::spv_resource_updatecounter:
5847 return selectUpdateCounter(ResVReg, ResType, I);
5848 case Intrinsic::spv_resource_store_typedbuffer: {
5849 return selectImageWriteIntrinsic(I);
5850 }
5851 case Intrinsic::spv_resource_load_typedbuffer: {
5852 return selectReadImageIntrinsic(ResVReg, ResType, I);
5853 }
5854 case Intrinsic::spv_resource_load_level: {
5855 return selectLoadLevelIntrinsic(ResVReg, ResType, I);
5856 }
5857 case Intrinsic::spv_resource_getdimensions_x:
5858 case Intrinsic::spv_resource_getdimensions_xy:
5859 case Intrinsic::spv_resource_getdimensions_xyz: {
5860 return selectGetDimensionsIntrinsic(ResVReg, ResType, I);
5861 }
5862 case Intrinsic::spv_resource_getdimensions_levels_x:
5863 case Intrinsic::spv_resource_getdimensions_levels_xy:
5864 case Intrinsic::spv_resource_getdimensions_levels_xyz: {
5865 return selectGetDimensionsLevelsIntrinsic(ResVReg, ResType, I);
5866 }
5867 case Intrinsic::spv_resource_getdimensions_ms_xy:
5868 case Intrinsic::spv_resource_getdimensions_ms_xyz: {
5869 return selectGetDimensionsMSIntrinsic(ResVReg, ResType, I);
5870 }
5871 case Intrinsic::spv_resource_calculate_lod:
5872 case Intrinsic::spv_resource_calculate_lod_unclamped:
5873 return selectCalculateLodIntrinsic(ResVReg, ResType, I);
5874 case Intrinsic::spv_resource_sample:
5875 case Intrinsic::spv_resource_sample_clamp:
5876 return selectSampleBasicIntrinsic(ResVReg, ResType, I);
5877 case Intrinsic::spv_resource_samplebias:
5878 case Intrinsic::spv_resource_samplebias_clamp:
5879 return selectSampleBiasIntrinsic(ResVReg, ResType, I);
5880 case Intrinsic::spv_resource_samplegrad:
5881 case Intrinsic::spv_resource_samplegrad_clamp:
5882 return selectSampleGradIntrinsic(ResVReg, ResType, I);
5883 case Intrinsic::spv_resource_samplelevel:
5884 return selectSampleLevelIntrinsic(ResVReg, ResType, I);
5885 case Intrinsic::spv_resource_samplecmp:
5886 case Intrinsic::spv_resource_samplecmp_clamp:
5887 return selectSampleCmpIntrinsic(ResVReg, ResType, I);
5888 case Intrinsic::spv_resource_samplecmplevelzero:
5889 return selectSampleCmpLevelZeroIntrinsic(ResVReg, ResType, I);
5890 case Intrinsic::spv_resource_gather:
5891 case Intrinsic::spv_resource_gather_cmp:
5892 return selectGatherIntrinsic(ResVReg, ResType, I);
5893 case Intrinsic::spv_resource_getbasepointer:
5894 case Intrinsic::spv_resource_getpointer: {
5895 return selectResourceGetPointer(ResVReg, ResType, I);
5896 }
5897 case Intrinsic::spv_pushconstant_getpointer: {
5898 return selectPushConstantGetPointer(ResVReg, ResType, I);
5899 }
5900 case Intrinsic::spv_discard: {
5901 return selectDiscard(ResVReg, ResType, I);
5902 }
5903 case Intrinsic::spv_resource_nonuniformindex: {
5904 return selectResourceNonUniformIndex(ResVReg, ResType, I);
5905 }
5906 case Intrinsic::spv_unpackhalf2x16: {
5907 return selectExtInst(ResVReg, ResType, I, GLInst: GL::UnpackHalf2x16);
5908 }
5909 case Intrinsic::spv_packhalf2x16: {
5910 return selectExtInst(ResVReg, ResType, I, GLInst: GL::PackHalf2x16);
5911 }
5912 case Intrinsic::spv_ddx:
5913 return selectDerivativeInst(ResVReg, ResType, I, DPdOpCode: SPIRV::OpDPdx);
5914 case Intrinsic::spv_ddy:
5915 return selectDerivativeInst(ResVReg, ResType, I, DPdOpCode: SPIRV::OpDPdy);
5916 case Intrinsic::spv_ddx_coarse:
5917 return selectDerivativeInst(ResVReg, ResType, I, DPdOpCode: SPIRV::OpDPdxCoarse);
5918 case Intrinsic::spv_ddy_coarse:
5919 return selectDerivativeInst(ResVReg, ResType, I, DPdOpCode: SPIRV::OpDPdyCoarse);
5920 case Intrinsic::spv_ddx_fine:
5921 return selectDerivativeInst(ResVReg, ResType, I, DPdOpCode: SPIRV::OpDPdxFine);
5922 case Intrinsic::spv_ddy_fine:
5923 return selectDerivativeInst(ResVReg, ResType, I, DPdOpCode: SPIRV::OpDPdyFine);
5924 case Intrinsic::spv_fwidth:
5925 return selectDerivativeInst(ResVReg, ResType, I, DPdOpCode: SPIRV::OpFwidth);
5926 case Intrinsic::spv_masked_gather:
5927 if (STI.canUseExtension(E: SPIRV::Extension::SPV_INTEL_masked_gather_scatter))
5928 return selectMaskedGather(ResVReg, ResType, I);
5929 return diagnoseUnsupported(
5930 I, Msg: "llvm.masked.gather requires SPV_INTEL_masked_gather_scatter");
5931 case Intrinsic::spv_masked_scatter:
5932 if (STI.canUseExtension(E: SPIRV::Extension::SPV_INTEL_masked_gather_scatter))
5933 return selectMaskedScatter(I);
5934 return diagnoseUnsupported(
5935 I, Msg: "llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter");
5936 case Intrinsic::returnaddress:
5937 case Intrinsic::frameaddress: {
5938 // SPIR-V does not have a stack or return address. Lower to null.
5939 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpConstantNull))
5940 .addDef(RegNo: ResVReg)
5941 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
5942 MIB.constrainAllUses(TII, TRI, RBI);
5943 return true;
5944 }
5945 default:
5946 return diagnoseUnsupported(I, Msg: "intrinsic selection not implemented.");
5947 }
5948 return true;
5949}
5950
5951bool SPIRVInstructionSelector::selectHandleFromBinding(Register &ResVReg,
5952 SPIRVTypeInst ResType,
5953 MachineInstr &I) const {
5954 // The images need to be loaded in the same basic block as their use. We defer
5955 // loading the image to the intrinsic that uses it.
5956 if (ResType->getOpcode() == SPIRV::OpTypeImage)
5957 return true;
5958
5959 return loadHandleBeforePosition(HandleReg&: ResVReg, ResType: GR.getSPIRVTypeForVReg(VReg: ResVReg),
5960 HandleDef&: *cast<GIntrinsic>(Val: &I), Pos&: I);
5961}
5962
5963bool SPIRVInstructionSelector::selectCounterHandleFromBinding(
5964 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5965 auto &Intr = cast<GIntrinsic>(Val&: I);
5966 assert(Intr.getIntrinsicID() ==
5967 Intrinsic::spv_resource_counterhandlefrombinding);
5968
5969 // Extract information from the intrinsic call.
5970 Register MainHandleReg = Intr.getOperand(i: 2).getReg();
5971 auto *MainHandleDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: MainHandleReg));
5972 assert(MainHandleDef->getIntrinsicID() ==
5973 Intrinsic::spv_resource_handlefrombinding);
5974
5975 uint32_t Set = getIConstVal(ConstReg: Intr.getOperand(i: 3).getReg(), MRI);
5976 uint32_t Binding = getIConstVal(ConstReg: Intr.getOperand(i: 4).getReg(), MRI);
5977 uint32_t ArraySize = getIConstVal(ConstReg: MainHandleDef->getOperand(i: 4).getReg(), MRI);
5978 Register IndexReg = MainHandleDef->getOperand(i: 5).getReg();
5979 std::string CounterName =
5980 getStringValueFromReg(Reg: MainHandleDef->getOperand(i: 6).getReg(), MRI&: *MRI) +
5981 ".counter";
5982
5983 // Create the counter variable.
5984 MachineIRBuilder MIRBuilder(I);
5985 Register CounterVarReg =
5986 buildPointerToResource(ResType: SPIRVTypeInst(GR.getPointeeType(PtrType: ResType)),
5987 SC: GR.getPointerStorageClass(Type: ResType), Set, Binding,
5988 ArraySize, IndexReg, Name: CounterName, MIRBuilder);
5989
5990 return BuildCOPY(DestReg: ResVReg, SrcReg: CounterVarReg, I);
5991}
5992
5993bool SPIRVInstructionSelector::selectUpdateCounter(Register &ResVReg,
5994 SPIRVTypeInst ResType,
5995 MachineInstr &I) const {
5996 auto &Intr = cast<GIntrinsic>(Val&: I);
5997 assert(Intr.getIntrinsicID() == Intrinsic::spv_resource_updatecounter);
5998
5999 Register CounterHandleReg = Intr.getOperand(i: 2).getReg();
6000 Register IncrReg = Intr.getOperand(i: 3).getReg();
6001
6002 // The counter handle is a pointer to the counter variable (which is a struct
6003 // containing an i32). We need to get a pointer to that i32 member to do the
6004 // atomic operation.
6005#ifndef NDEBUG
6006 SPIRVTypeInst CounterVarType = GR.getSPIRVTypeForVReg(CounterHandleReg);
6007 SPIRVTypeInst CounterVarPointeeType = GR.getPointeeType(CounterVarType);
6008 assert(CounterVarPointeeType &&
6009 CounterVarPointeeType->getOpcode() == SPIRV::OpTypeStruct &&
6010 "Counter variable must be a struct");
6011 assert(GR.getPointerStorageClass(CounterVarType) ==
6012 SPIRV::StorageClass::StorageBuffer &&
6013 "Counter variable must be in the storage buffer storage class");
6014 assert(CounterVarPointeeType->getNumOperands() == 2 &&
6015 "Counter variable must have exactly 1 member in the struct");
6016 const SPIRVTypeInst MemberType =
6017 GR.getSPIRVTypeForVReg(CounterVarPointeeType->getOperand(1).getReg());
6018 assert(MemberType->getOpcode() == SPIRV::OpTypeInt &&
6019 "Counter variable struct must have a single i32 member");
6020#endif
6021
6022 // The struct has a single i32 member.
6023 MachineIRBuilder MIRBuilder(I);
6024 const Type *LLVMIntType =
6025 Type::getInt32Ty(C&: I.getMF()->getFunction().getContext());
6026
6027 SPIRVTypeInst IntPtrType = GR.getOrCreateSPIRVPointerType(
6028 BaseType: LLVMIntType, MIRBuilder, SC: SPIRV::StorageClass::StorageBuffer);
6029
6030 Register Zero = buildI32Constant(Val: 0, I);
6031
6032 Register PtrToCounter =
6033 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: IntPtrType));
6034 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpAccessChain))
6035 .addDef(RegNo: PtrToCounter)
6036 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: IntPtrType))
6037 .addUse(RegNo: CounterHandleReg)
6038 .addUse(RegNo: Zero)
6039 .constrainAllUses(TII, TRI, RBI);
6040
6041 // For UAV/SSBO counters, the scope is Device. The counter variable is not
6042 // used as a flag. So the memory semantics can be None.
6043 Register Scope = buildI32Constant(Val: SPIRV::Scope::Device, I);
6044 Register Semantics = buildI32Constant(Val: SPIRV::MemorySemantics::None, I);
6045
6046 int64_t IncrVal = getIConstValSext(ConstReg: IncrReg, MRI);
6047 Register Incr = buildI32Constant(Val: static_cast<uint32_t>(IncrVal), I);
6048
6049 Register AtomicRes = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
6050 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpAtomicIAdd))
6051 .addDef(RegNo: AtomicRes)
6052 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6053 .addUse(RegNo: PtrToCounter)
6054 .addUse(RegNo: Scope)
6055 .addUse(RegNo: Semantics)
6056 .addUse(RegNo: Incr)
6057 .constrainAllUses(TII, TRI, RBI);
6058 if (IncrVal >= 0) {
6059 return BuildCOPY(DestReg: ResVReg, SrcReg: AtomicRes, I);
6060 }
6061
6062 // In HLSL, IncrementCounter returns the value *before* the increment, while
6063 // DecrementCounter returns the value *after* the decrement. Both are lowered
6064 // to the same atomic intrinsic which returns the value *before* the
6065 // operation. So for decrements (negative IncrVal), we must subtract the
6066 // increment value from the result to get the post-decrement value.
6067 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpIAddS))
6068 .addDef(RegNo: ResVReg)
6069 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6070 .addUse(RegNo: AtomicRes)
6071 .addUse(RegNo: Incr)
6072 .constrainAllUses(TII, TRI, RBI);
6073 return true;
6074}
6075bool SPIRVInstructionSelector::selectReadImageIntrinsic(Register &ResVReg,
6076 SPIRVTypeInst ResType,
6077 MachineInstr &I) const {
6078
6079 // If the load of the image is in a different basic block, then
6080 // this will generate invalid code. A proper solution is to move
6081 // the OpLoad from selectHandleFromBinding here. However, to do
6082 // that we will need to change the return type of the intrinsic.
6083 // We will do that when we can, but for now trying to move forward with other
6084 // issues.
6085 Register ImageReg = I.getOperand(i: 2).getReg();
6086 auto *ImageDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: ImageReg));
6087 Register NewImageReg = MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: ImageReg));
6088 if (!loadHandleBeforePosition(HandleReg&: NewImageReg, ResType: GR.getSPIRVTypeForVReg(VReg: ImageReg),
6089 HandleDef&: *ImageDef, Pos&: I)) {
6090 return false;
6091 }
6092
6093 Register IdxReg = I.getOperand(i: 3).getReg();
6094 DebugLoc Loc = I.getDebugLoc();
6095 MachineInstr &Pos = I;
6096
6097 return generateImageReadOrFetch(ResVReg, ResType, ImageReg: NewImageReg, IdxReg, Loc,
6098 Pos);
6099}
6100
6101bool SPIRVInstructionSelector::generateSampleImage(
6102 Register ResVReg, SPIRVTypeInst ResType, Register ImageReg,
6103 Register SamplerReg, Register CoordinateReg, const ImageOperands &ImOps,
6104 DebugLoc Loc, MachineInstr &Pos) const {
6105 auto *ImageDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: ImageReg));
6106 Register NewImageReg = MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: ImageReg));
6107 if (!loadHandleBeforePosition(HandleReg&: NewImageReg, ResType: GR.getSPIRVTypeForVReg(VReg: ImageReg),
6108 HandleDef&: *ImageDef, Pos)) {
6109 return false;
6110 }
6111
6112 auto *SamplerDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: SamplerReg));
6113 Register NewSamplerReg =
6114 MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: SamplerReg));
6115 if (!loadHandleBeforePosition(HandleReg&: NewSamplerReg,
6116 ResType: GR.getSPIRVTypeForVReg(VReg: SamplerReg), HandleDef&: *SamplerDef,
6117 Pos)) {
6118 return false;
6119 }
6120
6121 MachineIRBuilder MIRBuilder(Pos);
6122 SPIRVTypeInst SampledImageType = GR.getOrCreateOpTypeSampledImage(
6123 ImageType: GR.getSPIRVTypeForVReg(VReg: ImageReg), MIRBuilder);
6124 Register SampledImageReg =
6125 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: SampledImageType));
6126
6127 BuildMI(BB&: *Pos.getParent(), I&: Pos, MIMD: Loc, MCID: TII.get(Opcode: SPIRV::OpSampledImage))
6128 .addDef(RegNo: SampledImageReg)
6129 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: SampledImageType))
6130 .addUse(RegNo: NewImageReg)
6131 .addUse(RegNo: NewSamplerReg)
6132 .constrainAllUses(TII, TRI, RBI);
6133
6134 bool IsExplicitLod = ImOps.GradX.has_value() || ImOps.GradY.has_value() ||
6135 ImOps.Lod.has_value();
6136 unsigned Opcode = IsExplicitLod ? SPIRV::OpImageSampleExplicitLod
6137 : SPIRV::OpImageSampleImplicitLod;
6138 if (ImOps.Compare)
6139 Opcode = IsExplicitLod ? SPIRV::OpImageSampleDrefExplicitLod
6140 : SPIRV::OpImageSampleDrefImplicitLod;
6141
6142 auto MIB = BuildMI(BB&: *Pos.getParent(), I&: Pos, MIMD: Loc, MCID: TII.get(Opcode))
6143 .addDef(RegNo: ResVReg)
6144 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6145 .addUse(RegNo: SampledImageReg)
6146 .addUse(RegNo: CoordinateReg);
6147
6148 if (ImOps.Compare)
6149 MIB.addUse(RegNo: *ImOps.Compare);
6150
6151 uint32_t ImageOperands = 0;
6152 if (ImOps.Bias)
6153 ImageOperands |= SPIRV::ImageOperand::Bias;
6154 if (ImOps.Lod)
6155 ImageOperands |= SPIRV::ImageOperand::Lod;
6156 if (ImOps.GradX && ImOps.GradY)
6157 ImageOperands |= SPIRV::ImageOperand::Grad;
6158 if (ImOps.Offset && !isScalarOrVectorIntConstantZero(Reg: *ImOps.Offset)) {
6159 if (isConstReg(MRI, OpReg: *ImOps.Offset))
6160 ImageOperands |= SPIRV::ImageOperand::ConstOffset;
6161 else {
6162 Pos.emitGenericError(
6163 ErrMsg: "Non-constant offsets are not supported in sample instructions.");
6164 return false;
6165 }
6166 }
6167 if (ImOps.MinLod)
6168 ImageOperands |= SPIRV::ImageOperand::MinLod;
6169
6170 if (ImageOperands != 0) {
6171 MIB.addImm(Val: ImageOperands);
6172 if (ImageOperands & SPIRV::ImageOperand::Bias)
6173 MIB.addUse(RegNo: *ImOps.Bias);
6174 if (ImageOperands & SPIRV::ImageOperand::Lod)
6175 MIB.addUse(RegNo: *ImOps.Lod);
6176 if (ImageOperands & SPIRV::ImageOperand::Grad) {
6177 MIB.addUse(RegNo: *ImOps.GradX);
6178 MIB.addUse(RegNo: *ImOps.GradY);
6179 }
6180 if (ImageOperands &
6181 (SPIRV::ImageOperand::ConstOffset | SPIRV::ImageOperand::Offset))
6182 MIB.addUse(RegNo: *ImOps.Offset);
6183 if (ImageOperands & SPIRV::ImageOperand::MinLod)
6184 MIB.addUse(RegNo: *ImOps.MinLod);
6185 }
6186
6187 MIB.constrainAllUses(TII, TRI, RBI);
6188 return true;
6189}
6190
6191bool SPIRVInstructionSelector::selectImageQuerySize(
6192 Register ImageReg, Register &ResVReg, MachineInstr &I,
6193 std::optional<Register> LodReg) const {
6194 unsigned Opcode =
6195 LodReg ? SPIRV::OpImageQuerySizeLod : SPIRV::OpImageQuerySize;
6196 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(VReg: ImageReg);
6197 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
6198 "ImageReg is not an image type.");
6199
6200 auto Dim = static_cast<SPIRV::Dim::Dim>(ImageType->getOperand(i: 2).getImm());
6201 bool IsArray = ImageType->getOperand(i: 4).getImm() != 0;
6202 unsigned NumComponents = 0;
6203 switch (Dim) {
6204 case SPIRV::Dim::DIM_1D:
6205 case SPIRV::Dim::DIM_Buffer:
6206 NumComponents = IsArray ? 2 : 1;
6207 break;
6208 case SPIRV::Dim::DIM_2D:
6209 case SPIRV::Dim::DIM_Cube:
6210 case SPIRV::Dim::DIM_Rect:
6211 NumComponents = IsArray ? 3 : 2;
6212 break;
6213 case SPIRV::Dim::DIM_3D:
6214 NumComponents = 3;
6215 break;
6216 default:
6217 I.emitGenericError(ErrMsg: "Unsupported image dimension for OpImageQuerySize.");
6218 return false;
6219 }
6220
6221 SPIRVTypeInst I32Ty = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
6222 SPIRVTypeInst ResType =
6223 NumComponents == 1
6224 ? I32Ty
6225 : GR.getOrCreateSPIRVVectorType(BaseType: I32Ty, NumElements: NumComponents, I, TII);
6226
6227 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
6228 .addDef(RegNo: ResVReg)
6229 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6230 .addUse(RegNo: ImageReg);
6231 if (LodReg)
6232 MIB.addUse(RegNo: *LodReg);
6233 MIB.constrainAllUses(TII, TRI, RBI);
6234 return true;
6235}
6236
6237bool SPIRVInstructionSelector::selectGetDimensionsIntrinsic(
6238 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6239 Register ImageReg = I.getOperand(i: 2).getReg();
6240 auto *ImageDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: ImageReg));
6241 Register NewImageReg = MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: ImageReg));
6242 if (!loadHandleBeforePosition(HandleReg&: NewImageReg, ResType: GR.getSPIRVTypeForVReg(VReg: ImageReg),
6243 HandleDef&: *ImageDef, Pos&: I)) {
6244 return false;
6245 }
6246 return selectImageQuerySize(ImageReg: NewImageReg, ResVReg, I);
6247}
6248
6249bool SPIRVInstructionSelector::selectGetDimensionsLevelsIntrinsic(
6250 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6251 Register ImageReg = I.getOperand(i: 2).getReg();
6252 auto *ImageDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: ImageReg));
6253 Register NewImageReg = MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: ImageReg));
6254 if (!loadHandleBeforePosition(HandleReg&: NewImageReg, ResType: GR.getSPIRVTypeForVReg(VReg: ImageReg),
6255 HandleDef&: *ImageDef, Pos&: I)) {
6256 return false;
6257 }
6258
6259 Register SizeReg = MRI->createVirtualRegister(RegClass: &SPIRV::iIDRegClass);
6260 Register LodReg = I.getOperand(i: 3).getReg();
6261
6262 assert(GR.getSPIRVTypeForVReg(NewImageReg)->getOperand(6).getImm() == 1 &&
6263 "OpImageQuerySizeLod and OpImageQueryLevels require a sampled image");
6264
6265 if (!selectImageQuerySize(ImageReg: NewImageReg, ResVReg&: SizeReg, I, LodReg)) {
6266 return false;
6267 }
6268
6269 SPIRVTypeInst I32Ty = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
6270 Register LevelsReg = MRI->createVirtualRegister(RegClass: &SPIRV::iIDRegClass);
6271 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
6272 MCID: TII.get(Opcode: SPIRV::OpImageQueryLevels))
6273 .addDef(RegNo: LevelsReg)
6274 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: I32Ty))
6275 .addUse(RegNo: NewImageReg)
6276 .constrainAllUses(TII, TRI, RBI);
6277
6278 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
6279 MCID: TII.get(Opcode: SPIRV::OpCompositeConstruct))
6280 .addDef(RegNo: ResVReg)
6281 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6282 .addUse(RegNo: SizeReg)
6283 .addUse(RegNo: LevelsReg)
6284 .constrainAllUses(TII, TRI, RBI);
6285
6286 return true;
6287}
6288
6289bool SPIRVInstructionSelector::selectGetDimensionsMSIntrinsic(
6290 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6291 Register ImageReg = I.getOperand(i: 2).getReg();
6292 auto *ImageDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: ImageReg));
6293 Register NewImageReg = MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: ImageReg));
6294 if (!loadHandleBeforePosition(HandleReg&: NewImageReg, ResType: GR.getSPIRVTypeForVReg(VReg: ImageReg),
6295 HandleDef&: *ImageDef, Pos&: I)) {
6296 return false;
6297 }
6298
6299 Register SizeReg = MRI->createVirtualRegister(RegClass: &SPIRV::iIDRegClass);
6300
6301 assert(GR.getSPIRVTypeForVReg(NewImageReg)->getOperand(5).getImm() == 1 &&
6302 "OpImageQuerySamples requires a multisampled image");
6303
6304 if (!selectImageQuerySize(ImageReg: NewImageReg, ResVReg&: SizeReg, I)) {
6305 return false;
6306 }
6307
6308 Register SamplesReg = MRI->createVirtualRegister(RegClass: &SPIRV::iIDRegClass);
6309
6310 SPIRVTypeInst I32Ty = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
6311 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
6312 MCID: TII.get(Opcode: SPIRV::OpImageQuerySamples))
6313 .addDef(RegNo: SamplesReg)
6314 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: I32Ty))
6315 .addUse(RegNo: NewImageReg)
6316 .constrainAllUses(TII, TRI, RBI);
6317
6318 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
6319 MCID: TII.get(Opcode: SPIRV::OpCompositeConstruct))
6320 .addDef(RegNo: ResVReg)
6321 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6322 .addUse(RegNo: SizeReg)
6323 .addUse(RegNo: SamplesReg)
6324 .constrainAllUses(TII, TRI, RBI);
6325
6326 return true;
6327}
6328
6329bool SPIRVInstructionSelector::selectCalculateLodIntrinsic(
6330 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6331 Register ImageReg = I.getOperand(i: 2).getReg();
6332 Register SamplerReg = I.getOperand(i: 3).getReg();
6333 Register CoordinateReg = I.getOperand(i: 4).getReg();
6334
6335 auto *ImageDef = dyn_cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: ImageReg));
6336 if (!ImageDef)
6337 return false;
6338 Register NewImageReg = MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: ImageReg));
6339 if (!loadHandleBeforePosition(HandleReg&: NewImageReg, ResType: GR.getSPIRVTypeForVReg(VReg: ImageReg),
6340 HandleDef&: *ImageDef, Pos&: I)) {
6341 return false;
6342 }
6343
6344 auto *SamplerDef = dyn_cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: SamplerReg));
6345 if (!SamplerDef)
6346 return false;
6347 Register NewSamplerReg =
6348 MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: SamplerReg));
6349 if (!loadHandleBeforePosition(
6350 HandleReg&: NewSamplerReg, ResType: GR.getSPIRVTypeForVReg(VReg: SamplerReg), HandleDef&: *SamplerDef, Pos&: I)) {
6351 return false;
6352 }
6353
6354 MachineIRBuilder MIRBuilder(I);
6355 SPIRVTypeInst SampledImageType = GR.getOrCreateOpTypeSampledImage(
6356 ImageType: GR.getSPIRVTypeForVReg(VReg: ImageReg), MIRBuilder);
6357 Register SampledImageReg =
6358 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: SampledImageType));
6359
6360 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpSampledImage))
6361 .addDef(RegNo: SampledImageReg)
6362 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: SampledImageType))
6363 .addUse(RegNo: NewImageReg)
6364 .addUse(RegNo: NewSamplerReg)
6365 .constrainAllUses(TII, TRI, RBI);
6366
6367 SPIRVTypeInst Vec2Ty = GR.getOrCreateSPIRVVectorType(BaseType: ResType, NumElements: 2, I, TII);
6368 Register QueryResultReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: Vec2Ty));
6369
6370 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpImageQueryLod))
6371 .addDef(RegNo: QueryResultReg)
6372 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: Vec2Ty))
6373 .addUse(RegNo: SampledImageReg)
6374 .addUse(RegNo: CoordinateReg)
6375 .constrainAllUses(TII, TRI, RBI);
6376
6377 unsigned ExtractedIndex =
6378 cast<GIntrinsic>(Val&: I).getIntrinsicID() ==
6379 Intrinsic::spv_resource_calculate_lod_unclamped
6380 ? 1
6381 : 0;
6382
6383 MachineInstrBuilder MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
6384 MCID: TII.get(Opcode: SPIRV::OpCompositeExtract))
6385 .addDef(RegNo: ResVReg)
6386 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6387 .addUse(RegNo: QueryResultReg)
6388 .addImm(Val: ExtractedIndex);
6389
6390 MIB.constrainAllUses(TII, TRI, RBI);
6391 return true;
6392}
6393
6394bool SPIRVInstructionSelector::selectSampleBasicIntrinsic(
6395 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6396 Register ImageReg = I.getOperand(i: 2).getReg();
6397 Register SamplerReg = I.getOperand(i: 3).getReg();
6398 Register CoordinateReg = I.getOperand(i: 4).getReg();
6399 ImageOperands ImOps;
6400 if (I.getNumOperands() > 5)
6401 ImOps.Offset = I.getOperand(i: 5).getReg();
6402 if (I.getNumOperands() > 6)
6403 ImOps.MinLod = I.getOperand(i: 6).getReg();
6404 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6405 CoordinateReg, ImOps, Loc: I.getDebugLoc(), Pos&: I);
6406}
6407
6408bool SPIRVInstructionSelector::selectSampleBiasIntrinsic(
6409 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6410 Register ImageReg = I.getOperand(i: 2).getReg();
6411 Register SamplerReg = I.getOperand(i: 3).getReg();
6412 Register CoordinateReg = I.getOperand(i: 4).getReg();
6413 ImageOperands ImOps;
6414 ImOps.Bias = I.getOperand(i: 5).getReg();
6415 if (I.getNumOperands() > 6)
6416 ImOps.Offset = I.getOperand(i: 6).getReg();
6417 if (I.getNumOperands() > 7)
6418 ImOps.MinLod = I.getOperand(i: 7).getReg();
6419 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6420 CoordinateReg, ImOps, Loc: I.getDebugLoc(), Pos&: I);
6421}
6422
6423bool SPIRVInstructionSelector::selectSampleGradIntrinsic(
6424 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6425 Register ImageReg = I.getOperand(i: 2).getReg();
6426 Register SamplerReg = I.getOperand(i: 3).getReg();
6427 Register CoordinateReg = I.getOperand(i: 4).getReg();
6428 ImageOperands ImOps;
6429 ImOps.GradX = I.getOperand(i: 5).getReg();
6430 ImOps.GradY = I.getOperand(i: 6).getReg();
6431 if (I.getNumOperands() > 7)
6432 ImOps.Offset = I.getOperand(i: 7).getReg();
6433 if (I.getNumOperands() > 8)
6434 ImOps.MinLod = I.getOperand(i: 8).getReg();
6435 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6436 CoordinateReg, ImOps, Loc: I.getDebugLoc(), Pos&: I);
6437}
6438
6439bool SPIRVInstructionSelector::selectSampleLevelIntrinsic(
6440 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6441 Register ImageReg = I.getOperand(i: 2).getReg();
6442 Register SamplerReg = I.getOperand(i: 3).getReg();
6443 Register CoordinateReg = I.getOperand(i: 4).getReg();
6444 ImageOperands ImOps;
6445 ImOps.Lod = I.getOperand(i: 5).getReg();
6446 if (I.getNumOperands() > 6)
6447 ImOps.Offset = I.getOperand(i: 6).getReg();
6448 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6449 CoordinateReg, ImOps, Loc: I.getDebugLoc(), Pos&: I);
6450}
6451
6452bool SPIRVInstructionSelector::selectSampleCmpIntrinsic(Register &ResVReg,
6453 SPIRVTypeInst ResType,
6454 MachineInstr &I) const {
6455 Register ImageReg = I.getOperand(i: 2).getReg();
6456 Register SamplerReg = I.getOperand(i: 3).getReg();
6457 Register CoordinateReg = I.getOperand(i: 4).getReg();
6458 ImageOperands ImOps;
6459 ImOps.Compare = I.getOperand(i: 5).getReg();
6460 if (I.getNumOperands() > 6)
6461 ImOps.Offset = I.getOperand(i: 6).getReg();
6462 if (I.getNumOperands() > 7)
6463 ImOps.MinLod = I.getOperand(i: 7).getReg();
6464 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6465 CoordinateReg, ImOps, Loc: I.getDebugLoc(), Pos&: I);
6466}
6467
6468bool SPIRVInstructionSelector::selectLoadLevelIntrinsic(Register &ResVReg,
6469 SPIRVTypeInst ResType,
6470 MachineInstr &I) const {
6471 Register ImageReg = I.getOperand(i: 2).getReg();
6472 Register CoordinateReg = I.getOperand(i: 3).getReg();
6473 Register LodReg = I.getOperand(i: 4).getReg();
6474
6475 ImageOperands ImOps;
6476 ImOps.Lod = LodReg;
6477 if (I.getNumOperands() > 5)
6478 ImOps.Offset = I.getOperand(i: 5).getReg();
6479
6480 auto *ImageDef = dyn_cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: ImageReg));
6481 if (!ImageDef)
6482 return false;
6483
6484 Register NewImageReg = MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: ImageReg));
6485 if (!loadHandleBeforePosition(HandleReg&: NewImageReg, ResType: GR.getSPIRVTypeForVReg(VReg: ImageReg),
6486 HandleDef&: *ImageDef, Pos&: I)) {
6487 return false;
6488 }
6489
6490 return generateImageReadOrFetch(ResVReg, ResType, ImageReg: NewImageReg, IdxReg: CoordinateReg,
6491 Loc: I.getDebugLoc(), Pos&: I, ImOps: &ImOps);
6492}
6493
6494bool SPIRVInstructionSelector::selectSampleCmpLevelZeroIntrinsic(
6495 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6496 Register ImageReg = I.getOperand(i: 2).getReg();
6497 Register SamplerReg = I.getOperand(i: 3).getReg();
6498 Register CoordinateReg = I.getOperand(i: 4).getReg();
6499 ImageOperands ImOps;
6500 ImOps.Compare = I.getOperand(i: 5).getReg();
6501 if (I.getNumOperands() > 6)
6502 ImOps.Offset = I.getOperand(i: 6).getReg();
6503 SPIRVTypeInst FloatTy = GR.getOrCreateSPIRVFloatType(BitWidth: 32, I, TII);
6504 ImOps.Lod = GR.getOrCreateConstFP(Val: APFloat(0.0f), I, SpvType: FloatTy, TII);
6505 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6506 CoordinateReg, ImOps, Loc: I.getDebugLoc(), Pos&: I);
6507}
6508
6509bool SPIRVInstructionSelector::selectGatherIntrinsic(Register &ResVReg,
6510 SPIRVTypeInst ResType,
6511 MachineInstr &I) const {
6512 Register ImageReg = I.getOperand(i: 2).getReg();
6513 Register SamplerReg = I.getOperand(i: 3).getReg();
6514 Register CoordinateReg = I.getOperand(i: 4).getReg();
6515 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(VReg: ImageReg);
6516 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
6517 "ImageReg is not an image type.");
6518
6519 Register ComponentOrCompareReg;
6520 Register OffsetReg;
6521
6522 ComponentOrCompareReg = I.getOperand(i: 5).getReg();
6523 OffsetReg = I.getOperand(i: 6).getReg();
6524 auto *ImageDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: ImageReg));
6525 Register NewImageReg = MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: ImageReg));
6526 if (!loadHandleBeforePosition(HandleReg&: NewImageReg, ResType: ImageType, HandleDef&: *ImageDef, Pos&: I)) {
6527 return false;
6528 }
6529
6530 auto Dim = static_cast<SPIRV::Dim::Dim>(ImageType->getOperand(i: 2).getImm());
6531 if (Dim != SPIRV::Dim::DIM_2D && Dim != SPIRV::Dim::DIM_Cube &&
6532 Dim != SPIRV::Dim::DIM_Rect) {
6533 I.emitGenericError(
6534 ErrMsg: "Gather operations are only supported for 2D, Cube, and Rect images.");
6535 return false;
6536 }
6537
6538 auto *SamplerDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: SamplerReg));
6539 Register NewSamplerReg =
6540 MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: SamplerReg));
6541 if (!loadHandleBeforePosition(
6542 HandleReg&: NewSamplerReg, ResType: GR.getSPIRVTypeForVReg(VReg: SamplerReg), HandleDef&: *SamplerDef, Pos&: I)) {
6543 return false;
6544 }
6545
6546 MachineIRBuilder MIRBuilder(I);
6547 SPIRVTypeInst SampledImageType =
6548 GR.getOrCreateOpTypeSampledImage(ImageType, MIRBuilder);
6549 Register SampledImageReg =
6550 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: SampledImageType));
6551
6552 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpSampledImage))
6553 .addDef(RegNo: SampledImageReg)
6554 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: SampledImageType))
6555 .addUse(RegNo: NewImageReg)
6556 .addUse(RegNo: NewSamplerReg)
6557 .constrainAllUses(TII, TRI, RBI);
6558
6559 auto IntrId = cast<GIntrinsic>(Val&: I).getIntrinsicID();
6560 bool IsGatherCmp = IntrId == Intrinsic::spv_resource_gather_cmp;
6561 unsigned Opcode =
6562 IsGatherCmp ? SPIRV::OpImageDrefGather : SPIRV::OpImageGather;
6563
6564 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
6565 .addDef(RegNo: ResVReg)
6566 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6567 .addUse(RegNo: SampledImageReg)
6568 .addUse(RegNo: CoordinateReg)
6569 .addUse(RegNo: ComponentOrCompareReg);
6570
6571 uint32_t ImageOperands = 0;
6572 if (OffsetReg && !isScalarOrVectorIntConstantZero(Reg: OffsetReg)) {
6573 if (Dim == SPIRV::Dim::DIM_Cube) {
6574 I.emitGenericError(
6575 ErrMsg: "Gather operations with offset are not supported for Cube images.");
6576 return false;
6577 }
6578 if (isConstReg(MRI, OpReg: OffsetReg))
6579 ImageOperands |= SPIRV::ImageOperand::ConstOffset;
6580 else {
6581 ImageOperands |= SPIRV::ImageOperand::Offset;
6582 }
6583 }
6584
6585 if (ImageOperands != 0) {
6586 MIB.addImm(Val: ImageOperands);
6587 if (ImageOperands &
6588 (SPIRV::ImageOperand::ConstOffset | SPIRV::ImageOperand::Offset))
6589 MIB.addUse(RegNo: OffsetReg);
6590 }
6591
6592 MIB.constrainAllUses(TII, TRI, RBI);
6593 return true;
6594}
6595
6596bool SPIRVInstructionSelector::generateImageReadOrFetch(
6597 Register &ResVReg, SPIRVTypeInst ResType, Register ImageReg,
6598 Register IdxReg, DebugLoc Loc, MachineInstr &Pos,
6599 const ImageOperands *ImOps) const {
6600 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(VReg: ImageReg);
6601 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
6602 "ImageReg is not an image type.");
6603
6604 bool IsSignedInteger =
6605 sampledTypeIsSignedInteger(HandleType: GR.getTypeForSPIRVType(Ty: ImageType));
6606 // Check if the "sampled" operand of the image type is 1.
6607 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpImageFetch
6608 auto SampledOp = ImageType->getOperand(i: 6);
6609 bool IsFetch = (SampledOp.getImm() == 1);
6610
6611 auto AddOperands = [&](MachineInstrBuilder &MIB) {
6612 uint32_t ImageOperandsMask = 0;
6613 if (IsSignedInteger)
6614 ImageOperandsMask |= 0x1000; // SignExtend
6615
6616 if (IsFetch && ImOps) {
6617 if (ImOps->Lod)
6618 ImageOperandsMask |= SPIRV::ImageOperand::Lod;
6619 if (ImOps->Offset && !isScalarOrVectorIntConstantZero(Reg: *ImOps->Offset)) {
6620 if (isConstReg(MRI, OpReg: *ImOps->Offset))
6621 ImageOperandsMask |= SPIRV::ImageOperand::ConstOffset;
6622 else
6623 ImageOperandsMask |= SPIRV::ImageOperand::Offset;
6624 }
6625 }
6626
6627 if (ImageOperandsMask != 0) {
6628 MIB.addImm(Val: ImageOperandsMask);
6629 if (IsFetch && ImOps) {
6630 if (ImOps->Lod)
6631 MIB.addUse(RegNo: *ImOps->Lod);
6632 if (ImOps->Offset &&
6633 (ImageOperandsMask &
6634 (SPIRV::ImageOperand::Offset | SPIRV::ImageOperand::ConstOffset)))
6635 MIB.addUse(RegNo: *ImOps->Offset);
6636 }
6637 }
6638 };
6639
6640 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(Type: ResType);
6641
6642 // A wide element (e.g. int64_t2) is emulated with a narrower packed image, so
6643 // its sampled type is different from the result.
6644 SPIRVTypeInst SampledType =
6645 GR.getSPIRVTypeForVReg(VReg: ImageType->getOperand(i: 1).getReg());
6646 bool IsPacked = SampledType != GR.getScalarOrVectorComponentType(Type: ResType);
6647 SPIRVTypeInst ReadType =
6648 widenTypeToVec4(Type: IsPacked ? SampledType : ResType, I&: Pos);
6649 bool ReadTypeMatchesResult = ReadType == ResType;
6650 // Read directly into the result, or into a temporary to bitcast/extract.
6651 Register ReadReg = ReadTypeMatchesResult
6652 ? ResVReg
6653 : MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ReadType));
6654
6655 auto BMI =
6656 BuildMI(BB&: *Pos.getParent(), I&: Pos, MIMD: Loc,
6657 MCID: TII.get(Opcode: IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
6658 .addDef(RegNo: ReadReg)
6659 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ReadType))
6660 .addUse(RegNo: ImageReg)
6661 .addUse(RegNo: IdxReg);
6662 AddOperands(BMI);
6663 BMI.constrainAllUses(TII, TRI, RBI);
6664
6665 if (ReadTypeMatchesResult)
6666 return true;
6667
6668 if (IsPacked) {
6669 // Reinterpret the packed vector as the wide result type.
6670 BuildMI(BB&: *Pos.getParent(), I&: Pos, MIMD: Loc, MCID: TII.get(Opcode: SPIRV::OpBitcast))
6671 .addDef(RegNo: ResVReg)
6672 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6673 .addUse(RegNo: ReadReg)
6674 .constrainAllUses(TII, TRI, RBI);
6675 return true;
6676 }
6677
6678 if (ResultSize == 1) {
6679 BuildMI(BB&: *Pos.getParent(), I&: Pos, MIMD: Loc, MCID: TII.get(Opcode: SPIRV::OpCompositeExtract))
6680 .addDef(RegNo: ResVReg)
6681 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6682 .addUse(RegNo: ReadReg)
6683 .addImm(Val: 0)
6684 .constrainAllUses(TII, TRI, RBI);
6685 return true;
6686 }
6687 return extractSubvector(ResVReg, ResType, ReadReg, InsertionPoint&: Pos);
6688}
6689
6690bool SPIRVInstructionSelector::selectResourceGetPointer(Register &ResVReg,
6691 SPIRVTypeInst ResType,
6692 MachineInstr &I) const {
6693 Register ResourcePtr = I.getOperand(i: 2).getReg();
6694 SPIRVTypeInst RegType = GR.getSPIRVTypeForVReg(VReg: ResourcePtr, MF: I.getMF());
6695 if (RegType->getOpcode() == SPIRV::OpTypeImage) {
6696 // For texel buffers, the index into the image is part of the OpImageRead or
6697 // OpImageWrite instructions. So we will do nothing in this case. This
6698 // intrinsic will be combined with the load or store when selecting the load
6699 // or store.
6700 return true;
6701 }
6702
6703 assert(ResType->getOpcode() == SPIRV::OpTypePointer);
6704 MachineIRBuilder MIRBuilder(I);
6705
6706 Register ZeroReg =
6707 buildZerosVal(ResType: GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII), I);
6708 auto MIB =
6709 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpAccessChain))
6710 .addDef(RegNo: ResVReg)
6711 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6712 .addUse(RegNo: ResourcePtr)
6713 .addUse(RegNo: ZeroReg);
6714
6715 if (I.getNumExplicitOperands() > 3) {
6716 Register IndexReg = I.getOperand(i: 3).getReg();
6717 MIB.addUse(RegNo: IndexReg);
6718 }
6719 MIB.constrainAllUses(TII, TRI, RBI);
6720 return true;
6721}
6722
6723bool SPIRVInstructionSelector::selectPushConstantGetPointer(
6724 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6725 MRI->replaceRegWith(FromReg: ResVReg, ToReg: I.getOperand(i: 2).getReg());
6726 return true;
6727}
6728
6729bool SPIRVInstructionSelector::selectResourceNonUniformIndex(
6730 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6731 Register ObjReg = I.getOperand(i: 2).getReg();
6732 if (!BuildCOPY(DestReg: ResVReg, SrcReg: ObjReg, I))
6733 return false;
6734
6735 buildOpDecorate(Reg: ResVReg, I, TII, Dec: SPIRV::Decoration::NonUniformEXT, DecArgs: {});
6736 // Check for the registers that use the index marked as non-uniform
6737 // and recursively mark them as non-uniform.
6738 // Per the spec, it's necessary that the final argument used for
6739 // load/store/sample/atomic must be decorated, so we need to propagate the
6740 // decoration through access chains and copies.
6741 // https://docs.vulkan.org/samples/latest/samples/extensions/descriptor_indexing/README.html#_when_to_use_non_uniform_indexing_qualifier
6742 decorateUsesAsNonUniform(NonUniformReg&: ResVReg);
6743 return true;
6744}
6745
6746void SPIRVInstructionSelector::decorateUsesAsNonUniform(
6747 Register &NonUniformReg) const {
6748 llvm::SmallVector<std::pair<Register, MachineInstr *>> WorkList = {
6749 {NonUniformReg, nullptr}};
6750 llvm::SmallSet<Register, 8> Visited;
6751 while (WorkList.size() > 0) {
6752 auto [CurrentReg, DefMI] = WorkList.pop_back_val();
6753
6754 if (!Visited.insert(V: CurrentReg).second)
6755 continue;
6756
6757 bool IsDecorated = false;
6758 for (MachineInstr &Use : MRI->use_instructions(Reg: CurrentReg)) {
6759 if (Use.getOpcode() == SPIRV::OpDecorate &&
6760 Use.getOperand(i: 1).getImm() == SPIRV::Decoration::NonUniformEXT) {
6761 IsDecorated = true;
6762 continue;
6763 }
6764 // Check if the instruction has the result register and add it to the
6765 // worklist.
6766 if (Use.getOperand(i: 0).isReg() && Use.getOperand(i: 0).isDef()) {
6767 Register ResultReg = Use.getOperand(i: 0).getReg();
6768 if (ResultReg == CurrentReg)
6769 continue;
6770 WorkList.push_back(Elt: {ResultReg, &Use});
6771 }
6772 }
6773
6774 if (!IsDecorated) {
6775 MachineBasicBlock &MBB = *DefMI->getParent();
6776 MachineInstr &InsertPt =
6777 DefMI->isPHI() ? *MBB.getFirstNonPHI() : *DefMI->getNextNode();
6778 buildOpDecorate(Reg: CurrentReg, I&: InsertPt, TII,
6779 Dec: SPIRV::Decoration::NonUniformEXT, DecArgs: {});
6780 }
6781 }
6782}
6783
6784bool SPIRVInstructionSelector::extractSubvector(
6785 Register &ResVReg, SPIRVTypeInst ResType, Register &ReadReg,
6786 MachineInstr &InsertionPoint) const {
6787 SPIRVTypeInst InputType = GR.getResultType(VReg: ReadReg);
6788 [[maybe_unused]] uint64_t InputSize =
6789 GR.getScalarOrVectorComponentCount(Type: InputType);
6790 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(Type: ResType);
6791 [[maybe_unused]] bool IsLongVectorEXT =
6792 STI.canUseExtension(E: SPIRV::Extension::SPV_EXT_long_vector);
6793 assert((InputSize > 1 || IsLongVectorEXT) && "The input must be a vector.");
6794 assert((ResultSize > 1 || IsLongVectorEXT) && "The result must be a vector.");
6795 assert(ResultSize < InputSize &&
6796 "Cannot extract more element than there are in the input.");
6797 SmallVector<Register> ComponentRegisters;
6798 SPIRVTypeInst ScalarType = GR.getScalarOrVectorComponentType(Type: ResType);
6799 const TargetRegisterClass *ScalarRegClass = GR.getRegClass(SpvType: ScalarType);
6800 for (uint64_t I = 0; I < ResultSize; I++) {
6801 Register ComponentReg = MRI->createVirtualRegister(RegClass: ScalarRegClass);
6802 BuildMI(BB&: *InsertionPoint.getParent(), I&: InsertionPoint,
6803 MIMD: InsertionPoint.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpCompositeExtract))
6804 .addDef(RegNo: ComponentReg)
6805 .addUse(RegNo: ScalarType->getOperand(i: 0).getReg())
6806 .addUse(RegNo: ReadReg)
6807 .addImm(Val: I)
6808 .constrainAllUses(TII, TRI, RBI);
6809 ComponentRegisters.emplace_back(Args&: ComponentReg);
6810 }
6811
6812 MachineInstrBuilder MIB = BuildMI(BB&: *InsertionPoint.getParent(), I&: InsertionPoint,
6813 MIMD: InsertionPoint.getDebugLoc(),
6814 MCID: TII.get(Opcode: SPIRV::OpCompositeConstruct))
6815 .addDef(RegNo: ResVReg)
6816 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
6817
6818 for (Register ComponentReg : ComponentRegisters)
6819 MIB.addUse(RegNo: ComponentReg);
6820 MIB.constrainAllUses(TII, TRI, RBI);
6821 return true;
6822}
6823
6824bool SPIRVInstructionSelector::selectImageWriteIntrinsic(
6825 MachineInstr &I) const {
6826 // If the load of the image is in a different basic block, then
6827 // this will generate invalid code. A proper solution is to move
6828 // the OpLoad from selectHandleFromBinding here. However, to do
6829 // that we will need to change the return type of the intrinsic.
6830 // We will do that when we can, but for now trying to move forward with other
6831 // issues.
6832 Register ImageReg = I.getOperand(i: 1).getReg();
6833 auto *ImageDef = cast<GIntrinsic>(Val: getVRegDef(MRI&: *MRI, Reg: ImageReg));
6834 Register NewImageReg = MRI->createVirtualRegister(RegClass: MRI->getRegClass(Reg: ImageReg));
6835 if (!loadHandleBeforePosition(HandleReg&: NewImageReg, ResType: GR.getSPIRVTypeForVReg(VReg: ImageReg),
6836 HandleDef&: *ImageDef, Pos&: I)) {
6837 return false;
6838 }
6839
6840 Register CoordinateReg = I.getOperand(i: 2).getReg();
6841 Register DataReg = I.getOperand(i: 3).getReg();
6842 assert(isVectorType(GR.getResultType(DataReg)));
6843 assert(GR.getScalarOrVectorComponentCount(GR.getResultType(DataReg)) == 4);
6844 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpImageWrite))
6845 .addUse(RegNo: NewImageReg)
6846 .addUse(RegNo: CoordinateReg)
6847 .addUse(RegNo: DataReg)
6848 .constrainAllUses(TII, TRI, RBI);
6849 return true;
6850}
6851
6852Register SPIRVInstructionSelector::buildPointerToResource(
6853 SPIRVTypeInst SpirvResType, SPIRV::StorageClass::StorageClass SC,
6854 uint32_t Set, uint32_t Binding, uint32_t ArraySize, Register IndexReg,
6855 StringRef Name, MachineIRBuilder MIRBuilder) const {
6856 const Type *ResType = GR.getTypeForSPIRVType(Ty: SpirvResType);
6857 if (ArraySize == 1) {
6858 SPIRVTypeInst PtrType =
6859 GR.getOrCreateSPIRVPointerType(BaseType: ResType, MIRBuilder, SC);
6860 assert(GR.getPointeeType(PtrType) == SpirvResType &&
6861 "SpirvResType did not have an explicit layout.");
6862 return GR.getOrCreateGlobalVariableWithBinding(VarType: PtrType, Set, Binding, Name,
6863 MIRBuilder);
6864 }
6865
6866 const Type *VarType = ArrayType::get(ElementType: const_cast<Type *>(ResType), NumElements: ArraySize);
6867 SPIRVTypeInst VarPointerType =
6868 GR.getOrCreateSPIRVPointerType(BaseType: VarType, MIRBuilder, SC);
6869 Register VarReg = GR.getOrCreateGlobalVariableWithBinding(
6870 VarType: VarPointerType, Set, Binding, Name, MIRBuilder);
6871
6872 SPIRVTypeInst ResPointerType =
6873 GR.getOrCreateSPIRVPointerType(BaseType: ResType, MIRBuilder, SC);
6874 Register AcReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResPointerType));
6875
6876 MIRBuilder.buildInstr(Opcode: SPIRV::OpAccessChain)
6877 .addDef(RegNo: AcReg)
6878 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResPointerType))
6879 .addUse(RegNo: VarReg)
6880 .addUse(RegNo: IndexReg);
6881
6882 return AcReg;
6883}
6884
6885bool SPIRVInstructionSelector::selectFirstBitSet16(
6886 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
6887 unsigned ExtendOpcode, unsigned BitSetOpcode) const {
6888 Register ExtReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
6889 if (!selectOpWithSrcs(ResVReg: ExtReg, ResType, I, Srcs: {I.getOperand(i: 2).getReg()},
6890 Opcode: ExtendOpcode))
6891 return false;
6892
6893 return selectFirstBitSet32(ResVReg, ResType, I, SrcReg: ExtReg, BitSetOpcode);
6894}
6895
6896bool SPIRVInstructionSelector::selectFirstBitSet32(
6897 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
6898 unsigned BitSetOpcode) const {
6899 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpExtInst))
6900 .addDef(RegNo: ResVReg)
6901 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6902 .addImm(Val: static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
6903 .addImm(Val: BitSetOpcode)
6904 .addUse(RegNo: SrcReg)
6905 .constrainAllUses(TII, TRI, RBI);
6906 return true;
6907}
6908
6909bool SPIRVInstructionSelector::selectFirstBitSet64(
6910 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
6911 unsigned BitSetOpcode, bool SwapPrimarySide) const {
6912 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(Type: ResType);
6913 SPIRVTypeInst BaseType = GR.retrieveScalarOrVectorIntType(Type: ResType);
6914 bool ZeroAsNull = !STI.isShader();
6915 Register ConstIntZero =
6916 GR.getOrCreateConstInt(Val: 0, I, SpvType: BaseType, TII, ZeroAsNull);
6917 Register ConstIntOne =
6918 GR.getOrCreateConstInt(Val: 1, I, SpvType: BaseType, TII, ZeroAsNull);
6919
6920 // SPIRV doesn't support vectors with more than 4 components. Since the
6921 // algoritm below converts i64 -> i32x2 and i64x4 -> i32x8 it can only
6922 // operate on vectors with 2 or less components. When largers vectors are
6923 // seen. Split them, recurse, then recombine them.
6924 // TODO: handle the case where SPV_EXT_long_vector is enabled.
6925 if (ComponentCount > 2) {
6926 auto Func = [this, SwapPrimarySide](Register ResVReg, SPIRVTypeInst ResType,
6927 MachineInstr &I, Register SrcReg,
6928 unsigned Opcode) -> bool {
6929 return this->selectFirstBitSet64(ResVReg, ResType, I, SrcReg, BitSetOpcode: Opcode,
6930 SwapPrimarySide);
6931 };
6932
6933 return handle64BitOverflow(ResVReg, ResType, I, SrcReg, Opcode: BitSetOpcode, CallbackFunction: Func);
6934 }
6935
6936 // 1. Split int64 into 2 pieces using a bitcast
6937 MachineIRBuilder MIRBuilder(I);
6938 SPIRVTypeInst PostCastType = GR.getOrCreateSPIRVVectorType(
6939 BaseType, NumElements: 2 * ComponentCount, MIRBuilder, EmitIR: false);
6940 Register BitcastReg =
6941 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: PostCastType));
6942
6943 if (!selectOpWithSrcs(ResVReg: BitcastReg, ResType: PostCastType, I, Srcs: {SrcReg},
6944 Opcode: SPIRV::OpBitcast))
6945 return false;
6946
6947 // 2. Find the first set bit from the primary side for all the pieces in #1
6948 Register FBSReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: PostCastType));
6949 if (!selectFirstBitSet32(ResVReg: FBSReg, ResType: PostCastType, I, SrcReg: BitcastReg, BitSetOpcode))
6950 return false;
6951
6952 // 3. Split result vector into high bits and low bits
6953 Register HighReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
6954 Register LowReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
6955
6956 bool IsScalarRes = !isVectorType(SPVTy: ResType);
6957 if (IsScalarRes) {
6958 // if scalar do a vector extract
6959 if (!selectOpWithSrcs(ResVReg: HighReg, ResType, I, Srcs: {FBSReg, ConstIntOne},
6960 Opcode: SPIRV::OpVectorExtractDynamic))
6961 return false;
6962 if (!selectOpWithSrcs(ResVReg: LowReg, ResType, I, Srcs: {FBSReg, ConstIntZero},
6963 Opcode: SPIRV::OpVectorExtractDynamic))
6964 return false;
6965 } else {
6966 // if vector do a shufflevector
6967 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
6968 MCID: TII.get(Opcode: SPIRV::OpVectorShuffle))
6969 .addDef(RegNo: HighReg)
6970 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6971 .addUse(RegNo: FBSReg)
6972 // Per the spec, repeat the vector if only one vec is needed
6973 .addUse(RegNo: FBSReg);
6974
6975 // high bits are stored in even natural indexes. Extract them from FBSReg
6976 for (unsigned J = 1; J < ComponentCount * 2; J += 2) {
6977 MIB.addImm(Val: J);
6978 }
6979
6980 MIB.constrainAllUses(TII, TRI, RBI);
6981
6982 MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(),
6983 MCID: TII.get(Opcode: SPIRV::OpVectorShuffle))
6984 .addDef(RegNo: LowReg)
6985 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
6986 .addUse(RegNo: FBSReg)
6987 // Per the spec, repeat the vector if only one vec is needed
6988 .addUse(RegNo: FBSReg);
6989
6990 // low bits are stored in odd natural indices. Extract them from FBSReg
6991 for (unsigned J = 0; J < ComponentCount * 2; J += 2) {
6992 MIB.addImm(Val: J);
6993 }
6994 MIB.constrainAllUses(TII, TRI, RBI);
6995 }
6996
6997 // 4. Check the result. When primary bits == -1 use secondary, otherwise use
6998 // primary
6999 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
7000 Register NegOneReg;
7001 Register Reg0;
7002 Register Reg32;
7003 unsigned SelectOp;
7004 unsigned AddOp;
7005
7006 if (IsScalarRes) {
7007 NegOneReg =
7008 GR.getOrCreateConstInt(Val: (unsigned)-1, I, SpvType: ResType, TII, ZeroAsNull);
7009 Reg0 = GR.getOrCreateConstInt(Val: 0, I, SpvType: ResType, TII, ZeroAsNull);
7010 Reg32 = GR.getOrCreateConstInt(Val: 32, I, SpvType: ResType, TII, ZeroAsNull);
7011 SelectOp = SPIRV::OpSelectSISCond;
7012 AddOp = SPIRV::OpIAddS;
7013 } else {
7014 BoolType = GR.getOrCreateSPIRVVectorType(BaseType: BoolType, NumElements: ComponentCount,
7015 MIRBuilder, EmitIR: false);
7016 NegOneReg =
7017 GR.getOrCreateConstVector(Val: (unsigned)-1, I, SpvType: ResType, TII, ZeroAsNull);
7018 Reg0 = GR.getOrCreateConstVector(Val: 0, I, SpvType: ResType, TII, ZeroAsNull);
7019 Reg32 = GR.getOrCreateConstVector(Val: 32, I, SpvType: ResType, TII, ZeroAsNull);
7020 SelectOp = SPIRV::OpSelectVIVCond;
7021 AddOp = SPIRV::OpIAddV;
7022 }
7023
7024 Register PrimaryReg = HighReg;
7025 Register SecondaryReg = LowReg;
7026 Register RegPrimaryOffset = Reg32;
7027 Register RegSecondaryOffset = Reg0;
7028
7029 // By default the emitted opcodes check for the set bit from the MSB side.
7030 // Setting SwapPrimarySide checks the set bit from the LSB side
7031 if (SwapPrimarySide) {
7032 PrimaryReg = LowReg;
7033 SecondaryReg = HighReg;
7034 RegPrimaryOffset = Reg0;
7035 RegSecondaryOffset = Reg32;
7036 }
7037
7038 Register RegSecondaryHasVal =
7039 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: BoolType));
7040 if (!selectOpWithSrcs(ResVReg: RegSecondaryHasVal, ResType: BoolType, I,
7041 Srcs: {SecondaryReg, NegOneReg}, Opcode: SPIRV::OpINotEqual))
7042 return false;
7043
7044 Register RegPrimaryHasVal =
7045 MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: BoolType));
7046 if (!selectOpWithSrcs(ResVReg: RegPrimaryHasVal, ResType: BoolType, I, Srcs: {PrimaryReg, NegOneReg},
7047 Opcode: SPIRV::OpINotEqual))
7048 return false;
7049
7050 // Pass 1: seed with secondary (lower-priority fallback)
7051 // ReturnBits = secondaryHasVal ? SecondaryBits : -1
7052 // Add = secondaryHasVal ? SecondaryOffset : 0
7053 Register RegReturnBits = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
7054 if (!selectOpWithSrcs(ResVReg: RegReturnBits, ResType, I,
7055 Srcs: {RegSecondaryHasVal, SecondaryReg, NegOneReg},
7056 Opcode: SelectOp))
7057 return false;
7058
7059 Register RegAdd;
7060 if (SwapPrimarySide) {
7061 RegAdd = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
7062 if (!selectOpWithSrcs(ResVReg: RegAdd, ResType, I,
7063 Srcs: {RegSecondaryHasVal, RegSecondaryOffset, Reg0},
7064 Opcode: SelectOp))
7065 return false;
7066 } else {
7067 RegAdd = Reg0;
7068 }
7069
7070 // Pass 2: override with primary (higher priority) if it has a valid result
7071 // ReturnBits2 = primaryHasVal ? PrimaryBits : ReturnBits
7072 // Add2 = primaryHasVal ? PrimaryOffset : Add
7073 Register RegReturnBits2 = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
7074 if (!selectOpWithSrcs(ResVReg: RegReturnBits2, ResType, I,
7075 Srcs: {RegPrimaryHasVal, PrimaryReg, RegReturnBits},
7076 Opcode: SelectOp))
7077 return false;
7078
7079 Register RegAdd2 = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
7080 if (!selectOpWithSrcs(ResVReg: RegAdd2, ResType, I,
7081 Srcs: {RegPrimaryHasVal, RegPrimaryOffset, RegAdd}, Opcode: SelectOp))
7082 return false;
7083
7084 return selectOpWithSrcs(ResVReg, ResType, I, Srcs: {RegReturnBits2, RegAdd2},
7085 Opcode: AddOp);
7086}
7087
7088bool SPIRVInstructionSelector::selectFirstBitHigh(Register ResVReg,
7089 SPIRVTypeInst ResType,
7090 MachineInstr &I,
7091 bool IsSigned) const {
7092 // FindUMsb and FindSMsb intrinsics only support 32 bit integers
7093 Register OpReg = I.getOperand(i: 2).getReg();
7094 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(VReg: OpReg);
7095 // zero or sign extend
7096 unsigned ExtendOpcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
7097 unsigned BitSetOpcode = IsSigned ? GL::FindSMsb : GL::FindUMsb;
7098
7099 switch (GR.getScalarOrVectorBitWidth(Type: OpType)) {
7100 case 16:
7101 return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode);
7102 case 32:
7103 return selectFirstBitSet32(ResVReg, ResType, I, SrcReg: OpReg, BitSetOpcode);
7104 case 64:
7105 return selectFirstBitSet64(ResVReg, ResType, I, SrcReg: OpReg, BitSetOpcode,
7106 /*SwapPrimarySide=*/false);
7107 default:
7108 return diagnoseUnsupported(
7109 I,
7110 Msg: "spv_firstbituhigh and spv_firstbitshigh only support 16,32,64 bits.");
7111 }
7112}
7113
7114bool SPIRVInstructionSelector::selectFirstBitLow(Register ResVReg,
7115 SPIRVTypeInst ResType,
7116 MachineInstr &I) const {
7117 // FindILsb intrinsic only supports 32 bit integers
7118 Register OpReg = I.getOperand(i: 2).getReg();
7119 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(VReg: OpReg);
7120 // OpUConvert treats the operand bits as an unsigned i16 and zero extends it
7121 // to an unsigned i32. As this leaves all the least significant bits unchanged
7122 // so the first set bit from the LSB side doesn't change.
7123 unsigned ExtendOpcode = SPIRV::OpUConvert;
7124 unsigned BitSetOpcode = GL::FindILsb;
7125
7126 switch (GR.getScalarOrVectorBitWidth(Type: OpType)) {
7127 case 16:
7128 return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode);
7129 case 32:
7130 return selectFirstBitSet32(ResVReg, ResType, I, SrcReg: OpReg, BitSetOpcode);
7131 case 64:
7132 return selectFirstBitSet64(ResVReg, ResType, I, SrcReg: OpReg, BitSetOpcode,
7133 /*SwapPrimarySide=*/true);
7134 default:
7135 return diagnoseUnsupported(I,
7136 Msg: "spv_firstbitlow only supports 16,32,64 bits.");
7137 }
7138}
7139
7140bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg,
7141 SPIRVTypeInst ResType,
7142 MachineInstr &I) const {
7143 // there was an allocation size parameter to the allocation instruction
7144 // that is not 1
7145 MachineBasicBlock &BB = *I.getParent();
7146
7147 bool UseUntypedPointers =
7148 ResType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
7149 unsigned Opcode = UseUntypedPointers
7150 ? SPIRV::OpUntypedVariableLengthArrayINTEL
7151 : SPIRV::OpVariableLengthArrayINTEL;
7152
7153 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
7154 .addDef(RegNo: ResVReg)
7155 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
7156
7157 // OpUntypedVariableLengthArrayINTEL takes an explicit Element Type <id>
7158 // right after the result type
7159 if (UseUntypedPointers) {
7160 SPIRVTypeInst ElementType = GR.getUntypedPtrElementType(Reg: ResVReg);
7161 assert(ElementType &&
7162 "untyped variable length array result must have a recorded element "
7163 "type");
7164 MIB.addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ElementType));
7165 }
7166
7167 MIB.addUse(RegNo: I.getOperand(i: 2).getReg());
7168 MIB.constrainAllUses(TII, TRI, RBI);
7169
7170 if (!STI.isShader()) {
7171 unsigned Alignment = I.getOperand(i: 3).getImm();
7172 buildOpDecorate(Reg: ResVReg, I, TII, Dec: SPIRV::Decoration::Alignment, DecArgs: {Alignment});
7173 }
7174 return true;
7175}
7176
7177// Returns true iff `Ty` is a concrete SPIR-V type per the SPV_KHR_abort
7178// definition: a numerical scalar (int/float), a (physical) pointer, a vector,
7179// matrix or any aggregate (array/struct) recursively containing only such
7180// types. OpTypeBool, OpTypeVoid, opaque handles and similar abstract
7181// non-concrete types are rejected.
7182static bool isConcreteSPIRVType(SPIRVTypeInst Ty,
7183 const SPIRVGlobalRegistry &GR) {
7184 SmallVector<SPIRVTypeInst, 4> Worklist{Ty};
7185 while (!Worklist.empty()) {
7186 SPIRVTypeInst T = Worklist.pop_back_val();
7187 switch (T->getOpcode()) {
7188 case SPIRV::OpTypeInt:
7189 case SPIRV::OpTypeFloat:
7190 case SPIRV::OpTypePointer:
7191 break;
7192 case SPIRV::OpTypeVector:
7193 case SPIRV::OpTypeVectorIdEXT:
7194 case SPIRV::OpTypeMatrix:
7195 case SPIRV::OpTypeArray: {
7196 Register OperandReg = T->getOperand(i: 1).getReg();
7197 SPIRVTypeInst ElementT = GR.getSPIRVTypeForVReg(VReg: OperandReg);
7198 Worklist.push_back(Elt: ElementT);
7199 } break;
7200 case SPIRV::OpTypeStruct:
7201 for (unsigned Idx = 1, E = T->getNumOperands(); Idx < E; ++Idx) {
7202 Register OperandReg = T->getOperand(i: Idx).getReg();
7203 SPIRVTypeInst ElementT = GR.getSPIRVTypeForVReg(VReg: OperandReg);
7204 Worklist.push_back(Elt: ElementT);
7205 }
7206 break;
7207 default:
7208 return false;
7209 }
7210 }
7211 return true;
7212}
7213
7214static bool containsStorageBufferPointer(SPIRVTypeInst Ty,
7215 const SPIRVGlobalRegistry &GR,
7216 SmallSet<Register, 8> &Visited) {
7217 Register TypeReg = Ty->getOperand(i: 0).getReg();
7218 if (!Visited.insert(V: TypeReg).second)
7219 return false;
7220
7221 switch (Ty->getOpcode()) {
7222 case SPIRV::OpTypePointer:
7223 if (Ty->getOperand(i: 1).getImm() == SPIRV::StorageClass::StorageBuffer)
7224 return true;
7225 return containsStorageBufferPointer(
7226 Ty: GR.getSPIRVTypeForVReg(VReg: Ty->getOperand(i: 2).getReg()), GR, Visited);
7227 case SPIRV::OpTypeArray:
7228 case SPIRV::OpTypeRuntimeArray:
7229 return containsStorageBufferPointer(
7230 Ty: GR.getSPIRVTypeForVReg(VReg: Ty->getOperand(i: 1).getReg()), GR, Visited);
7231 case SPIRV::OpTypeStruct:
7232 for (unsigned I = 1; I < Ty->getNumOperands(); ++I)
7233 if (containsStorageBufferPointer(
7234 Ty: GR.getSPIRVTypeForVReg(VReg: Ty->getOperand(i: I).getReg()), GR, Visited))
7235 return true;
7236 return false;
7237 default:
7238 return false;
7239 }
7240}
7241
7242static bool containsStorageBufferPointer(SPIRVTypeInst Ty,
7243 const SPIRVGlobalRegistry &GR) {
7244 SmallSet<Register, 8> Visited;
7245 return containsStorageBufferPointer(Ty, GR, Visited);
7246}
7247
7248bool SPIRVInstructionSelector::selectAbort(MachineInstr &I) const {
7249 assert(I.getNumExplicitOperands() == 2);
7250
7251 Register MsgReg = I.getOperand(i: 1).getReg();
7252 SPIRVTypeInst MsgType = GR.getSPIRVTypeForVReg(VReg: MsgReg);
7253 assert(MsgType && "Message argument of llvm.spv.abort has no SPIR-V type");
7254
7255 if (!isConcreteSPIRVType(Ty: MsgType, GR))
7256 return diagnoseUnsupported(
7257 I,
7258 Msg: "llvm.spv.abort message type must be a concrete SPIR-V type (numerical "
7259 "scalar, pointer, vector, matrix, or aggregate of such types)");
7260
7261 MachineBasicBlock &BB = *I.getParent();
7262 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpAbortKHR))
7263 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: MsgType))
7264 .addUse(RegNo: MsgReg)
7265 .constrainAllUses(TII, TRI, RBI);
7266 return true;
7267}
7268
7269bool SPIRVInstructionSelector::selectTrap(MachineInstr &I) const {
7270 // When the SPV_KHR_abort extension is disabled, drop the G_TRAP and
7271 // G_UBSANTRAP silently. Also drop the no-op placeholder of the service
7272 // function.
7273 if (!STI.canUseExtension(E: SPIRV::Extension::SPV_KHR_abort) ||
7274 I.getMF()->getFunction().hasFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME))
7275 return true;
7276
7277 // Use the 32-bit integer constant for the abort "message" argument:
7278 // - G_UBSANTRAP operand is zero-extended to 32 bits.
7279 // - "All ones" constant is used for G_TRAP.
7280 uint32_t MsgVal = ~0u;
7281 if (I.getOpcode() == TargetOpcode::G_UBSANTRAP)
7282 MsgVal = static_cast<uint32_t>(I.getOperand(i: 0).getImm());
7283
7284 SPIRVTypeInst MsgType = GR.getOrCreateSPIRVIntegerType(BitWidth: 32, I, TII);
7285 Register MsgReg = buildI32ConstantInEntryBlock(Val: MsgVal, I, ResType: MsgType);
7286
7287 MachineBasicBlock &BB = *I.getParent();
7288 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpAbortKHR))
7289 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: MsgType))
7290 .addUse(RegNo: MsgReg)
7291 .constrainAllUses(TII, TRI, RBI);
7292 return true;
7293}
7294
7295bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg,
7296 SPIRVTypeInst ResType,
7297 MachineInstr &I) const {
7298 // Change order of instructions if needed: all OpVariable instructions in a
7299 // function must be the first instructions in the first block
7300 auto It = getOpVariableMBBIt(MF&: *I.getMF());
7301
7302 // Pointers to opaque types stay typed even with the extension on, so emit the
7303 // untyped variant only when the result is actually an untyped pointer.
7304 bool UseUntypedPointers =
7305 ResType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
7306 unsigned Opcode =
7307 UseUntypedPointers ? SPIRV::OpUntypedVariableKHR : SPIRV::OpVariable;
7308
7309 if (!UseUntypedPointers && containsStorageBufferPointer(Ty: ResType, GR)) {
7310 MachineIRBuilder MIRBuilder(I);
7311 if (!STI.isAtLeastSPIRVVer(VerToCompareTo: VersionTuple(1, 3)))
7312 MIRBuilder.buildInstr(Opcode: SPIRV::OpExtension)
7313 .addImm(Val: SPIRV::Extension::SPV_KHR_variable_pointers);
7314 MIRBuilder.buildInstr(Opcode: SPIRV::OpCapability)
7315 .addImm(Val: SPIRV::Capability::VariablePointersStorageBuffer);
7316 }
7317
7318 auto MIB = BuildMI(BB&: *It->getParent(), I: It, MIMD: It->getDebugLoc(), MCID: TII.get(Opcode))
7319 .addDef(RegNo: ResVReg)
7320 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
7321 .addImm(Val: static_cast<uint32_t>(SPIRV::StorageClass::Function));
7322
7323 // OpUntypedVariableKHR takes an extra Data Type operand right after the
7324 // storage class.
7325 if (UseUntypedPointers) {
7326 // Get the element type that was stored when processing spv_assign_ptr_type.
7327 SPIRVTypeInst DataType = GR.getUntypedPtrElementType(Reg: ResVReg);
7328 if (!DataType)
7329 return diagnoseUnsupported(
7330 I, Msg: "could not deduce the data type of an untyped variable");
7331 MIB.addUse(RegNo: GR.getSPIRVTypeID(SpirvType: DataType));
7332 }
7333 MIB.constrainAllUses(TII, TRI, RBI);
7334
7335 if (!STI.isShader()) {
7336 unsigned Alignment = I.getOperand(i: 2).getImm();
7337 buildOpDecorate(Reg: ResVReg, I&: *It, TII, Dec: SPIRV::Decoration::Alignment,
7338 DecArgs: {Alignment});
7339 }
7340 return true;
7341}
7342
7343bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const {
7344 // InstructionSelector walks backwards through the instructions. We can use
7345 // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
7346 // first, so can generate an OpBranchConditional here. If there is no
7347 // G_BRCOND, we just use OpBranch for a regular unconditional branch.
7348 const MachineInstr *PrevI = I.getPrevNode();
7349 MachineBasicBlock &MBB = *I.getParent();
7350 if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) {
7351 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpBranchConditional))
7352 .addUse(RegNo: PrevI->getOperand(i: 0).getReg())
7353 .addMBB(MBB: PrevI->getOperand(i: 1).getMBB())
7354 .addMBB(MBB: I.getOperand(i: 0).getMBB())
7355 .constrainAllUses(TII, TRI, RBI);
7356 return true;
7357 }
7358 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpBranch))
7359 .addMBB(MBB: I.getOperand(i: 0).getMBB())
7360 .constrainAllUses(TII, TRI, RBI);
7361 return true;
7362}
7363
7364bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const {
7365 // InstructionSelector walks backwards through the instructions. For an
7366 // explicit conditional branch with no fallthrough, we use both a G_BR and a
7367 // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
7368 // generate the OpBranchConditional in selectBranch above.
7369 //
7370 // If an OpBranchConditional has been generated, we simply return, as the work
7371 // is alread done. If there is no OpBranchConditional, LLVM must be relying on
7372 // implicit fallthrough to the next basic block, so we need to create an
7373 // OpBranchConditional with an explicit "false" argument pointing to the next
7374 // basic block that LLVM would fall through to.
7375 const MachineInstr *NextI = I.getNextNode();
7376 // Check if this has already been successfully selected.
7377 if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional)
7378 return true;
7379 // Must be relying on implicit block fallthrough, so generate an
7380 // OpBranchConditional with the "next" basic block as the "false" target.
7381 MachineBasicBlock &MBB = *I.getParent();
7382 unsigned NextMBBNum = MBB.getNextNode()->getNumber();
7383 MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(N: NextMBBNum);
7384 BuildMI(BB&: MBB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpBranchConditional))
7385 .addUse(RegNo: I.getOperand(i: 0).getReg())
7386 .addMBB(MBB: I.getOperand(i: 1).getMBB())
7387 .addMBB(MBB: NextMBB)
7388 .constrainAllUses(TII, TRI, RBI);
7389 return true;
7390}
7391
7392bool SPIRVInstructionSelector::selectPhi(Register ResVReg,
7393 MachineInstr &I) const {
7394 auto MIB =
7395 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: TargetOpcode::PHI))
7396 .addDef(RegNo: ResVReg);
7397 const unsigned NumOps = I.getNumOperands();
7398 for (unsigned i = 1; i < NumOps; i += 2) {
7399 MIB.addUse(RegNo: I.getOperand(i: i + 0).getReg());
7400 MIB.addMBB(MBB: I.getOperand(i: i + 1).getMBB());
7401 }
7402 MIB.constrainAllUses(TII, TRI, RBI);
7403 return true;
7404}
7405
7406bool SPIRVInstructionSelector::selectGlobalValue(
7407 Register ResVReg, MachineInstr &I, const MachineInstr *Init) const {
7408 // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
7409 MachineIRBuilder MIRBuilder(I);
7410 const GlobalValue *GV = I.getOperand(i: 1).getGlobal();
7411 Type *GVType = toTypedPointer(Ty: GR.getDeducedGlobalValueType(Global: GV));
7412
7413 std::string GlobalIdent;
7414 if (!GV->hasName()) {
7415 unsigned &ID = UnnamedGlobalIDs[GV];
7416 if (ID == 0)
7417 ID = UnnamedGlobalIDs.size();
7418 GlobalIdent = "__unnamed_" + Twine(ID).str();
7419 } else {
7420 GlobalIdent = GV->getName();
7421 }
7422
7423 // Behaviour of functions as operands depends on availability of the
7424 // corresponding extension (SPV_INTEL_function_pointers):
7425 // - If there is an extension to operate with functions as operands:
7426 // We create a proper constant operand and evaluate a correct type for a
7427 // function pointer.
7428 // - Without the required extension:
7429 // We have functions as operands in tests with blocks of instruction e.g. in
7430 // transcoding/global_block.ll. These operands are not used and should be
7431 // substituted by zero constants. Their type is expected to be always
7432 // OpTypePointer Function %uchar.
7433 if (isa<Function>(Val: GV)) {
7434 const Constant *ConstVal = GV;
7435 MachineBasicBlock &BB = *I.getParent();
7436 Register NewReg = GR.find(V: ConstVal, MF: GR.CurMF);
7437 if (!NewReg.isValid()) {
7438 const Function *GVFun =
7439 STI.canUseExtension(E: SPIRV::Extension::SPV_INTEL_function_pointers)
7440 ? dyn_cast<Function>(Val: GV)
7441 : nullptr;
7442 SPIRVTypeInst ResType = GR.getOrCreateSPIRVPointerType(
7443 BaseType: GVType, I,
7444 SC: GVFun ? SPIRV::StorageClass::CodeSectionINTEL
7445 : addressSpaceToStorageClass(AddrSpace: GV->getAddressSpace(), STI));
7446 if (GVFun) {
7447 // References to a function via function pointers generate virtual
7448 // registers without a definition. We will resolve it later, during
7449 // module analysis stage.
7450 Register ResTypeReg = GR.getSPIRVTypeID(SpirvType: ResType);
7451 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
7452 Register FuncVReg =
7453 MRI->createGenericVirtualRegister(Ty: GR.getRegType(SpvType: ResType));
7454 MRI->setRegClass(Reg: FuncVReg, RC: &SPIRV::pIDRegClass);
7455 GR.assignSPIRVTypeToVReg(Type: ResType, VReg: FuncVReg, MF: *GR.CurMF);
7456 MachineInstrBuilder MIB1 =
7457 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpUndef))
7458 .addDef(RegNo: FuncVReg)
7459 .addUse(RegNo: ResTypeReg);
7460 MachineInstrBuilder MIB2 =
7461 BuildMI(BB, I, MIMD: I.getDebugLoc(),
7462 MCID: TII.get(Opcode: SPIRV::OpConstantFunctionPointerINTEL))
7463 .addDef(RegNo: ResVReg)
7464 .addUse(RegNo: ResTypeReg)
7465 .addUse(RegNo: FuncVReg);
7466 GR.add(V: ConstVal, MI: MIB2);
7467 // mapping the function pointer to the used Function
7468 GR.recordFunctionPointer(MO: &MIB2.getInstr()->getOperand(i: 2), F: GVFun);
7469 GR.assignSPIRVTypeToVReg(Type: ResType, VReg: ResVReg, MF: *GR.CurMF);
7470 MIB1.constrainAllUses(TII, TRI, RBI);
7471 MIB2.constrainAllUses(TII, TRI, RBI);
7472 return true;
7473 }
7474 MachineInstrBuilder MIB3 =
7475 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpUndef))
7476 .addDef(RegNo: ResVReg)
7477 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType));
7478 GR.add(V: ConstVal, MI: MIB3);
7479 GR.recordFunctionPointer(MO: &MIB3.getInstr()->getOperand(i: 0),
7480 F: cast<Function>(Val: GV));
7481 MIB3.constrainAllUses(TII, TRI, RBI);
7482 return true;
7483 }
7484 assert(NewReg != ResVReg);
7485 return BuildCOPY(DestReg: ResVReg, SrcReg: NewReg, I);
7486 }
7487 auto GlobalVar = cast<GlobalVariable>(Val: GV);
7488 assert(GlobalVar->getName() != "llvm.global.annotations");
7489
7490 // Skip empty declaration for GVs with initializers till we get the decl with
7491 // passed initializer.
7492 if (hasInitializer(GV: GlobalVar) && !Init)
7493 return true;
7494
7495 const std::optional<SPIRV::LinkageType::LinkageType> LnkType =
7496 getSpirvLinkageTypeFor(ST: STI, GV: *GV);
7497
7498 if (LnkType && *LnkType == SPIRV::LinkageType::Import)
7499 Init = nullptr;
7500
7501 const unsigned AddrSpace = GV->getAddressSpace();
7502 SPIRV::StorageClass::StorageClass StorageClass =
7503 addressSpaceToStorageClass(AddrSpace, STI);
7504 SPIRVTypeInst ResType =
7505 GR.getOrCreateSPIRVPointerType(BaseType: GVType, I, SC: StorageClass);
7506 Register Reg = GR.buildGlobalVariable(
7507 Reg: ResVReg, BaseType: ResType, Name: GlobalIdent, GV, Storage: StorageClass, Init,
7508 IsConst: GlobalVar->isConstant(), LinkageType: LnkType, MIRBuilder, IsInstSelector: true);
7509 // TODO: For AMDGCN, we pipe externally_initialized through via
7510 // HostAccessINTEL, with ReadWrite (3) access, which is we then handle during
7511 // reverse translation. We should remove this once SPIR-V gains the ability to
7512 // express the concept.
7513 if (GlobalVar->isExternallyInitialized() &&
7514 STI.getTargetTriple().getVendor() == Triple::AMD) {
7515 constexpr unsigned ReadWriteINTEL = 3u;
7516 buildOpDecorate(Reg, MIRBuilder, Dec: SPIRV::Decoration::HostAccessINTEL,
7517 DecArgs: {ReadWriteINTEL});
7518 MachineInstrBuilder MIB(*MF, --MIRBuilder.getInsertPt());
7519 addStringImm(Str: GV->getName(), MIB);
7520 }
7521 return Reg.isValid();
7522}
7523
7524bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
7525 SPIRVTypeInst ResType,
7526 MachineInstr &I) const {
7527 if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::OpenCL_std)) {
7528 return selectExtInst(ResVReg, ResType, I, CLInst: CL::log10);
7529 }
7530
7531 // There is no log10 instruction in the GLSL Extended Instruction set, so it
7532 // is implemented as:
7533 // log10(x) = log2(x) * (1 / log2(10))
7534 // = log2(x) * 0.30103
7535
7536 MachineIRBuilder MIRBuilder(I);
7537 MachineBasicBlock &BB = *I.getParent();
7538
7539 // Build log2(x).
7540 Register VarReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
7541 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpExtInst))
7542 .addDef(RegNo: VarReg)
7543 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
7544 .addImm(Val: static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
7545 .addImm(Val: GL::Log2)
7546 .add(MO: I.getOperand(i: 1))
7547 .constrainAllUses(TII, TRI, RBI);
7548
7549 // Build 0.30103.
7550 assert(isVectorType(ResType) || ResType.isAnyTypeFloat());
7551 // TODO: Add matrix implementation once supported by the HLSL frontend.
7552 SPIRVTypeInst SpirvScalarType = GR.getScalarOrVectorComponentType(Type: ResType);
7553 // The literal must match the precision of the scalar type, otherwise the
7554 // OpConstant will contain non-zero high-order bits and fail SPIR-V
7555 // validation when the type is narrower than 32 bits (e.g. half).
7556 APFloat ScaleVal(0.30103);
7557 bool LosesInfo;
7558 ScaleVal.convert(
7559 ToSemantics: getZeroFP(LLVMFloatTy: GR.getTypeForSPIRVType(Ty: SpirvScalarType)).getSemantics(),
7560 RM: APFloat::rmNearestTiesToEven, losesInfo: &LosesInfo);
7561 Register ScaleReg = GR.buildConstantFP(Val: ScaleVal, MIRBuilder, SpvType: SpirvScalarType);
7562
7563 // Multiply log2(x) by 0.30103 to get log10(x) result.
7564 auto Opcode =
7565 isVectorType(SPVTy: ResType) ? SPIRV::OpVectorTimesScalar : SPIRV::OpFMulS;
7566 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode))
7567 .addDef(RegNo: ResVReg)
7568 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
7569 .addUse(RegNo: VarReg)
7570 .addUse(RegNo: ScaleReg)
7571 .constrainAllUses(TII, TRI, RBI);
7572 return true;
7573}
7574
7575bool SPIRVInstructionSelector::selectFpowi(Register ResVReg,
7576 SPIRVTypeInst ResType,
7577 MachineInstr &I) const {
7578 // On OpenCL targets, pown(gentype x, intn n) maps directly.
7579 if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::OpenCL_std))
7580 return selectExtInst(ResVReg, ResType, I, CLInst: CL::pown);
7581
7582 // On GLSL (Vulkan) targets, there is no integer-exponent power instruction.
7583 // Lower as: Pow(base, OpConvertSToF(exp)).
7584 if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::GLSL_std_450)) {
7585 Register BaseReg = I.getOperand(i: 1).getReg();
7586 Register ExpReg = I.getOperand(i: 2).getReg();
7587 Register FloatExpReg = MRI->createVirtualRegister(RegClass: GR.getRegClass(SpvType: ResType));
7588 if (!selectOpWithSrcs(ResVReg: FloatExpReg, ResType, I, Srcs: {ExpReg},
7589 Opcode: SPIRV::OpConvertSToF))
7590 return false;
7591 return selectExtInst(ResVReg, ResType, I, GLInst: GL::Pow,
7592 /*setMIFlags=*/true, /*useMISrc=*/false,
7593 SrcRegs: {BaseReg, FloatExpReg});
7594 }
7595 return false;
7596}
7597
7598bool SPIRVInstructionSelector::selectModf(Register ResVReg,
7599 SPIRVTypeInst ResType,
7600 MachineInstr &I) const {
7601 // llvm.modf has a single arg --the number to be decomposed-- and returns a
7602 // struct { restype, restype }, while OpenCLLIB::modf has two args --the
7603 // number to be decomposed and a pointer--, returns the fractional part and
7604 // the integral part is stored in the pointer argument. Therefore, we can't
7605 // use directly the OpenCLLIB::modf intrinsic. However, we can do some
7606 // scaffolding to make it work. The idea is to create an alloca instruction
7607 // to get a ptr, pass this ptr to OpenCL::modf, and then load the value
7608 // from this ptr to place it in the struct. llvm.modf returns the fractional
7609 // part as the first element of the result, and the integral part as the
7610 // second element of the result.
7611
7612 // At this point, the return type is not a struct anymore, but rather two
7613 // independent elements of SPIRVResType. We can get each independent element
7614 // from I.getDefs() or I.getOperands().
7615 if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::OpenCL_std)) {
7616 MachineIRBuilder MIRBuilder(I);
7617 SPIRVTypeInst FloatType =
7618 GR.getSPIRVTypeForVReg(VReg: I.getOperand(i: I.getNumExplicitDefs()).getReg());
7619 // Get pointer type for alloca variable.
7620 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
7621 BaseType: FloatType, MIRBuilder, SC: SPIRV::StorageClass::Function);
7622 // Create new register for the pointer type of alloca variable.
7623 Register PtrTyReg =
7624 MIRBuilder.getMRI()->createVirtualRegister(RegClass: &SPIRV::iIDRegClass);
7625 MIRBuilder.getMRI()->setType(
7626 VReg: PtrTyReg,
7627 Ty: LLT::pointer(AddressSpace: storageClassToAddressSpace(SC: SPIRV::StorageClass::Function),
7628 SizeInBits: GR.getPointerSize()));
7629
7630 // Assign SPIR-V type of the pointer type of the alloca variable to the
7631 // new register.
7632 GR.assignSPIRVTypeToVReg(Type: PtrType, VReg: PtrTyReg, MF: MIRBuilder.getMF());
7633 MachineBasicBlock::iterator VarPos = getOpVariableMBBIt(MF&: *I.getMF());
7634 MachineBasicBlock &EntryBB = I.getMF()->front();
7635 const bool IsUntyped =
7636 PtrType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
7637 auto AllocaMIB =
7638 BuildMI(BB&: EntryBB, I: VarPos, MIMD: I.getDebugLoc(),
7639 MCID: TII.get(Opcode: IsUntyped ? SPIRV::OpUntypedVariableKHR
7640 : SPIRV::OpVariable))
7641 .addDef(RegNo: PtrTyReg)
7642 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: PtrType))
7643 .addImm(Val: static_cast<uint32_t>(SPIRV::StorageClass::Function));
7644 if (IsUntyped)
7645 AllocaMIB.addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType)); // Data Type
7646 Register Variable = AllocaMIB->getOperand(i: 0).getReg();
7647
7648 MachineBasicBlock &BB = *I.getParent();
7649 // Create the OpenCLLIB::modf instruction.
7650 auto MIB =
7651 BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpExtInst))
7652 .addDef(RegNo: ResVReg)
7653 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: FloatType))
7654 .addImm(Val: static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
7655 .addImm(Val: CL::modf)
7656 .setMIFlags(I.getFlags())
7657 .add(MO: I.getOperand(i: I.getNumExplicitDefs())) // Floating point value.
7658 .addUse(RegNo: Variable); // Pointer to integral part.
7659 // Assign the integral part stored in the ptr to the second element of the
7660 // result.
7661 Register IntegralPartReg = I.getOperand(i: 1).getReg();
7662 if (IntegralPartReg.isValid() && !MRI->use_nodbg_empty(RegNo: IntegralPartReg)) {
7663 // Load the value from the pointer to integral part.
7664 auto LoadMIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpLoad))
7665 .addDef(RegNo: IntegralPartReg)
7666 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: FloatType))
7667 .addUse(RegNo: Variable);
7668 LoadMIB.constrainAllUses(TII, TRI, RBI);
7669 }
7670
7671 MIB.constrainAllUses(TII, TRI, RBI);
7672 return true;
7673 } else if (STI.canUseExtInstSet(E: SPIRV::InstructionSet::GLSL_std_450)) {
7674 assert(false && "GLSL::Modf is deprecated.");
7675 // FIXME: GL::Modf is deprecated, use Modfstruct instead.
7676 return false;
7677 }
7678 return false;
7679}
7680
7681// Generate the instructions to load 3-element vector builtin input
7682// IDs/Indices.
7683// Like: GlobalInvocationId, LocalInvocationId, etc....
7684
7685bool SPIRVInstructionSelector::loadVec3BuiltinInputID(
7686 SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg,
7687 SPIRVTypeInst ResType, MachineInstr &I) const {
7688 MachineIRBuilder MIRBuilder(I);
7689 const SPIRVTypeInst Vec3Ty =
7690 GR.getOrCreateSPIRVVectorType(BaseType: ResType, NumElements: 3, MIRBuilder, EmitIR: false);
7691 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
7692 BaseType: Vec3Ty, MIRBuilder, SC: SPIRV::StorageClass::Input);
7693
7694 // Create new register for the input ID builtin variable.
7695 Register NewRegister =
7696 MIRBuilder.getMRI()->createVirtualRegister(RegClass: &SPIRV::iIDRegClass);
7697 MIRBuilder.getMRI()->setType(VReg: NewRegister, Ty: LLT::pointer(AddressSpace: 0, SizeInBits: 64));
7698 GR.assignSPIRVTypeToVReg(Type: PtrType, VReg: NewRegister, MF: MIRBuilder.getMF());
7699
7700 // Build global variable with the necessary decorations for the input ID
7701 // builtin variable.
7702 Register Variable = GR.buildGlobalVariable(
7703 Reg: NewRegister, BaseType: PtrType, Name: getLinkStringForBuiltIn(BuiltInValue), GV: nullptr,
7704 Storage: SPIRV::StorageClass::Input, Init: nullptr, IsConst: true, LinkageType: std::nullopt, MIRBuilder,
7705 IsInstSelector: false);
7706
7707 // Create new register for loading value.
7708 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
7709 Register LoadedRegister = MRI->createVirtualRegister(RegClass: &SPIRV::iIDRegClass);
7710 MIRBuilder.getMRI()->setType(VReg: LoadedRegister, Ty: LLT::pointer(AddressSpace: 0, SizeInBits: 64));
7711 GR.assignSPIRVTypeToVReg(Type: Vec3Ty, VReg: LoadedRegister, MF: MIRBuilder.getMF());
7712
7713 // Load v3uint value from the global variable.
7714 BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpLoad))
7715 .addDef(RegNo: LoadedRegister)
7716 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: Vec3Ty))
7717 .addUse(RegNo: Variable);
7718
7719 // Get the input ID index. Expecting operand is a constant immediate value,
7720 // wrapped in a type assignment.
7721 assert(I.getOperand(2).isReg());
7722 const uint32_t ThreadId = foldImm(MO: I.getOperand(i: 2), MRI);
7723
7724 // Extract the input ID from the loaded vector value.
7725 MachineBasicBlock &BB = *I.getParent();
7726 auto MIB = BuildMI(BB, I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpCompositeExtract))
7727 .addDef(RegNo: ResVReg)
7728 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
7729 .addUse(RegNo: LoadedRegister)
7730 .addImm(Val: ThreadId);
7731 MIB.constrainAllUses(TII, TRI, RBI);
7732 return true;
7733}
7734
7735// Generate the instructions to load 32-bit integer builtin input IDs/Indices.
7736// Like LocalInvocationIndex
7737bool SPIRVInstructionSelector::loadBuiltinInputID(
7738 SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg,
7739 SPIRVTypeInst ResType, MachineInstr &I) const {
7740 MachineIRBuilder MIRBuilder(I);
7741 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
7742 BaseType: ResType, MIRBuilder, SC: SPIRV::StorageClass::Input);
7743
7744 // Create new register for the input ID builtin variable.
7745 Register NewRegister =
7746 MIRBuilder.getMRI()->createVirtualRegister(RegClass: GR.getRegClass(SpvType: PtrType));
7747 MIRBuilder.getMRI()->setType(
7748 VReg: NewRegister,
7749 Ty: LLT::pointer(AddressSpace: storageClassToAddressSpace(SC: SPIRV::StorageClass::Input),
7750 SizeInBits: GR.getPointerSize()));
7751 GR.assignSPIRVTypeToVReg(Type: PtrType, VReg: NewRegister, MF: MIRBuilder.getMF());
7752
7753 // Build global variable with the necessary decorations for the input ID
7754 // builtin variable.
7755 Register Variable = GR.buildGlobalVariable(
7756 Reg: NewRegister, BaseType: PtrType, Name: getLinkStringForBuiltIn(BuiltInValue), GV: nullptr,
7757 Storage: SPIRV::StorageClass::Input, Init: nullptr, IsConst: true, LinkageType: std::nullopt, MIRBuilder,
7758 IsInstSelector: false);
7759
7760 // Load uint value from the global variable.
7761 auto MIB = BuildMI(BB&: *I.getParent(), I, MIMD: I.getDebugLoc(), MCID: TII.get(Opcode: SPIRV::OpLoad))
7762 .addDef(RegNo: ResVReg)
7763 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
7764 .addUse(RegNo: Variable);
7765
7766 MIB.constrainAllUses(TII, TRI, RBI);
7767 return true;
7768}
7769
7770SPIRVTypeInst SPIRVInstructionSelector::widenTypeToVec4(SPIRVTypeInst Type,
7771 MachineInstr &I) const {
7772 MachineIRBuilder MIRBuilder(I);
7773 if (!isVectorType(SPVTy: Type))
7774 return GR.getOrCreateSPIRVVectorType(BaseType: Type, NumElements: 4, MIRBuilder, EmitIR: false);
7775
7776 if (GR.getScalarOrVectorComponentCount(Type) == 4)
7777 return Type;
7778
7779 SPIRVTypeInst ScalarType = GR.getScalarOrVectorComponentType(Type);
7780 return GR.getOrCreateSPIRVVectorType(BaseType: ScalarType, NumElements: 4, MIRBuilder, EmitIR: false);
7781}
7782
7783bool SPIRVInstructionSelector::loadHandleBeforePosition(
7784 Register &HandleReg, SPIRVTypeInst ResType, GIntrinsic &HandleDef,
7785 MachineInstr &Pos) const {
7786
7787 assert(HandleDef.getIntrinsicID() ==
7788 Intrinsic::spv_resource_handlefrombinding);
7789 uint32_t Set = foldImm(MO: HandleDef.getOperand(i: 2), MRI);
7790 uint32_t Binding = foldImm(MO: HandleDef.getOperand(i: 3), MRI);
7791 uint32_t ArraySize = foldImm(MO: HandleDef.getOperand(i: 4), MRI);
7792 Register IndexReg = HandleDef.getOperand(i: 5).getReg();
7793 std::string Name =
7794 getStringValueFromReg(Reg: HandleDef.getOperand(i: 6).getReg(), MRI&: *MRI);
7795
7796 bool IsStructuredBuffer = ResType->getOpcode() == SPIRV::OpTypePointer;
7797 MachineIRBuilder MIRBuilder(HandleDef);
7798 SPIRVTypeInst VarType = ResType;
7799 SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::UniformConstant;
7800
7801 if (IsStructuredBuffer) {
7802 VarType = GR.getPointeeType(PtrType: ResType);
7803 SC = GR.getPointerStorageClass(Type: ResType);
7804 }
7805
7806 // ArraySize 0 means an unbounded array and we need to set to required
7807 // capability.
7808 if (ArraySize == 0)
7809 MIRBuilder.buildInstr(Opcode: SPIRV::OpCapability)
7810 .addImm(Val: SPIRV::Capability::RuntimeDescriptorArrayEXT);
7811
7812 Register VarReg =
7813 buildPointerToResource(SpirvResType: SPIRVTypeInst(VarType), SC, Set, Binding,
7814 ArraySize, IndexReg, Name, MIRBuilder);
7815
7816 // The handle for the buffer is the pointer to the resource. For an image, the
7817 // handle is the image object. So images get an extra load.
7818 uint32_t LoadOpcode =
7819 IsStructuredBuffer ? SPIRV::OpCopyObject : SPIRV::OpLoad;
7820 GR.assignSPIRVTypeToVReg(Type: ResType, VReg: HandleReg, MF: *Pos.getMF());
7821 BuildMI(BB&: *Pos.getParent(), I&: Pos, MIMD: HandleDef.getDebugLoc(), MCID: TII.get(Opcode: LoadOpcode))
7822 .addDef(RegNo: HandleReg)
7823 .addUse(RegNo: GR.getSPIRVTypeID(SpirvType: ResType))
7824 .addUse(RegNo: VarReg)
7825 .constrainAllUses(TII, TRI, RBI);
7826 return true;
7827}
7828
7829bool SPIRVInstructionSelector::errorIfInstrOutsideShader(
7830 MachineInstr &I) const {
7831 if (!STI.isShader())
7832 return diagnoseUnsupported(
7833 I, Msg: "this instruction is only supported in shaders.");
7834 return true;
7835}
7836
7837namespace llvm {
7838InstructionSelector *
7839createSPIRVInstructionSelector(const SPIRVTargetMachine &TM,
7840 const SPIRVSubtarget &Subtarget,
7841 const RegisterBankInfo &RBI) {
7842 return new SPIRVInstructionSelector(TM, Subtarget, RBI);
7843}
7844} // namespace llvm
7845