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