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