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