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