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 MemSem = static_cast<uint32_t>(getMemSemantics(AO));
2749 Register MemSemReg = buildI32ConstantInEntryBlock(MemSem, I);
2750 SyncScope::ID Ord = SyncScope::ID(I.getOperand(1).getImm());
2751 uint32_t Scope = static_cast<uint32_t>(getMemScope(
2752 STI.getTargetTriple(), GR.CurMF->getFunction().getContext(), Ord));
2753 Register ScopeReg = buildI32ConstantInEntryBlock(Scope, I);
2754 MachineBasicBlock &BB = *I.getParent();
2755 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMemoryBarrier))
2756 .addUse(ScopeReg)
2757 .addUse(MemSemReg)
2758 .constrainAllUses(TII, TRI, RBI);
2759 return true;
2760}
2761
2762bool SPIRVInstructionSelector::selectOverflowArith(Register ResVReg,
2763 SPIRVTypeInst ResType,
2764 MachineInstr &I,
2765 unsigned Opcode) const {
2766 Type *ResTy = nullptr;
2767 StringRef ResName;
2768 if (!GR.findValueAttrs(&I, ResTy, ResName))
2769 return diagnoseUnsupported(
2770 I,
2771 "Not enough info to select the arithmetic with overflow instruction");
2772 if (!ResTy || !ResTy->isStructTy())
2773 return diagnoseUnsupported(I,
2774 "Expect struct type result for the arithmetic "
2775 "with overflow instruction");
2776 // "Result Type must be from OpTypeStruct. The struct must have two members,
2777 // and the two members must be the same type."
2778 Type *ResElemTy = cast<StructType>(ResTy)->getElementType(0);
2779 ResTy = StructType::get(ResElemTy, ResElemTy);
2780 // Build SPIR-V types and constant(s) if needed.
2781 MachineIRBuilder MIRBuilder(I);
2782 SPIRVTypeInst StructType = GR.getOrCreateSPIRVType(
2783 ResTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false);
2784 assert(I.getNumDefs() > 1 && "Not enought operands");
2785 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
2786 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
2787 if (N > 1 || (isVectorType(ResType) &&
2788 STI.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector)))
2789 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, N, I, TII);
2790 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
2791 Register ZeroReg = buildZerosVal(ResType, I);
2792 // A new virtual register to store the result struct.
2793 Register StructVReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
2794 MRI->setRegClass(StructVReg, &SPIRV::IDRegClass);
2795 // Build the result name if needed.
2796 if (ResName.size() > 0)
2797 buildOpName(StructVReg, ResName, MIRBuilder);
2798 // Build the arithmetic with overflow instruction.
2799 MachineBasicBlock &BB = *I.getParent();
2800 auto MIB =
2801 BuildMI(BB, MIRBuilder.getInsertPt(), I.getDebugLoc(), TII.get(Opcode))
2802 .addDef(StructVReg)
2803 .addUse(GR.getSPIRVTypeID(StructType));
2804 for (unsigned i = I.getNumDefs(); i < I.getNumOperands(); ++i)
2805 MIB.addUse(I.getOperand(i).getReg());
2806 MIB.constrainAllUses(TII, TRI, RBI);
2807 // Build instructions to extract fields of the instruction's result.
2808 // A new virtual register to store the higher part of the result struct.
2809 Register HigherVReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
2810 MRI->setRegClass(HigherVReg, &SPIRV::iIDRegClass);
2811 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
2812 auto MIB =
2813 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
2814 .addDef(i == 1 ? HigherVReg : I.getOperand(i).getReg())
2815 .addUse(GR.getSPIRVTypeID(ResType))
2816 .addUse(StructVReg)
2817 .addImm(i);
2818 MIB.constrainAllUses(TII, TRI, RBI);
2819 }
2820 // Build boolean value from the higher part.
2821 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
2822 .addDef(I.getOperand(1).getReg())
2823 .addUse(BoolTypeReg)
2824 .addUse(HigherVReg)
2825 .addUse(ZeroReg)
2826 .constrainAllUses(TII, TRI, RBI);
2827 return true;
2828}
2829
2830bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg,
2831 SPIRVTypeInst ResType,
2832 MachineInstr &I) const {
2834 "selectAtomicCmpXchg only handles the spv_cmpxchg intrinsic");
2835 Register Ptr = I.getOperand(2).getReg();
2836 Register ScopeReg = I.getOperand(5).getReg();
2837 Register MemSemEqReg = I.getOperand(6).getReg();
2838 Register MemSemNeqReg = I.getOperand(7).getReg();
2839 Register Cmp = I.getOperand(3).getReg();
2840 Register Val = I.getOperand(4).getReg();
2841 SPIRVTypeInst SpvValTy = GR.getSPIRVTypeForVReg(Val);
2842 Register ACmpRes = createVirtualRegister(SpvValTy, &GR, MRI, *I.getMF());
2843 const DebugLoc &DL = I.getDebugLoc();
2844 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpAtomicCompareExchange))
2845 .addDef(ACmpRes)
2846 .addUse(GR.getSPIRVTypeID(SpvValTy))
2847 .addUse(Ptr)
2848 .addUse(ScopeReg)
2849 .addUse(MemSemEqReg)
2850 .addUse(MemSemNeqReg)
2851 .addUse(Val)
2852 .addUse(Cmp)
2853 .constrainAllUses(TII, TRI, RBI);
2854 SPIRVTypeInst BoolTy = GR.getOrCreateSPIRVBoolType(I, TII);
2855 Register CmpSuccReg = createVirtualRegister(BoolTy, &GR, MRI, *I.getMF());
2856 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpIEqual))
2857 .addDef(CmpSuccReg)
2858 .addUse(GR.getSPIRVTypeID(BoolTy))
2859 .addUse(ACmpRes)
2860 .addUse(Cmp)
2861 .constrainAllUses(TII, TRI, RBI);
2862 Register TmpReg = createVirtualRegister(ResType, &GR, MRI, *I.getMF());
2863 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
2864 .addDef(TmpReg)
2865 .addUse(GR.getSPIRVTypeID(ResType))
2866 .addUse(ACmpRes)
2867 .addUse(GR.getOrCreateUndef(I, ResType, TII))
2868 .addImm(0)
2869 .constrainAllUses(TII, TRI, RBI);
2870 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
2871 .addDef(ResVReg)
2872 .addUse(GR.getSPIRVTypeID(ResType))
2873 .addUse(CmpSuccReg)
2874 .addUse(TmpReg)
2875 .addImm(1)
2876 .constrainAllUses(TII, TRI, RBI);
2877 return true;
2878}
2879
2880static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) {
2881 switch (SC) {
2882 case SPIRV::StorageClass::DeviceOnlyINTEL:
2883 case SPIRV::StorageClass::HostOnlyINTEL:
2884 return true;
2885 default:
2886 return false;
2887 }
2888}
2889
2890// Returns true ResVReg is referred only from global vars and OpName's.
2891static bool isASCastInGVar(MachineRegisterInfo *MRI, Register ResVReg) {
2892 bool IsGRef = false;
2893 bool IsAllowedRefs =
2894 llvm::all_of(MRI->use_instructions(ResVReg), [&IsGRef](auto const &It) {
2895 unsigned Opcode = It.getOpcode();
2896 if (Opcode == SPIRV::OpConstantComposite ||
2897 Opcode == SPIRV::OpSpecConstantComposite ||
2898 Opcode == SPIRV::OpVariable ||
2899 Opcode == SPIRV::OpUntypedVariableKHR ||
2900 isSpvIntrinsic(It, Intrinsic::spv_init_global))
2901 return IsGRef = true;
2902 return Opcode == SPIRV::OpName;
2903 });
2904 return IsAllowedRefs && IsGRef;
2905}
2906
2907Register SPIRVInstructionSelector::getUcharPtrTypeReg(
2908 MachineInstr &I, SPIRV::StorageClass::StorageClass SC) const {
2910 Type::getInt8Ty(I.getMF()->getFunction().getContext()), I, SC));
2911}
2912
2913MachineInstrBuilder
2914SPIRVInstructionSelector::buildSpecConstantOp(MachineInstr &I, Register Dest,
2915 Register Src, Register DestType,
2916 uint32_t Opcode) const {
2917 return BuildMI(*I.getParent(), I, I.getDebugLoc(),
2918 TII.get(SPIRV::OpSpecConstantOp))
2919 .addDef(Dest)
2920 .addUse(DestType)
2921 .addImm(Opcode)
2922 .addUse(Src);
2923}
2924
2925MachineInstrBuilder
2926SPIRVInstructionSelector::buildConstGenericPtr(MachineInstr &I, Register SrcPtr,
2927 SPIRVTypeInst SrcPtrTy) const {
2928 SPIRVTypeInst GenericPtrTy =
2929 GR.changePointerStorageClass(SrcPtrTy, SPIRV::StorageClass::Generic, I);
2930 Register Tmp = MRI->createVirtualRegister(&SPIRV::pIDRegClass);
2932 SPIRV::StorageClass::Generic),
2933 GR.getPointerSize()));
2934 MachineFunction *MF = I.getParent()->getParent();
2935 GR.assignSPIRVTypeToVReg(GenericPtrTy, Tmp, *MF);
2936 MachineInstrBuilder MIB = buildSpecConstantOp(
2937 I, Tmp, SrcPtr, GR.getSPIRVTypeID(GenericPtrTy),
2938 static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric));
2939 GR.add(MIB.getInstr(), MIB);
2940 return MIB;
2941}
2942
2943// In SPIR-V address space casting can only happen to and from the Generic
2944// storage class. We can also only cast Workgroup, CrossWorkgroup, or Function
2945// pointers to and from Generic pointers. As such, we can convert e.g. from
2946// Workgroup to Function by going via a Generic pointer as an intermediary. All
2947// other combinations can only be done by a bitcast, and are probably not safe.
2948bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
2949 SPIRVTypeInst ResType,
2950 MachineInstr &I) const {
2951 MachineBasicBlock &BB = *I.getParent();
2952 const DebugLoc &DL = I.getDebugLoc();
2953
2954 Register SrcPtr = I.getOperand(1).getReg();
2955 SPIRVTypeInst SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
2956
2957 // don't generate a cast for a null that may be represented by OpTypeInt
2958 if (!SrcPtrTy || !SrcPtrTy.isPointer() || !ResType || !ResType.isPointer())
2959 return BuildCOPY(ResVReg, SrcPtr, I);
2960
2961 SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtrTy);
2962 SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResType);
2963
2964 if (isASCastInGVar(MRI, ResVReg)) {
2965 // AddrSpaceCast uses within OpVariable and OpConstantComposite instructions
2966 // are expressed by OpSpecConstantOp with an Opcode.
2967 // TODO: maybe insert a check whether the Kernel capability was declared and
2968 // so PtrCastToGeneric/GenericCastToPtr are available.
2969 unsigned SpecOpcode = [&]() -> unsigned {
2970 if (SrcSC == SPIRV::StorageClass::CodeSectionINTEL)
2971 return static_cast<uint32_t>(SPIRV::Opcode::Bitcast);
2972 if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC))
2973 return static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric);
2974 if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC))
2975 return static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr);
2976 return 0u;
2977 }();
2978 // TODO: OpConstantComposite expects i8*, so we are forced to forget a
2979 // correct value of ResType and use general i8* instead. Maybe this should
2980 // be addressed in the emit-intrinsic step to infer a correct
2981 // OpConstantComposite type.
2982 if (SpecOpcode) {
2983 buildSpecConstantOp(I, ResVReg, SrcPtr, getUcharPtrTypeReg(I, DstSC),
2984 SpecOpcode)
2985 .constrainAllUses(TII, TRI, RBI);
2986 } else if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
2987 MachineInstrBuilder MIB = buildConstGenericPtr(I, SrcPtr, SrcPtrTy);
2988 MIB.constrainAllUses(TII, TRI, RBI);
2989 buildSpecConstantOp(
2990 I, ResVReg, MIB->getOperand(0).getReg(), getUcharPtrTypeReg(I, DstSC),
2991 static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr))
2992 .constrainAllUses(TII, TRI, RBI);
2993 }
2994 return true;
2995 }
2996
2997 // don't generate a cast between identical storage classes
2998 if (SrcSC == DstSC)
2999 return BuildCOPY(ResVReg, SrcPtr, I);
3000
3001 if ((SrcSC == SPIRV::StorageClass::Function &&
3002 DstSC == SPIRV::StorageClass::Private) ||
3003 (DstSC == SPIRV::StorageClass::Function &&
3004 SrcSC == SPIRV::StorageClass::Private))
3005 return BuildCOPY(ResVReg, SrcPtr, I);
3006
3007 // Casting from an eligible pointer to Generic.
3008 if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC))
3009 return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
3010 // Casting from Generic to an eligible pointer.
3011 if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC))
3012 return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
3013 // Casting between 2 eligible pointers using Generic as an intermediary.
3014 if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
3015 SPIRVTypeInst GenericPtrTy =
3016 GR.changePointerStorageClass(SrcPtrTy, SPIRV::StorageClass::Generic, I);
3017 Register Tmp = createVirtualRegister(GenericPtrTy, &GR, MRI, MRI->getMF());
3018 BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric))
3019 .addDef(Tmp)
3020 .addUse(GR.getSPIRVTypeID(GenericPtrTy))
3021 .addUse(SrcPtr)
3022 .constrainAllUses(TII, TRI, RBI);
3023 BuildMI(BB, I, DL, TII.get(SPIRV::OpGenericCastToPtr))
3024 .addDef(ResVReg)
3025 .addUse(GR.getSPIRVTypeID(ResType))
3026 .addUse(Tmp)
3027 .constrainAllUses(TII, TRI, RBI);
3028 return true;
3029 }
3030
3031 // Check if instructions from the SPV_INTEL_usm_storage_classes extension may
3032 // be applied
3033 if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::CrossWorkgroup)
3034 return selectUnOp(ResVReg, ResType, I,
3035 SPIRV::OpPtrCastToCrossWorkgroupINTEL);
3036 if (SrcSC == SPIRV::StorageClass::CrossWorkgroup && isUSMStorageClass(DstSC))
3037 return selectUnOp(ResVReg, ResType, I,
3038 SPIRV::OpCrossWorkgroupCastToPtrINTEL);
3039 if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::Generic)
3040 return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
3041 if (SrcSC == SPIRV::StorageClass::Generic && isUSMStorageClass(DstSC))
3042 return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
3043
3044 // Bitcast for pointers requires that the address spaces must match
3045 return false;
3046}
3047
3048// G_PTRMASK - Apply a bitmask to a pointer value.
3049// Result = Ptr & Mask
3050// We need to convert the pointer to an integer, perform the AND operation,
3051// and convert back to a pointer.
3052bool SPIRVInstructionSelector::selectPtrMask(Register ResVReg,
3053 SPIRVTypeInst ResType,
3054 MachineInstr &I) const {
3055 if (STI.isLogicalSPIRV())
3056 return diagnoseUnsupported(
3057 I, "G_PTRMASK is not supported with logical SPIR-V");
3058 MachineBasicBlock &BB = *I.getParent();
3059 MachineFunction &MF = *BB.getParent();
3060 const DebugLoc &DL = I.getDebugLoc();
3061
3062 Register PtrReg = I.getOperand(1).getReg();
3063 Register MaskReg = I.getOperand(2).getReg();
3064
3065 SPIRVTypeInst MaskType = GR.getSPIRVTypeForVReg(MaskReg);
3066
3067 // Convert pointer to integer.
3068 Register PtrAsInt = MRI->createVirtualRegister(GR.getRegClass(MaskType));
3069 GR.assignSPIRVTypeToVReg(MaskType, PtrAsInt, MF);
3070
3071 BuildMI(BB, I, DL, TII.get(SPIRV::OpConvertPtrToU))
3072 .addDef(PtrAsInt)
3073 .addUse(GR.getSPIRVTypeID(MaskType))
3074 .addUse(PtrReg)
3075 .constrainAllUses(TII, TRI, RBI);
3076
3077 // Perform bitwise AND.
3078 Register MaskedInt = MRI->createVirtualRegister(GR.getRegClass(MaskType));
3079 GR.assignSPIRVTypeToVReg(MaskType, MaskedInt, MF);
3080
3081 unsigned AndOpcode = GR.getScalarOrVectorComponentCount(MaskType) > 1
3082 ? SPIRV::OpBitwiseAndV
3083 : SPIRV::OpBitwiseAndS;
3084
3085 BuildMI(BB, I, DL, TII.get(AndOpcode))
3086 .addDef(MaskedInt)
3087 .addUse(GR.getSPIRVTypeID(MaskType))
3088 .addUse(PtrAsInt)
3089 .addUse(MaskReg)
3090 .constrainAllUses(TII, TRI, RBI);
3091
3092 // Convert integer back to pointer.
3093 BuildMI(BB, I, DL, TII.get(SPIRV::OpConvertUToPtr))
3094 .addDef(ResVReg)
3095 .addUse(GR.getSPIRVTypeID(ResType))
3096 .addUse(MaskedInt)
3097 .constrainAllUses(TII, TRI, RBI);
3098
3099 return true;
3100}
3101
3102static unsigned getFCmpOpcode(unsigned PredNum) {
3103 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
3104 switch (Pred) {
3105 case CmpInst::FCMP_OEQ:
3106 return SPIRV::OpFOrdEqual;
3107 case CmpInst::FCMP_OGE:
3108 return SPIRV::OpFOrdGreaterThanEqual;
3109 case CmpInst::FCMP_OGT:
3110 return SPIRV::OpFOrdGreaterThan;
3111 case CmpInst::FCMP_OLE:
3112 return SPIRV::OpFOrdLessThanEqual;
3113 case CmpInst::FCMP_OLT:
3114 return SPIRV::OpFOrdLessThan;
3115 case CmpInst::FCMP_ONE:
3116 return SPIRV::OpFOrdNotEqual;
3117 case CmpInst::FCMP_ORD:
3118 return SPIRV::OpOrdered;
3119 case CmpInst::FCMP_UEQ:
3120 return SPIRV::OpFUnordEqual;
3121 case CmpInst::FCMP_UGE:
3122 return SPIRV::OpFUnordGreaterThanEqual;
3123 case CmpInst::FCMP_UGT:
3124 return SPIRV::OpFUnordGreaterThan;
3125 case CmpInst::FCMP_ULE:
3126 return SPIRV::OpFUnordLessThanEqual;
3127 case CmpInst::FCMP_ULT:
3128 return SPIRV::OpFUnordLessThan;
3129 case CmpInst::FCMP_UNE:
3130 return SPIRV::OpFUnordNotEqual;
3131 case CmpInst::FCMP_UNO:
3132 return SPIRV::OpUnordered;
3133 default:
3134 llvm_unreachable("Unknown predicate type for FCmp");
3135 }
3136}
3137
3138static unsigned getICmpOpcode(unsigned PredNum) {
3139 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
3140 switch (Pred) {
3141 case CmpInst::ICMP_EQ:
3142 return SPIRV::OpIEqual;
3143 case CmpInst::ICMP_NE:
3144 return SPIRV::OpINotEqual;
3145 case CmpInst::ICMP_SGE:
3146 return SPIRV::OpSGreaterThanEqual;
3147 case CmpInst::ICMP_SGT:
3148 return SPIRV::OpSGreaterThan;
3149 case CmpInst::ICMP_SLE:
3150 return SPIRV::OpSLessThanEqual;
3151 case CmpInst::ICMP_SLT:
3152 return SPIRV::OpSLessThan;
3153 case CmpInst::ICMP_UGE:
3154 return SPIRV::OpUGreaterThanEqual;
3155 case CmpInst::ICMP_UGT:
3156 return SPIRV::OpUGreaterThan;
3157 case CmpInst::ICMP_ULE:
3158 return SPIRV::OpULessThanEqual;
3159 case CmpInst::ICMP_ULT:
3160 return SPIRV::OpULessThan;
3161 default:
3162 llvm_unreachable("Unknown predicate type for ICmp");
3163 }
3164}
3165
3166static unsigned getPtrCmpOpcode(unsigned Pred) {
3167 switch (static_cast<CmpInst::Predicate>(Pred)) {
3168 case CmpInst::ICMP_EQ:
3169 return SPIRV::OpPtrEqual;
3170 case CmpInst::ICMP_NE:
3171 return SPIRV::OpPtrNotEqual;
3172 default:
3173 llvm_unreachable("Unknown predicate type for pointer comparison");
3174 }
3175}
3176
3177// Return the logical operation, or abort if none exists.
3178static unsigned getBoolCmpOpcode(unsigned PredNum) {
3179 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
3180 switch (Pred) {
3181 case CmpInst::ICMP_EQ:
3182 return SPIRV::OpLogicalEqual;
3183 case CmpInst::ICMP_NE:
3184 return SPIRV::OpLogicalNotEqual;
3185 default:
3186 llvm_unreachable("Unknown predicate type for Bool comparison");
3187 }
3188}
3189
3190static APFloat getZeroFP(const Type *LLVMFloatTy) {
3191 if (!LLVMFloatTy)
3193 switch (LLVMFloatTy->getScalarType()->getTypeID()) {
3194 case Type::HalfTyID:
3196 case Type::BFloatTyID:
3198 default:
3199 case Type::FloatTyID:
3201 case Type::DoubleTyID:
3203 }
3204}
3205
3206static APFloat getOneFP(const Type *LLVMFloatTy) {
3207 if (!LLVMFloatTy)
3209 switch (LLVMFloatTy->getScalarType()->getTypeID()) {
3210 case Type::HalfTyID:
3212 case Type::BFloatTyID:
3214 default:
3215 case Type::FloatTyID:
3217 case Type::DoubleTyID:
3219 }
3220}
3221
3222bool SPIRVInstructionSelector::selectAnyOrAll(Register ResVReg,
3223 SPIRVTypeInst ResType,
3224 MachineInstr &I,
3225 unsigned OpAnyOrAll) const {
3226 assert(I.getNumOperands() == 3);
3227 assert(I.getOperand(2).isReg());
3228 MachineBasicBlock &BB = *I.getParent();
3229 Register InputRegister = I.getOperand(2).getReg();
3230 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
3231
3232 assert(InputType && "VReg has no type assigned");
3233
3234 bool IsBoolTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeBool);
3235 if (IsBoolTy && !isVectorType(InputType)) {
3236 assert(ResVReg == I.getOperand(0).getReg());
3237 return BuildCOPY(ResVReg, InputRegister, I);
3238 }
3239
3240 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
3241 unsigned SpirvNotEqualId =
3242 IsFloatTy ? SPIRV::OpFOrdNotEqual : SPIRV::OpINotEqual;
3243 SPIRVTypeInst SpvBoolScalarTy = GR.getOrCreateSPIRVBoolType(I, TII);
3244 SPIRVTypeInst SpvBoolTy = SpvBoolScalarTy;
3245 Register NotEqualReg = ResVReg;
3246
3247 if (isVectorType(InputType)) {
3248 NotEqualReg =
3249 IsBoolTy ? InputRegister
3250 : createVirtualRegister(SpvBoolTy, &GR, MRI, MRI->getMF());
3251 const unsigned NumElts = GR.getScalarOrVectorComponentCount(InputType);
3252 SpvBoolTy = GR.getOrCreateSPIRVVectorType(SpvBoolTy, NumElts, I, TII);
3253 }
3254
3255 if (!IsBoolTy) {
3256 Register ConstZeroReg =
3257 IsFloatTy ? buildZerosValF(InputType, I) : buildZerosVal(InputType, I);
3258
3259 BuildMI(BB, I, I.getDebugLoc(), TII.get(SpirvNotEqualId))
3260 .addDef(NotEqualReg)
3261 .addUse(GR.getSPIRVTypeID(SpvBoolTy))
3262 .addUse(InputRegister)
3263 .addUse(ConstZeroReg)
3264 .constrainAllUses(TII, TRI, RBI);
3265 }
3266
3267 if (isVectorType(InputType))
3268 BuildMI(BB, I, I.getDebugLoc(), TII.get(OpAnyOrAll))
3269 .addDef(ResVReg)
3270 .addUse(GR.getSPIRVTypeID(SpvBoolScalarTy))
3271 .addUse(NotEqualReg)
3272 .constrainAllUses(TII, TRI, RBI);
3273 return true;
3274}
3275
3276bool SPIRVInstructionSelector::selectAll(Register ResVReg,
3277 SPIRVTypeInst ResType,
3278 MachineInstr &I) const {
3279 return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAll);
3280}
3281
3282bool SPIRVInstructionSelector::selectAny(Register ResVReg,
3283 SPIRVTypeInst ResType,
3284 MachineInstr &I) const {
3285 return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAny);
3286}
3287
3288// Select the OpDot instruction for the given float dot
3289bool SPIRVInstructionSelector::selectFloatDot(Register ResVReg,
3290 SPIRVTypeInst ResType,
3291 MachineInstr &I) const {
3292 assert(I.getNumOperands() == 4);
3293 assert(I.getOperand(2).isReg());
3294 assert(I.getOperand(3).isReg());
3295
3296 [[maybe_unused]] SPIRVTypeInst VecType =
3297 GR.getSPIRVTypeForVReg(I.getOperand(2).getReg());
3298
3299 assert(((VecType->getOpcode() == SPIRV::OpTypeVector &&
3300 GR.getScalarOrVectorComponentCount(VecType) > 1) ||
3301 VecType->getOpcode() == SPIRV::OpTypeVectorIdEXT) &&
3302 "dot product requires either a vector of at least 2 components or"
3303 " the SPV_EXT_long vector extension.");
3304
3305 [[maybe_unused]] SPIRVTypeInst EltType =
3307
3308 assert(EltType->getOpcode() == SPIRV::OpTypeFloat);
3309
3310 MachineBasicBlock &BB = *I.getParent();
3311 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpDot))
3312 .addDef(ResVReg)
3313 .addUse(GR.getSPIRVTypeID(ResType))
3314 .addUse(I.getOperand(2).getReg())
3315 .addUse(I.getOperand(3).getReg())
3316 .constrainAllUses(TII, TRI, RBI);
3317 return true;
3318}
3319
3320bool SPIRVInstructionSelector::selectIntegerDot(Register ResVReg,
3321 SPIRVTypeInst ResType,
3322 MachineInstr &I,
3323 bool Signed) const {
3324 assert(I.getNumOperands() == 4);
3325 assert(I.getOperand(2).isReg());
3326 assert(I.getOperand(3).isReg());
3327 MachineBasicBlock &BB = *I.getParent();
3328
3329 auto DotOp = Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
3330 BuildMI(BB, I, I.getDebugLoc(), TII.get(DotOp))
3331 .addDef(ResVReg)
3332 .addUse(GR.getSPIRVTypeID(ResType))
3333 .addUse(I.getOperand(2).getReg())
3334 .addUse(I.getOperand(3).getReg())
3335 .constrainAllUses(TII, TRI, RBI);
3336 return true;
3337}
3338
3339// Since pre-1.6 SPIRV has no integer dot implementation,
3340// expand by piecewise multiplying and adding the results
3341bool SPIRVInstructionSelector::selectIntegerDotExpansion(
3342 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3343 assert(I.getNumOperands() == 4);
3344 assert(I.getOperand(2).isReg());
3345 assert(I.getOperand(3).isReg());
3346 MachineBasicBlock &BB = *I.getParent();
3347
3348 // Multiply the vectors, then sum the results
3349 Register Vec0 = I.getOperand(2).getReg();
3350 Register Vec1 = I.getOperand(3).getReg();
3351 Register TmpVec = MRI->createVirtualRegister(GR.getRegClass(ResType));
3352 SPIRVTypeInst VecType = GR.getSPIRVTypeForVReg(Vec0);
3353
3354 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIMulV))
3355 .addDef(TmpVec)
3356 .addUse(GR.getSPIRVTypeID(VecType))
3357 .addUse(Vec0)
3358 .addUse(Vec1)
3359 .constrainAllUses(TII, TRI, RBI);
3360
3361 assert(((VecType->getOpcode() == SPIRV::OpTypeVector &&
3362 GR.getScalarOrVectorComponentCount(VecType) > 1) ||
3363 VecType->getOpcode() == SPIRV::OpTypeVectorIdEXT) &&
3364 "dot product requires either a vector of at least 2 components "
3365 "or the SPV_EXT_long_vector extension.");
3366
3367 Register Res = MRI->createVirtualRegister(GR.getRegClass(ResType));
3368 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
3369 .addDef(Res)
3370 .addUse(GR.getSPIRVTypeID(ResType))
3371 .addUse(TmpVec)
3372 .addImm(0)
3373 .constrainAllUses(TII, TRI, RBI);
3374
3375 for (unsigned i = 1; i < GR.getScalarOrVectorComponentCount(VecType); i++) {
3376 Register Elt = MRI->createVirtualRegister(GR.getRegClass(ResType));
3377
3378 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
3379 .addDef(Elt)
3380 .addUse(GR.getSPIRVTypeID(ResType))
3381 .addUse(TmpVec)
3382 .addImm(i)
3383 .constrainAllUses(TII, TRI, RBI);
3384
3385 Register Sum = i < GR.getScalarOrVectorComponentCount(VecType) - 1
3386 ? MRI->createVirtualRegister(GR.getRegClass(ResType))
3387 : ResVReg;
3388
3389 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
3390 .addDef(Sum)
3391 .addUse(GR.getSPIRVTypeID(ResType))
3392 .addUse(Res)
3393 .addUse(Elt)
3394 .constrainAllUses(TII, TRI, RBI);
3395 Res = Sum;
3396 }
3397
3398 return true;
3399}
3400
3401bool SPIRVInstructionSelector::selectOpIsInf(Register ResVReg,
3402 SPIRVTypeInst ResType,
3403 MachineInstr &I) const {
3404 MachineBasicBlock &BB = *I.getParent();
3405 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsInf))
3406 .addDef(ResVReg)
3407 .addUse(GR.getSPIRVTypeID(ResType))
3408 .addUse(I.getOperand(2).getReg())
3409 .constrainAllUses(TII, TRI, RBI);
3410 return true;
3411}
3412
3413bool SPIRVInstructionSelector::selectOpIsNan(Register ResVReg,
3414 SPIRVTypeInst ResType,
3415 MachineInstr &I) const {
3416 MachineBasicBlock &BB = *I.getParent();
3417 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsNan))
3418 .addDef(ResVReg)
3419 .addUse(GR.getSPIRVTypeID(ResType))
3420 .addUse(I.getOperand(2).getReg())
3421 .constrainAllUses(TII, TRI, RBI);
3422 return true;
3423}
3424
3425bool SPIRVInstructionSelector::selectOpIsFinite(Register ResVReg,
3426 SPIRVTypeInst ResType,
3427 MachineInstr &I) const {
3428 MachineBasicBlock &BB = *I.getParent();
3429 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsFinite))
3430 .addDef(ResVReg)
3431 .addUse(GR.getSPIRVTypeID(ResType))
3432 .addUse(I.getOperand(2).getReg())
3433 .constrainAllUses(TII, TRI, RBI);
3434 return true;
3435}
3436
3437bool SPIRVInstructionSelector::selectOpIsNormal(Register ResVReg,
3438 SPIRVTypeInst ResType,
3439 MachineInstr &I) const {
3440 MachineBasicBlock &BB = *I.getParent();
3441 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsNormal))
3442 .addDef(ResVReg)
3443 .addUse(GR.getSPIRVTypeID(ResType))
3444 .addUse(I.getOperand(2).getReg())
3445 .constrainAllUses(TII, TRI, RBI);
3446 return true;
3447}
3448
3449template <bool Signed>
3450bool SPIRVInstructionSelector::selectDot4AddPacked(Register ResVReg,
3451 SPIRVTypeInst ResType,
3452 MachineInstr &I) const {
3453 assert(I.getNumOperands() == 5);
3454 assert(I.getOperand(2).isReg());
3455 assert(I.getOperand(3).isReg());
3456 assert(I.getOperand(4).isReg());
3457 MachineBasicBlock &BB = *I.getParent();
3458
3459 Register Acc = I.getOperand(2).getReg();
3460 Register X = I.getOperand(3).getReg();
3461 Register Y = I.getOperand(4).getReg();
3462
3463 auto DotOp = Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
3464 Register Dot = MRI->createVirtualRegister(GR.getRegClass(ResType));
3465 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(DotOp))
3466 .addDef(Dot)
3467 .addUse(GR.getSPIRVTypeID(ResType))
3468 .addUse(X)
3469 .addUse(Y);
3470 MIB.addImm(SPIRV::BuiltIn::PackedVectorFormat4x8Bit);
3471 MIB.constrainAllUses(TII, TRI, RBI);
3472
3473 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
3474 .addDef(ResVReg)
3475 .addUse(GR.getSPIRVTypeID(ResType))
3476 .addUse(Dot)
3477 .addUse(Acc)
3478 .constrainAllUses(TII, TRI, RBI);
3479 return true;
3480}
3481
3482// Since pre-1.6 SPIRV has no DotProductInput4x8BitPacked implementation,
3483// extract the elements of the packed inputs, multiply them and add the result
3484// to the accumulator.
3485template <bool Signed>
3486bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
3487 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3488 assert(I.getNumOperands() == 5);
3489 assert(I.getOperand(2).isReg());
3490 assert(I.getOperand(3).isReg());
3491 assert(I.getOperand(4).isReg());
3492 MachineBasicBlock &BB = *I.getParent();
3493
3494 Register Acc = I.getOperand(2).getReg();
3495 Register X = I.getOperand(3).getReg();
3496 Register Y = I.getOperand(4).getReg();
3497
3498 SPIRVTypeInst EltType = GR.getOrCreateSPIRVIntegerType(8, I, TII);
3499 auto ExtractOp =
3500 Signed ? SPIRV::OpBitFieldSExtract : SPIRV::OpBitFieldUExtract;
3501
3502 bool ZeroAsNull = !STI.isShader();
3503 // Extract the i8 element, multiply and add it to the accumulator
3504 for (unsigned i = 0; i < 4; i++) {
3505 // A[i]
3506 Register AElt = MRI->createVirtualRegister(&SPIRV::IDRegClass);
3507 BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
3508 .addDef(AElt)
3509 .addUse(GR.getSPIRVTypeID(ResType))
3510 .addUse(X)
3511 .addUse(GR.getOrCreateConstInt(i * 8, I, EltType, TII, ZeroAsNull))
3512 .addUse(GR.getOrCreateConstInt(8, I, EltType, TII, ZeroAsNull))
3513 .constrainAllUses(TII, TRI, RBI);
3514
3515 // B[i]
3516 Register BElt = MRI->createVirtualRegister(&SPIRV::IDRegClass);
3517 BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
3518 .addDef(BElt)
3519 .addUse(GR.getSPIRVTypeID(ResType))
3520 .addUse(Y)
3521 .addUse(GR.getOrCreateConstInt(i * 8, I, EltType, TII, ZeroAsNull))
3522 .addUse(GR.getOrCreateConstInt(8, I, EltType, TII, ZeroAsNull))
3523 .constrainAllUses(TII, TRI, RBI);
3524
3525 // A[i] * B[i]
3526 Register Mul = MRI->createVirtualRegister(&SPIRV::IDRegClass);
3527 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIMulS))
3528 .addDef(Mul)
3529 .addUse(GR.getSPIRVTypeID(ResType))
3530 .addUse(AElt)
3531 .addUse(BElt)
3532 .constrainAllUses(TII, TRI, RBI);
3533
3534 // Discard 24 highest-bits so that stored i32 register is i8 equivalent
3535 Register MaskMul = MRI->createVirtualRegister(&SPIRV::IDRegClass);
3536 BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
3537 .addDef(MaskMul)
3538 .addUse(GR.getSPIRVTypeID(ResType))
3539 .addUse(Mul)
3540 .addUse(GR.getOrCreateConstInt(0, I, EltType, TII, ZeroAsNull))
3541 .addUse(GR.getOrCreateConstInt(8, I, EltType, TII, ZeroAsNull))
3542 .constrainAllUses(TII, TRI, RBI);
3543
3544 // Acc = Acc + A[i] * B[i]
3545 Register Sum =
3546 i < 3 ? MRI->createVirtualRegister(&SPIRV::IDRegClass) : ResVReg;
3547 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
3548 .addDef(Sum)
3549 .addUse(GR.getSPIRVTypeID(ResType))
3550 .addUse(Acc)
3551 .addUse(MaskMul)
3552 .constrainAllUses(TII, TRI, RBI);
3553
3554 Acc = Sum;
3555 }
3556
3557 return true;
3558}
3559
3560/// Transform saturate(x) to clamp(x, 0.0f, 1.0f) as SPIRV
3561/// does not have a saturate builtin.
3562bool SPIRVInstructionSelector::selectSaturate(Register ResVReg,
3563 SPIRVTypeInst ResType,
3564 MachineInstr &I) const {
3565 assert(I.getNumOperands() == 3);
3566 assert(I.getOperand(2).isReg());
3567 MachineBasicBlock &BB = *I.getParent();
3568 Register VZero = buildZerosValF(ResType, I);
3569 Register VOne = buildOnesValF(ResType, I);
3570
3571 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
3572 .addDef(ResVReg)
3573 .addUse(GR.getSPIRVTypeID(ResType))
3574 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
3575 .addImm(GL::FClamp)
3576 .addUse(I.getOperand(2).getReg())
3577 .addUse(VZero)
3578 .addUse(VOne)
3579 .constrainAllUses(TII, TRI, RBI);
3580 return true;
3581}
3582
3583bool SPIRVInstructionSelector::selectSign(Register ResVReg,
3584 SPIRVTypeInst ResType,
3585 MachineInstr &I) const {
3586 assert(I.getNumOperands() == 3);
3587 assert(I.getOperand(2).isReg());
3588 MachineBasicBlock &BB = *I.getParent();
3589 Register InputRegister = I.getOperand(2).getReg();
3590 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
3591 auto &DL = I.getDebugLoc();
3592
3593 if (!InputType)
3594 return diagnoseUnsupported(I, "Input Type could not be determined.");
3595
3596 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
3597
3598 unsigned SignBitWidth = GR.getScalarOrVectorBitWidth(InputType);
3599 unsigned ResBitWidth = GR.getScalarOrVectorBitWidth(ResType);
3600
3601 bool NeedsConversion = IsFloatTy || SignBitWidth != ResBitWidth;
3602
3603 auto SignOpcode = IsFloatTy ? GL::FSign : GL::SSign;
3604 Register SignReg = NeedsConversion
3605 ? MRI->createVirtualRegister(&SPIRV::IDRegClass)
3606 : ResVReg;
3607
3608 BuildMI(BB, I, DL, TII.get(SPIRV::OpExtInst))
3609 .addDef(SignReg)
3610 .addUse(GR.getSPIRVTypeID(InputType))
3611 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
3612 .addImm(SignOpcode)
3613 .addUse(InputRegister)
3614 .constrainAllUses(TII, TRI, RBI);
3615
3616 if (NeedsConversion) {
3617 auto ConvertOpcode = IsFloatTy ? SPIRV::OpConvertFToS : SPIRV::OpSConvert;
3618 BuildMI(*I.getParent(), I, DL, TII.get(ConvertOpcode))
3619 .addDef(ResVReg)
3620 .addUse(GR.getSPIRVTypeID(ResType))
3621 .addUse(SignReg)
3622 .constrainAllUses(TII, TRI, RBI);
3623 }
3624
3625 return true;
3626}
3627
3628bool SPIRVInstructionSelector::selectWaveOpInst(Register ResVReg,
3629 SPIRVTypeInst ResType,
3630 MachineInstr &I,
3631 unsigned Opcode) const {
3632 MachineBasicBlock &BB = *I.getParent();
3633 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3634
3635 auto BMI = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3636 .addDef(ResVReg)
3637 .addUse(GR.getSPIRVTypeID(ResType))
3638 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I,
3639 IntTy, TII, !STI.isShader()));
3640
3641 for (unsigned J = 2; J < I.getNumOperands(); J++) {
3642 BMI.addUse(I.getOperand(J).getReg());
3643 }
3644
3645 BMI.constrainAllUses(TII, TRI, RBI);
3646 return true;
3647}
3648
3649bool SPIRVInstructionSelector::selectBarrierInst(MachineInstr &I,
3650 unsigned Scope,
3651 unsigned MemSem,
3652 bool WithGroupSync) const {
3653 auto BarrierType =
3654 WithGroupSync ? SPIRV::OpControlBarrier : SPIRV::OpMemoryBarrier;
3655
3656 MemSem |= SPIRV::MemorySemantics::AcquireRelease;
3657
3658 assert(((Scope != SPIRV::Scope::Workgroup) ||
3659 ((MemSem & SPIRV::MemorySemantics::WorkgroupMemory) > 0)) &&
3660 "Workgroup Scope must set WorkGroupMemory semantic "
3661 "in Barrier instruction");
3662
3663 assert(((Scope != SPIRV::Scope::Device) ||
3664 ((MemSem & SPIRV::MemorySemantics::UniformMemory) > 0 &&
3665 (MemSem & SPIRV::MemorySemantics::ImageMemory) > 0)) &&
3666 "Device Scope must set UniformMemory and ImageMemory semantic "
3667 "in Barrier instruction");
3668
3669 MachineBasicBlock &BB = *I.getParent();
3670 auto MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(BarrierType));
3671
3672 // OpControlBarrier needs to also set Execution Scope
3673 if (WithGroupSync) {
3674 Register ExecReg = buildI32Constant(SPIRV::Scope::Workgroup, I);
3675 MI.addUse(ExecReg);
3676 }
3677
3678 Register ScopeReg = buildI32Constant(Scope, I);
3679 Register MemSemReg = buildI32Constant(MemSem, I);
3680
3681 MI.addUse(ScopeReg).addUse(MemSemReg).constrainAllUses(TII, TRI, RBI);
3682 return true;
3683}
3684
3685bool SPIRVInstructionSelector::selectWaveActiveCountBits(
3686 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3687
3688 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3689 SPIRVTypeInst BallotType = GR.getOrCreateSPIRVVectorType(IntTy, 4, I, TII);
3690 Register BallotReg = MRI->createVirtualRegister(GR.getRegClass(BallotType));
3691 if (!selectWaveOpInst(BallotReg, BallotType, I,
3692 SPIRV::OpGroupNonUniformBallot))
3693 return false;
3694
3695 MachineBasicBlock &BB = *I.getParent();
3696 BuildMI(BB, I, I.getDebugLoc(),
3697 TII.get(SPIRV::OpGroupNonUniformBallotBitCount))
3698 .addDef(ResVReg)
3699 .addUse(GR.getSPIRVTypeID(ResType))
3700 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
3701 !STI.isShader()))
3702 .addImm(SPIRV::GroupOperation::Reduce)
3703 .addUse(BallotReg)
3704 .constrainAllUses(TII, TRI, RBI);
3705
3706 return true;
3707}
3708
3709bool SPIRVInstructionSelector::selectWaveActiveAllEqual(Register ResVReg,
3710 SPIRVTypeInst ResType,
3711 MachineInstr &I) const {
3712 MachineBasicBlock &BB = *I.getParent();
3713 const DebugLoc &DL = I.getDebugLoc();
3714
3715 // Input to the intrinsic
3716 Register InputReg = I.getOperand(2).getReg();
3717 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputReg);
3718
3719 // Determine if input is vector
3720 unsigned NumElems = GR.getScalarOrVectorComponentCount(InputType);
3721 bool IsVector = NumElems > 1 ||
3722 (InputType->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
3723 STI.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector));
3724
3725 // Determine element types
3726 SPIRVTypeInst ElemInputType = GR.getScalarOrVectorComponentType(InputType);
3727 SPIRVTypeInst ElemBoolType = GR.getScalarOrVectorComponentType(ResType);
3728
3729 // Subgroup scope constant
3730 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3731 Register ScopeConst = GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy,
3732 TII, !STI.isShader());
3733
3734 // Scalar case
3735 if (!IsVector) {
3736 return selectWaveOpInst(ResVReg, ElemBoolType, I,
3737 SPIRV::OpGroupNonUniformAllEqual);
3738 }
3739
3740 // Vector case
3741 SmallVector<Register, 4> ElementResults;
3742 ElementResults.reserve(NumElems);
3743
3744 for (unsigned Idx = 0; Idx < NumElems; ++Idx) {
3745 // Extract element
3746 Register ElemInput = InputReg;
3747 Register Extracted =
3748 MRI->createVirtualRegister(GR.getRegClass(ElemInputType));
3749
3750 BuildMI(BB, I, DL, TII.get(SPIRV::OpCompositeExtract))
3751 .addDef(Extracted)
3752 .addUse(GR.getSPIRVTypeID(ElemInputType))
3753 .addUse(InputReg)
3754 .addImm(Idx)
3755 .constrainAllUses(TII, TRI, RBI);
3756
3757 ElemInput = Extracted;
3758
3759 // Emit per-element AllEqual
3760 Register ElemResult =
3761 MRI->createVirtualRegister(GR.getRegClass(ElemBoolType));
3762
3763 BuildMI(BB, I, DL, TII.get(SPIRV::OpGroupNonUniformAllEqual))
3764 .addDef(ElemResult)
3765 .addUse(GR.getSPIRVTypeID(ElemBoolType))
3766 .addUse(ScopeConst)
3767 .addUse(ElemInput)
3768 .constrainAllUses(TII, TRI, RBI);
3769
3770 ElementResults.push_back(ElemResult);
3771 }
3772
3773 // Reconstruct vector<bool>
3774 auto MIB = BuildMI(BB, I, DL, TII.get(SPIRV::OpCompositeConstruct))
3775 .addDef(ResVReg)
3776 .addUse(GR.getSPIRVTypeID(ResType));
3777 for (Register R : ElementResults)
3778 MIB.addUse(R);
3779
3780 MIB.constrainAllUses(TII, TRI, RBI);
3781
3782 return true;
3783}
3784
3785bool SPIRVInstructionSelector::selectWavePrefixBitCount(Register ResVReg,
3786 SPIRVTypeInst ResType,
3787 MachineInstr &I) const {
3788
3789 assert(I.getNumOperands() == 3);
3790
3791 auto Op = I.getOperand(2);
3792 assert(Op.isReg());
3793
3794 MachineBasicBlock &BB = *I.getParent();
3795 DebugLoc DL = I.getDebugLoc();
3796
3797 Register InputRegister = Op.getReg();
3798 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
3799
3800 if (!InputType)
3801 return diagnoseUnsupported(I, "Input Type could not be determined.");
3802
3803 if (InputType->getOpcode() != SPIRV::OpTypeBool)
3804 return diagnoseUnsupported(I, "WavePrefixBitCount requires boolean input");
3805
3806 // Types
3807 SPIRVTypeInst Int32Ty = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3808
3809 // Ballot result type: vector<uint32>
3810 // Match DXC: %v4uint for Subgroup size
3811 SPIRVTypeInst BallotTy = GR.getOrCreateSPIRVVectorType(Int32Ty, 4, I, TII);
3812
3813 // Create a vreg for the ballot result
3814 Register BallotVReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
3815
3816 // 1. OpGroupNonUniformBallot
3817 BuildMI(BB, I, DL, TII.get(SPIRV::OpGroupNonUniformBallot))
3818 .addDef(BallotVReg)
3819 .addUse(GR.getSPIRVTypeID(BallotTy))
3820 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, Int32Ty, TII))
3821 .addUse(InputRegister)
3822 .constrainAllUses(TII, TRI, RBI);
3823
3824 // 2. OpGroupNonUniformBallotBitCount
3825 BuildMI(BB, I, DL, TII.get(SPIRV::OpGroupNonUniformBallotBitCount))
3826 .addDef(ResVReg)
3827 .addUse(GR.getSPIRVTypeID(ResType))
3828 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, Int32Ty, TII))
3829 .addImm(SPIRV::GroupOperation::ExclusiveScan)
3830 .addUse(BallotVReg)
3831 .constrainAllUses(TII, TRI, RBI);
3832
3833 return true;
3834}
3835
3836bool SPIRVInstructionSelector::selectWaveReduceMax(Register ResVReg,
3837 SPIRVTypeInst ResType,
3838 MachineInstr &I,
3839 bool IsUnsigned) const {
3840 return selectWaveReduce(
3841 ResVReg, ResType, I, IsUnsigned,
3842 [&](Register InputRegister, bool IsUnsigned) {
3843 const bool IsFloatTy =
3844 GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
3845 const auto IntOp = IsUnsigned ? SPIRV::OpGroupNonUniformUMax
3846 : SPIRV::OpGroupNonUniformSMax;
3847 return IsFloatTy ? SPIRV::OpGroupNonUniformFMax : IntOp;
3848 });
3849}
3850
3851bool SPIRVInstructionSelector::selectWaveReduceMin(Register ResVReg,
3852 SPIRVTypeInst ResType,
3853 MachineInstr &I,
3854 bool IsUnsigned) const {
3855 return selectWaveReduce(
3856 ResVReg, ResType, I, IsUnsigned,
3857 [&](Register InputRegister, bool IsUnsigned) {
3858 const bool IsFloatTy =
3859 GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
3860 const auto IntOp = IsUnsigned ? SPIRV::OpGroupNonUniformUMin
3861 : SPIRV::OpGroupNonUniformSMin;
3862 return IsFloatTy ? SPIRV::OpGroupNonUniformFMin : IntOp;
3863 });
3864}
3865
3866bool SPIRVInstructionSelector::selectWaveReduceSum(Register ResVReg,
3867 SPIRVTypeInst ResType,
3868 MachineInstr &I) const {
3869 return selectWaveReduce(ResVReg, ResType, I, /*IsUnsigned*/ false,
3870 [&](Register InputRegister, bool IsUnsigned) {
3871 bool IsFloatTy = GR.isScalarOrVectorOfType(
3872 InputRegister, SPIRV::OpTypeFloat);
3873 return IsFloatTy ? SPIRV::OpGroupNonUniformFAdd
3874 : SPIRV::OpGroupNonUniformIAdd;
3875 });
3876}
3877
3878bool SPIRVInstructionSelector::selectWaveReduceProduct(Register ResVReg,
3879 SPIRVTypeInst ResType,
3880 MachineInstr &I) const {
3881 return selectWaveReduce(ResVReg, ResType, I, /*IsUnsigned*/ false,
3882 [&](Register InputRegister, bool IsUnsigned) {
3883 bool IsFloatTy = GR.isScalarOrVectorOfType(
3884 InputRegister, SPIRV::OpTypeFloat);
3885 return IsFloatTy ? SPIRV::OpGroupNonUniformFMul
3886 : SPIRV::OpGroupNonUniformIMul;
3887 });
3888}
3889
3890template <typename PickOpcodeFn>
3891bool SPIRVInstructionSelector::selectWaveReduce(
3892 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, bool IsUnsigned,
3893 PickOpcodeFn &&PickOpcode) const {
3894 assert(I.getNumOperands() == 3);
3895 assert(I.getOperand(2).isReg());
3896 MachineBasicBlock &BB = *I.getParent();
3897 Register InputRegister = I.getOperand(2).getReg();
3898 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
3899
3900 if (!InputType)
3901 return diagnoseUnsupported(I, "Input Type could not be determined.");
3902
3903 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3904 const unsigned Opcode = PickOpcode(InputRegister, IsUnsigned);
3905 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3906 .addDef(ResVReg)
3907 .addUse(GR.getSPIRVTypeID(ResType))
3908 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
3909 !STI.isShader()))
3910 .addImm(SPIRV::GroupOperation::Reduce)
3911 .addUse(I.getOperand(2).getReg())
3912 .constrainAllUses(TII, TRI, RBI);
3913 return true;
3914}
3915
3916bool SPIRVInstructionSelector::selectWaveReduceOp(Register ResVReg,
3917 SPIRVTypeInst ResType,
3918 MachineInstr &I,
3919 unsigned Opcode) const {
3920 return selectWaveReduce(
3921 ResVReg, ResType, I, false,
3922 [&](Register InputRegister, bool IsUnsigned) { return Opcode; });
3923}
3924
3925bool SPIRVInstructionSelector::selectWaveExclusiveScanSum(
3926 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3927 return selectWaveExclusiveScan(ResVReg, ResType, I, /*IsUnsigned*/ false,
3928 [&](Register InputRegister, bool IsUnsigned) {
3929 bool IsFloatTy = GR.isScalarOrVectorOfType(
3930 InputRegister, SPIRV::OpTypeFloat);
3931 return IsFloatTy
3932 ? SPIRV::OpGroupNonUniformFAdd
3933 : SPIRV::OpGroupNonUniformIAdd;
3934 });
3935}
3936
3937bool SPIRVInstructionSelector::selectWaveExclusiveScanProduct(
3938 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3939 return selectWaveExclusiveScan(ResVReg, ResType, I, /*IsUnsigned*/ false,
3940 [&](Register InputRegister, bool IsUnsigned) {
3941 bool IsFloatTy = GR.isScalarOrVectorOfType(
3942 InputRegister, SPIRV::OpTypeFloat);
3943 return IsFloatTy
3944 ? SPIRV::OpGroupNonUniformFMul
3945 : SPIRV::OpGroupNonUniformIMul;
3946 });
3947}
3948
3949template <typename PickOpcodeFn>
3950bool SPIRVInstructionSelector::selectWaveExclusiveScan(
3951 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, bool IsUnsigned,
3952 PickOpcodeFn &&PickOpcode) const {
3953 assert(I.getNumOperands() == 3);
3954 assert(I.getOperand(2).isReg());
3955 MachineBasicBlock &BB = *I.getParent();
3956 Register InputRegister = I.getOperand(2).getReg();
3957 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
3958
3959 if (!InputType)
3960 return diagnoseUnsupported(I, "Input Type could not be determined.");
3961
3962 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3963 const unsigned Opcode = PickOpcode(InputRegister, IsUnsigned);
3964 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3965 .addDef(ResVReg)
3966 .addUse(GR.getSPIRVTypeID(ResType))
3967 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
3968 !STI.isShader()))
3969 .addImm(SPIRV::GroupOperation::ExclusiveScan)
3970 .addUse(I.getOperand(2).getReg())
3971 .constrainAllUses(TII, TRI, RBI);
3972 return true;
3973}
3974
3975bool SPIRVInstructionSelector::selectQuadSwap(Register ResVReg,
3976 SPIRVTypeInst ResType,
3977 MachineInstr &I,
3978 unsigned Direction) const {
3979 assert(I.getNumOperands() == 3);
3980 assert(I.getOperand(2).isReg());
3981 MachineBasicBlock &BB = *I.getParent();
3982 Register InputRegister = I.getOperand(2).getReg();
3983
3984 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3985 bool ZeroAsNull = !STI.isShader();
3986 Register DirectionReg =
3987 GR.getOrCreateConstInt(Direction, I, IntTy, TII, ZeroAsNull);
3988 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpGroupNonUniformQuadSwap))
3989 .addDef(ResVReg)
3990 .addUse(GR.getSPIRVTypeID(ResType))
3991 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
3992 ZeroAsNull))
3993 .addUse(InputRegister)
3994 .addUse(DirectionReg)
3995 .constrainAllUses(TII, TRI, RBI);
3996 return true;
3997}
3998
3999bool SPIRVInstructionSelector::selectBitreverseViaI32(Register ResVReg,
4000 SPIRVTypeInst ResType,
4001 MachineInstr &I,
4002 Register Op) const {
4003 SPIRVTypeInst Int32Type = GR.getOrCreateSPIRVIntegerType(32, I, TII);
4004 const unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
4005 Register ShiftConst =
4006 GR.getOrCreateConstInt(32 - BitWidth, I, Int32Type, TII);
4007 unsigned ShiftOp = SPIRV::OpShiftRightLogicalS;
4008
4009 const unsigned N = GR.getScalarOrVectorComponentCount(ResType);
4010 const unsigned ExtendOpcode = GR.isScalarOrVectorSigned(ResType)
4011 ? SPIRV::OpSConvert
4012 : SPIRV::OpUConvert;
4013
4014 if (N > 1 || (ResType->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
4015 STI.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector))) {
4016 Int32Type = GR.getOrCreateSPIRVVectorType(Int32Type, N, I, TII);
4017 ShiftOp = SPIRV::OpShiftRightLogicalV;
4018
4019 // Vector shifts require a composite constant
4020 const Register CompositeReg =
4021 MRI->createVirtualRegister(GR.getRegClass(Int32Type));
4022 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
4023 TII.get(SPIRV::OpConstantComposite))
4024 .addDef(CompositeReg)
4025 .addUse(GR.getSPIRVTypeID(Int32Type));
4026 for (unsigned It = 0; It < N; ++It)
4027 MIB.addUse(ShiftConst);
4028 MIB.constrainAllUses(TII, TRI, RBI);
4029
4030 ShiftConst = CompositeReg;
4031 }
4032
4033 // Converts the input to i32 (or vector of i32)
4034 Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
4035 if (!selectOpWithSrcs(ExtReg, Int32Type, I, {Op}, ExtendOpcode))
4036 return false;
4037
4038 // Perform bitreverse on the i32 value
4039 Register BitrevReg = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
4040 if (!selectBitreverseNative(BitrevReg, Int32Type, I, ExtReg))
4041 return false;
4042
4043 // Shift the bit-reversed value to get the final result.
4044 Register ShiftReg = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
4045 if (!selectOpWithSrcs(ShiftReg, Int32Type, I, {BitrevReg, ShiftConst},
4046 ShiftOp))
4047 return false;
4048
4049 // Finally, convert the result back.
4050 return selectOpWithSrcs(ResVReg, ResType, I, {ShiftReg}, ExtendOpcode);
4051}
4052
4053bool SPIRVInstructionSelector::handle64BitOverflow(
4054 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
4055 unsigned int Opcode,
4056 std::function<bool(Register, SPIRVTypeInst, MachineInstr &, Register,
4057 unsigned)>
4058 CallbackFunction) const {
4059
4060 SPIRVTypeInst BaseType = GR.retrieveScalarOrVectorIntType(ResType);
4061 assert(BaseType->getOpcode() == SPIRV::OpTypeInt &&
4062 "handle64BitOverflow should only be used for integer types");
4063 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType);
4064 assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops");
4065
4066 MachineIRBuilder MIRBuilder(I);
4067 SPIRVTypeInst I64Type = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder);
4068 SPIRVTypeInst I64x2Type =
4069 GR.getOrCreateSPIRVVectorType(I64Type, 2, MIRBuilder, false);
4070 SPIRVTypeInst Vec2ResType =
4071 GR.getOrCreateSPIRVVectorType(BaseType, 2, MIRBuilder, false);
4072
4073 std::vector<Register> PartialRegs;
4074
4075 unsigned CurrentComponent = 0;
4076 for (; CurrentComponent + 1 < ComponentCount; CurrentComponent += 2) {
4077 Register PopCountResult =
4078 MRI->createVirtualRegister(GR.getRegClass(I64x2Type));
4079
4080 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
4081 TII.get(SPIRV::OpVectorShuffle))
4082 .addDef(PopCountResult)
4083 .addUse(GR.getSPIRVTypeID(I64x2Type))
4084 .addUse(SrcReg)
4085 .addUse(SrcReg)
4086 .addImm(CurrentComponent)
4087 .addImm(CurrentComponent + 1);
4088
4089 MIB.constrainAllUses(TII, TRI, RBI);
4090
4091 Register SubVecReg =
4092 MRI->createVirtualRegister(GR.getRegClass(Vec2ResType));
4093
4094 if (!CallbackFunction(SubVecReg, Vec2ResType, I, PopCountResult, Opcode))
4095 return false;
4096
4097 PartialRegs.push_back(SubVecReg);
4098 }
4099 // On odd component counts we need to handle one more component
4100 if (CurrentComponent != ComponentCount) {
4101 bool ZeroAsNull = !STI.isShader();
4102 Register FinalElemReg = MRI->createVirtualRegister(GR.getRegClass(I64Type));
4103 Register ConstIntLastIdx = GR.getOrCreateConstInt(
4104 ComponentCount - 1, I, BaseType, TII, ZeroAsNull);
4105
4106 if (!selectOpWithSrcs(FinalElemReg, I64Type, I, {SrcReg, ConstIntLastIdx},
4107 SPIRV::OpVectorExtractDynamic))
4108 return false;
4109
4110 Register FinalElemResReg =
4112
4113 if (!CallbackFunction(FinalElemResReg, BaseType, I, FinalElemReg, Opcode))
4114 return false;
4115
4116 PartialRegs.push_back(FinalElemResReg);
4117 }
4118 // Join all the resulting registers back into the return type in order
4119 // (ie i32x2, i32x2, i32x1 -> i32x5)
4120 return selectOpWithSrcs(ResVReg, ResType, I, PartialRegs,
4121 SPIRV::OpCompositeConstruct);
4122}
4123
4124bool SPIRVInstructionSelector::selectBitreverse64(Register ResVReg,
4125 SPIRVTypeInst ResType,
4126 MachineInstr &I,
4127 Register SrcReg) const {
4128 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType);
4129 if (ComponentCount > 2)
4130 return handle64BitOverflow(
4131 ResVReg, ResType, I, SrcReg, SPIRV::OpBitReverse,
4132 [this](Register R, SPIRVTypeInst T, MachineInstr &I, Register S,
4133 unsigned O) { return this->selectBitreverse64(R, T, I, S); });
4134
4135 MachineIRBuilder MIRBuilder(I);
4136
4137 SPIRVTypeInst I32Type = GR.getOrCreateSPIRVIntegerType(32, MIRBuilder);
4138 SPIRVTypeInst VecI32Type = GR.getOrCreateSPIRVVectorType(
4139 I32Type, 2 * ComponentCount, MIRBuilder, /*IsSigned=*/false);
4140
4141 // Converts 64 bit into and array of 32 bit, containing 2 elements.
4142 Register Vec32 = MRI->createVirtualRegister(GR.getRegClass(VecI32Type));
4143 if (!selectOpWithSrcs(Vec32, VecI32Type, I, {SrcReg}, SPIRV::OpBitcast))
4144 return false;
4145
4146 // Apply bitreverse on each 32 bit lane
4147 Register Reverse32 = MRI->createVirtualRegister(GR.getRegClass(VecI32Type));
4148 if (!selectBitreverseNative(Reverse32, VecI32Type, I, Vec32))
4149 return false;
4150
4151 // Reversing a 64-bit value = reverse each 32-bit half AND swap them,
4152 // so the old High word becomes lane 0 (low) and old Low becomes lane 1
4153 // (high).
4154 Register SwappedVec = MRI->createVirtualRegister(GR.getRegClass(VecI32Type));
4155 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
4156 TII.get(SPIRV::OpVectorShuffle))
4157 .addDef(SwappedVec)
4158 .addUse(GR.getSPIRVTypeID(VecI32Type))
4159 .addUse(Reverse32)
4160 .addUse(Reverse32);
4161 for (unsigned J = 0; J < ComponentCount; ++J) {
4162 MIB.addImm(2 * J + 1);
4163 MIB.addImm(2 * J);
4164 }
4165 MIB.constrainAllUses(TII, TRI, RBI);
4166
4167 // Groups 32 bit vector back to 64 bit scalar.
4168 return selectOpWithSrcs(ResVReg, ResType, I, {SwappedVec}, SPIRV::OpBitcast);
4169}
4170
4171bool SPIRVInstructionSelector::selectBitreverseNative(Register ResVReg,
4172 SPIRVTypeInst ResType,
4173 MachineInstr &I,
4174 Register Op) const {
4175 MachineBasicBlock &BB = *I.getParent();
4176 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse))
4177 .addDef(ResVReg)
4178 .addUse(GR.getSPIRVTypeID(ResType))
4179 .addUse(Op)
4180 .constrainAllUses(TII, TRI, RBI);
4181 return true;
4182}
4183
4184bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
4185 SPIRVTypeInst ResType,
4186 MachineInstr &I) const {
4187 Register OpReg = I.getOperand(1).getReg();
4188
4189 // TODO: Fix shader behavior in case of VK_KHR_maintenance9 extension is set
4190 if (STI.isShader()) {
4191 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
4192 switch (GR.getScalarOrVectorBitWidth(OpType)) {
4193 case 8:
4194 case 16:
4195 case 24:
4196 return selectBitreverseViaI32(ResVReg, ResType, I, OpReg);
4197 case 32:
4198 return selectBitreverseNative(ResVReg, ResType, I, OpReg);
4199 case 64:
4200 return selectBitreverse64(ResVReg, ResType, I, OpReg);
4201 }
4202 return SPIRVInstructionSelector::diagnoseUnsupported(
4203 I, "G_BITREVERSE only support 16,32,64 bits.");
4204 }
4205
4206 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions))
4207 return selectBitreverseNative(ResVReg, ResType, I, OpReg);
4208
4209 // Expansion bitreverse using bit manipulation operations
4210 // Algo: https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel
4211 const unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
4212 // TODO: add support for any bit width and bitwidth more than 64.
4213 if (BitWidth > 64 || !isPowerOf2_32(BitWidth))
4214 return false;
4215
4216 const unsigned N = GR.getScalarOrVectorComponentCount(ResType);
4217
4218 unsigned AndOp = SPIRV::OpBitwiseAndS;
4219 unsigned OrOp = SPIRV::OpBitwiseOrS;
4220 unsigned ShlOp = SPIRV::OpShiftLeftLogicalS;
4221 unsigned ShrOp = SPIRV::OpShiftRightLogicalS;
4222 if (N > 1 || (ResType->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
4223 STI.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector))) {
4224 AndOp = SPIRV::OpBitwiseAndV;
4225 OrOp = SPIRV::OpBitwiseOrV;
4226 ShlOp = SPIRV::OpShiftLeftLogicalV;
4227 ShrOp = SPIRV::OpShiftRightLogicalV;
4228 }
4229
4230 // Helper, one swap per step: ((input>>shift)&mask)|((input&mask)<<shift),
4231 // RPN: input shift >> mask & input mask & shift << |
4232 auto SwapBits = [&](const Register Input, const uint64_t Mask,
4233 const unsigned Shift) -> Register {
4234 auto CreateConst = [&](const uint64_t Value) -> Register {
4235 if (N == 1 &&
4236 (ResType->getOpcode() != SPIRV::OpTypeVectorIdEXT ||
4237 !STI.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector)))
4238 return GR.getOrCreateConstInt(
4239 Value, I, GR.retrieveScalarOrVectorIntType(ResType), TII);
4240 return GR.getOrCreateConstVector(Value, I, ResType, TII);
4241 };
4242
4243 Register MaskReg = CreateConst(Mask);
4244 Register ShiftReg = CreateConst(Shift);
4245 Register T1 = MRI->createVirtualRegister(GR.getRegClass(ResType));
4246 Register T2 = MRI->createVirtualRegister(GR.getRegClass(ResType));
4247 Register T3 = MRI->createVirtualRegister(GR.getRegClass(ResType));
4248 Register T4 = MRI->createVirtualRegister(GR.getRegClass(ResType));
4250
4251 if (!selectOpWithSrcs(T1, ResType, I, {Input, ShiftReg}, ShrOp) ||
4252 !selectOpWithSrcs(T2, ResType, I, {T1, MaskReg}, AndOp) ||
4253 !selectOpWithSrcs(T3, ResType, I, {Input, MaskReg}, AndOp) ||
4254 !selectOpWithSrcs(T4, ResType, I, {T3, ShiftReg}, ShlOp) ||
4255 !selectOpWithSrcs(Result, ResType, I, {T2, T4}, OrOp))
4256 return Register();
4257
4258 return Result;
4259 };
4260
4261 unsigned Shift = BitWidth;
4262 Register Result = OpReg;
4263 uint64_t Mask = ~0ull;
4264 while ((Shift >>= 1) > 0) {
4265 Mask ^= (Mask << Shift);
4266 Result = SwapBits(Result, Mask, Shift);
4267 if (!Result.isValid())
4268 return false;
4269 }
4270
4271 return BuildCOPY(ResVReg, Result, I);
4272}
4273
4274bool SPIRVInstructionSelector::selectFreeze(Register ResVReg,
4275 SPIRVTypeInst ResType,
4276 MachineInstr &I) const {
4277 assert(I.getOperand(0).isReg() && I.getOperand(1).isReg() &&
4278 "G_FREEZE must define and use a register");
4279 Register OpReg = I.getOperand(1).getReg();
4280
4281 // With SPV_KHR_poison_freeze, lower `freeze` to OpFreezeKHR.
4282 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_poison_freeze)) {
4283 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFreezeKHR))
4284 .addDef(ResVReg)
4285 .addUse(GR.getSPIRVTypeID(ResType))
4286 .addUse(OpReg)
4287 .constrainAllUses(TII, TRI, RBI);
4288 return true;
4289 }
4290
4291 // There is no way to implement `freeze` correctly without support on SPIR-V
4292 // standard side, but we may at least address a simple (static) case when
4293 // undef/poison value presence is obvious. The main benefit of even
4294 // incomplete `freeze` support is preventing of translation from crashing due
4295 // to lack of support on legalization and instruction selection steps.
4296 if (MachineInstr *Def = MRI->getVRegDef(OpReg)) {
4297 if (Def->getOpcode() == TargetOpcode::COPY)
4298 Def = MRI->getVRegDef(Def->getOperand(1).getReg());
4299 Register Reg;
4300 switch (Def->getOpcode()) {
4301 case SPIRV::ASSIGN_TYPE:
4302 if (MachineInstr *AssignToDef =
4303 MRI->getVRegDef(Def->getOperand(1).getReg())) {
4304 if (AssignToDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
4305 Reg = Def->getOperand(2).getReg();
4306 }
4307 break;
4308 case SPIRV::OpUndef:
4309 Reg = Def->getOperand(1).getReg();
4310 break;
4311 }
4312 unsigned DestOpCode;
4313 if (Reg.isValid()) {
4314 DestOpCode = SPIRV::OpConstantNull;
4315 LLVM_DEBUG(dbgs() << "SPV_KHR_poison_freeze is not enabled. freeze of a "
4316 "static undef/poison lowered to OpConstantNull\n");
4317 } else {
4318 DestOpCode = TargetOpcode::COPY;
4319 Reg = OpReg;
4320 LLVM_DEBUG(dbgs() << "SPV_KHR_poison_freeze is not enabled. freeze "
4321 "skipped, lowered as a copy of the operand\n");
4322 }
4323 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DestOpCode))
4324 .addDef(I.getOperand(0).getReg())
4325 .addUse(Reg)
4326 .constrainAllUses(TII, TRI, RBI);
4327 return true;
4328 }
4329 return false;
4330}
4331
4332bool SPIRVInstructionSelector::selectBuildVector(Register ResVReg,
4333 SPIRVTypeInst ResType,
4334 MachineInstr &I) const {
4335 unsigned N = 0;
4336 if (isVectorType(ResType))
4337 N = GR.getScalarOrVectorComponentCount(ResType);
4338 else if (ResType->getOpcode() == SPIRV::OpTypeArray)
4339 N = getArrayComponentCount(MRI, ResType);
4340 else
4341 report_fatal_error("Cannot select G_BUILD_VECTOR with a non-vector result");
4342 if (I.getNumExplicitOperands() - I.getNumExplicitDefs() != N)
4343 report_fatal_error("G_BUILD_VECTOR and the result type are inconsistent");
4344
4345 // check if we may construct a constant vector
4346 bool IsConst = true;
4347 for (unsigned i = I.getNumExplicitDefs();
4348 i < I.getNumExplicitOperands() && IsConst; ++i)
4349 if (!isConstReg(MRI, I.getOperand(i).getReg()))
4350 IsConst = false;
4351
4352 if (!IsConst && (N < 2 && ResType->getOpcode() != SPIRV::OpTypeVectorIdEXT))
4353 return diagnoseUnsupported(
4354 I, "There must be at least two constituent operands in a vector");
4355
4356 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
4357
4358 bool IsNullVector = IsConst && !STI.isShader();
4359 for (unsigned i = I.getNumExplicitDefs();
4360 i < I.getNumExplicitOperands() && IsNullVector; ++i) {
4361 MachineInstr *Def = getDef(I.getOperand(i), MRI);
4362 IsNullVector = Def && isNullOrNullSplat(*Def, *MRI);
4363 }
4364
4365 if (IsNullVector) {
4366 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
4367 .addDef(ResVReg)
4368 .addUse(GR.getSPIRVTypeID(ResType))
4369 .constrainAllUses(TII, TRI, RBI);
4370 return true;
4371 }
4372
4373 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
4374 TII.get(IsConst ? SPIRV::OpConstantComposite
4375 : SPIRV::OpCompositeConstruct))
4376 .addDef(ResVReg)
4377 .addUse(GR.getSPIRVTypeID(ResType));
4378 for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i)
4379 MIB.addUse(I.getOperand(i).getReg());
4380 MIB.constrainAllUses(TII, TRI, RBI);
4381 return true;
4382}
4383
4384bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg,
4385 SPIRVTypeInst ResType,
4386 MachineInstr &I) const {
4387 unsigned N = 0;
4388 if (isVectorType(ResType))
4389 N = GR.getScalarOrVectorComponentCount(ResType);
4390 else if (ResType->getOpcode() == SPIRV::OpTypeArray)
4391 N = getArrayComponentCount(MRI, ResType);
4392 else
4393 report_fatal_error("Cannot select G_SPLAT_VECTOR with a non-vector result");
4394
4395 unsigned OpIdx = I.getNumExplicitDefs();
4396 if (!I.getOperand(OpIdx).isReg())
4397 report_fatal_error("Unexpected argument in G_SPLAT_VECTOR");
4398
4399 // check if we may construct a constant vector
4400 Register OpReg = I.getOperand(OpIdx).getReg();
4401 bool IsConst = isConstReg(MRI, OpReg);
4402
4403 if (!IsConst && (N < 2 && ResType->getOpcode() != SPIRV::OpTypeVectorIdEXT))
4404 return diagnoseUnsupported(
4405 I, "There must be at least two constituent operands in a vector");
4406
4407 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
4408 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
4409 TII.get(IsConst ? SPIRV::OpConstantComposite
4410 : SPIRV::OpCompositeConstruct))
4411 .addDef(ResVReg)
4412 .addUse(GR.getSPIRVTypeID(ResType));
4413 for (unsigned i = 0; i < N; ++i)
4414 MIB.addUse(OpReg);
4415 MIB.constrainAllUses(TII, TRI, RBI);
4416 return true;
4417}
4418
4419bool SPIRVInstructionSelector::selectConcatVectors(Register ResVReg,
4420 SPIRVTypeInst ResType,
4421 MachineInstr &I) const {
4422 // Implement G_CONCAT_VECTORS using OpCompositeConstruct, which allows vector
4423 // constituents that share the result's component type to be
4424 // concatenated in operand order.
4425 if (!isVectorType(ResType))
4427 "Cannot select G_CONCAT_VECTORS with a non-vector result");
4428
4429 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
4430 TII.get(SPIRV::OpCompositeConstruct))
4431 .addDef(ResVReg)
4432 .addUse(GR.getSPIRVTypeID(ResType));
4433 for (unsigned OpIdx = I.getNumExplicitDefs();
4434 OpIdx < I.getNumExplicitOperands(); ++OpIdx)
4435 MIB.addUse(I.getOperand(OpIdx).getReg());
4436 MIB.constrainAllUses(TII, TRI, RBI);
4437 return true;
4438}
4439
4440bool SPIRVInstructionSelector::selectDiscard(Register ResVReg,
4441 SPIRVTypeInst ResType,
4442 MachineInstr &I) const {
4443
4444 unsigned Opcode;
4445 MachineBasicBlock &BB = *I.getParent();
4446
4447 if (STI.canUseExtension(
4448 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation) ||
4449 STI.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6))) {
4450 Opcode = SPIRV::OpDemoteToHelperInvocation;
4451 } else {
4452 Opcode = SPIRV::OpKill;
4453 // OpKill must be the last operation of any basic block.
4454 for (MachineInstr &ToErase : make_early_inc_range(
4455 make_range(std::next(I.getIterator()), BB.instr_end()))) {
4456 GR.invalidateMachineInstr(&ToErase);
4457 ToErase.eraseFromParent();
4458 }
4459 }
4460
4461 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
4462 .constrainAllUses(TII, TRI, RBI);
4463 return true;
4464}
4465
4466bool SPIRVInstructionSelector::selectCmp(Register ResVReg,
4467 SPIRVTypeInst ResType, unsigned CmpOpc,
4468 MachineInstr &I) const {
4469 Register Cmp0 = I.getOperand(2).getReg();
4470 Register Cmp1 = I.getOperand(3).getReg();
4471 assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() ==
4472 GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() &&
4473 "CMP operands should have the same type");
4474 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(CmpOpc))
4475 .addDef(ResVReg)
4476 .addUse(GR.getSPIRVTypeID(ResType))
4477 .addUse(Cmp0)
4478 .addUse(Cmp1)
4479 .setMIFlags(I.getFlags())
4480 .constrainAllUses(TII, TRI, RBI);
4481 return true;
4482}
4483
4484bool SPIRVInstructionSelector::selectICmp(Register ResVReg,
4485 SPIRVTypeInst ResType,
4486 MachineInstr &I) const {
4487 auto Pred = I.getOperand(1).getPredicate();
4488 unsigned CmpOpc;
4489
4490 Register CmpOperand = I.getOperand(2).getReg();
4491 SPIRVTypeInst CmpOperandType = GR.getSPIRVTypeForVReg(CmpOperand);
4492 bool IsPtrCmp = CmpOperandType && CmpOperandType.isPointer();
4493 if (IsPtrCmp) {
4494 CmpOpc = getPtrCmpOpcode(Pred);
4495 // OpPtrEqual/OpPtrNotEqual require both operands to share an identical
4496 // pointer type. If they are not OpBitcast is inserted.
4497 Register Op1 = I.getOperand(3).getReg();
4498 SPIRVTypeInst Ty0 = GR.getSPIRVTypeForVReg(CmpOperand);
4499 if (Ty0 != GR.getSPIRVTypeForVReg(Op1)) {
4500 Register NewOp1 = createVirtualRegister(Ty0, &GR, MRI, MRI->getMF());
4501 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpBitcast))
4502 .addDef(NewOp1)
4503 .addUse(GR.getSPIRVTypeID(Ty0))
4504 .addUse(Op1)
4505 .constrainAllUses(TII, TRI, RBI);
4506 I.getOperand(3).setReg(NewOp1);
4507 }
4508 } else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool))
4509 CmpOpc = getBoolCmpOpcode(Pred);
4510 else
4511 CmpOpc = getICmpOpcode(Pred);
4512 return selectCmp(ResVReg, ResType, CmpOpc, I);
4513}
4514
4516SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I,
4517 SPIRVTypeInst ResType) const {
4518 Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32);
4519 SPIRVTypeInst SpvI32Ty =
4520 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII);
4521 // Find a constant in DT or build a new one.
4522 auto ConstInt = ConstantInt::get(LLVMTy, Val);
4523 Register NewReg = GR.find(ConstInt, GR.CurMF);
4524 if (!NewReg.isValid()) {
4525 NewReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
4526 MachineBasicBlock &BB = *I.getParent();
4527 MachineInstr *MI =
4528 Val == 0
4529 ? BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
4530 .addDef(NewReg)
4531 .addUse(GR.getSPIRVTypeID(SpvI32Ty))
4532 : BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
4533 .addDef(NewReg)
4534 .addUse(GR.getSPIRVTypeID(SpvI32Ty))
4535 .addImm(APInt(32, Val).getZExtValue());
4537 GR.add(ConstInt, MI);
4538 }
4539 return NewReg;
4540}
4541
4542// Like buildI32Constant, but always inserts the constant definition in the
4543// entry block so it dominates all uses regardless of block ordering.
4544Register SPIRVInstructionSelector::buildI32ConstantInEntryBlock(
4545 uint32_t Val, MachineInstr &I, SPIRVTypeInst ResType) const {
4546 Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32);
4547 SPIRVTypeInst SpvI32Ty =
4548 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII);
4549 auto *ConstInt = ConstantInt::get(LLVMTy, Val);
4550 Register NewReg = GR.find(ConstInt, GR.CurMF);
4551 if (!NewReg.isValid()) {
4552 NewReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
4553 auto InsertIt = getOpVariableMBBIt(*I.getMF());
4554 MachineBasicBlock &EntryBB = *InsertIt->getParent();
4555 MachineInstr *MI = nullptr;
4556 Register TypeReg = GR.getSPIRVTypeID(SpvI32Ty);
4557 DebugLoc DbgLoc = I.getDebugLoc();
4558 if (Val == 0) {
4559 MI = BuildMI(EntryBB, InsertIt, DbgLoc, TII.get(SPIRV::OpConstantNull))
4560 .addDef(NewReg)
4561 .addUse(TypeReg);
4562 } else {
4563 uint64_t ImmVal = APInt(32, Val).getZExtValue();
4564 MI = BuildMI(EntryBB, InsertIt, DbgLoc, TII.get(SPIRV::OpConstantI))
4565 .addDef(NewReg)
4566 .addUse(TypeReg)
4567 .addImm(ImmVal);
4568 }
4570 GR.add(ConstInt, MI);
4571 }
4572 return NewReg;
4573}
4574
4575bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
4576 SPIRVTypeInst ResType,
4577 MachineInstr &I) const {
4578 unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate());
4579 return selectCmp(ResVReg, ResType, CmpOp, I);
4580}
4581
4582bool SPIRVInstructionSelector::selectExp10(Register ResVReg,
4583 SPIRVTypeInst ResType,
4584 MachineInstr &I) const {
4585 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
4586 return selectExtInst(ResVReg, ResType, I, CL::exp10);
4587 }
4588
4589 if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
4590 /// There is no exp10 in GLSL. Use exp10(x) = exp2(x * log2(10)) instead
4591 /// log2(10) ~= 3.3219280948874l
4592
4593 if (!isVectorType(ResType) && !ResType.isAnyTypeFloat())
4594 return false;
4595
4596 MachineIRBuilder MIRBuilder(I);
4597
4598 SPIRVTypeInst SpirvScalarType = GR.getScalarOrVectorComponentType(ResType);
4599
4600 // Match the literal precision to the scalar type so the OpConstant
4601 // literal does not contain non-zero high-order bits that would fail
4602 // SPIR-V validation when the type is narrower than 32 bits (e.g. half).
4603 APFloat ConstVal(3.3219280948873623);
4604 bool LosesInfo;
4605 ConstVal.convert(
4606 getZeroFP(GR.getTypeForSPIRVType(SpirvScalarType)).getSemantics(),
4607 APFloat::rmNearestTiesToEven, &LosesInfo);
4608 Register ConstReg =
4609 GR.buildConstantFP(ConstVal, MIRBuilder, SpirvScalarType);
4610 Register ArgReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
4611 auto Opcode =
4612 isVectorType(ResType) ? SPIRV::OpVectorTimesScalar : SPIRV::OpFMulS;
4613
4614 if (!selectOpWithSrcs(ArgReg, ResType, I,
4615 {I.getOperand(1).getReg(), ConstReg}, Opcode))
4616 return false;
4617 if (!selectExtInst(ResVReg, ResType, I,
4618 {{SPIRV::InstructionSet::GLSL_std_450, GL::Exp2}}, false,
4619 false, {ArgReg}))
4620 return false;
4621
4622 return true;
4623 }
4624
4625 return false;
4626}
4627
4628Register SPIRVInstructionSelector::buildZerosVal(SPIRVTypeInst ResType,
4629 MachineInstr &I) const {
4630 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
4631 bool ZeroAsNull = !STI.isShader();
4632 if (isVectorType(ResType))
4633 return GR.getOrCreateConstVector(0UL, I, ResType, TII, ZeroAsNull);
4634 return GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
4635}
4636
4637bool SPIRVInstructionSelector::isScalarOrVectorIntConstantZero(
4638 Register Reg) const {
4639 SPIRVTypeInst Type = GR.getSPIRVTypeForVReg(Reg);
4640 if (!Type)
4641 return false;
4642 SPIRVTypeInst CompType = GR.getScalarOrVectorComponentType(Type);
4643 if (!CompType || CompType->getOpcode() != SPIRV::OpTypeInt)
4644 return false;
4645
4646 auto IsZero = [this](Register Reg) {
4647 MachineInstr *Def = getDefInstrMaybeConstant(Reg, MRI);
4648 if (!Def)
4649 return false;
4650
4651 if (Def->getOpcode() == SPIRV::OpConstantNull)
4652 return true;
4653
4654 if (Def->getOpcode() == TargetOpcode::G_CONSTANT ||
4655 Def->getOpcode() == SPIRV::OpConstantI)
4656 return getIConstVal(Reg, MRI) == 0;
4657
4658 return false;
4659 };
4660
4661 if (IsZero(Reg))
4662 return true;
4663
4664 MachineInstr *Def = MRI->getVRegDef(Reg);
4665 if (!Def)
4666 return false;
4667
4668 if (Def->getOpcode() == TargetOpcode::G_BUILD_VECTOR ||
4669 (Def->getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS &&
4670 cast<GIntrinsic>(Def)->getIntrinsicID() ==
4671 Intrinsic::spv_const_composite)) {
4672 unsigned StartOp = Def->getOpcode() == TargetOpcode::G_BUILD_VECTOR ? 1 : 2;
4673 for (unsigned i = StartOp; i < Def->getNumOperands(); ++i) {
4674 if (!IsZero(Def->getOperand(i).getReg()))
4675 return false;
4676 }
4677 return true;
4678 }
4679
4680 return false;
4681}
4682
4683Register SPIRVInstructionSelector::buildZerosValF(SPIRVTypeInst ResType,
4684 MachineInstr &I) const {
4685 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
4686 bool ZeroAsNull = !STI.isShader();
4687 APFloat VZero = getZeroFP(GR.getTypeForSPIRVType(ResType));
4688 if (isVectorType(ResType))
4689 return GR.getOrCreateConstVector(VZero, I, ResType, TII, ZeroAsNull);
4690 return GR.getOrCreateConstFP(VZero, I, ResType, TII, ZeroAsNull);
4691}
4692
4693Register SPIRVInstructionSelector::buildOnesValF(SPIRVTypeInst ResType,
4694 MachineInstr &I) const {
4695 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
4696 bool ZeroAsNull = !STI.isShader();
4697 APFloat VOne = getOneFP(GR.getTypeForSPIRVType(ResType));
4698 if (isVectorType(ResType))
4699 return GR.getOrCreateConstVector(VOne, I, ResType, TII, ZeroAsNull);
4700 return GR.getOrCreateConstFP(VOne, I, ResType, TII, ZeroAsNull);
4701}
4702
4703Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
4704 SPIRVTypeInst ResType,
4705 MachineInstr &I) const {
4706 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
4707 APInt One =
4708 AllOnes ? APInt::getAllOnes(BitWidth) : APInt::getOneBitSet(BitWidth, 0);
4709 if (isVectorType(ResType))
4710 return GR.getOrCreateConstVector(One, I, ResType, TII);
4711 return GR.getOrCreateConstInt(One, I, ResType, TII);
4712}
4713
4714bool SPIRVInstructionSelector::selectSelect(Register ResVReg,
4715 SPIRVTypeInst ResType,
4716 MachineInstr &I) const {
4717 Register SelectFirstArg = I.getOperand(2).getReg();
4718 Register SelectSecondArg = I.getOperand(3).getReg();
4719 assert(ResType == GR.getSPIRVTypeForVReg(SelectFirstArg) &&
4720 ResType == GR.getSPIRVTypeForVReg(SelectSecondArg));
4721
4722 bool IsFloatTy =
4723 GR.isScalarOrVectorOfType(SelectFirstArg, SPIRV::OpTypeFloat);
4724 bool IsPtrTy =
4725 GR.isScalarOrVectorOfType(SelectFirstArg, SPIRV::OpTypePointer);
4726
4727 bool IsScalarBool =
4728 GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool);
4729 unsigned Opcode;
4730 if (isVectorType(GR.getSPIRVTypeForVReg(SelectFirstArg))) {
4731 if (IsFloatTy) {
4732 Opcode = IsScalarBool ? SPIRV::OpSelectVFSCond : SPIRV::OpSelectVFVCond;
4733 } else if (IsPtrTy) {
4734 Opcode = IsScalarBool ? SPIRV::OpSelectVPSCond : SPIRV::OpSelectVPVCond;
4735 } else {
4736 Opcode = IsScalarBool ? SPIRV::OpSelectVISCond : SPIRV::OpSelectVIVCond;
4737 }
4738 } else {
4739 assert(IsScalarBool && "OpSelect with a scalar result requires a scalar "
4740 "boolean condition");
4741 if (IsFloatTy) {
4742 Opcode = SPIRV::OpSelectSFSCond;
4743 } else if (IsPtrTy) {
4744 Opcode = SPIRV::OpSelectSPSCond;
4745 } else {
4746 Opcode = SPIRV::OpSelectSISCond;
4747 }
4748 }
4749 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
4750 .addDef(ResVReg)
4751 .addUse(GR.getSPIRVTypeID(ResType))
4752 .addUse(I.getOperand(1).getReg())
4753 .addUse(SelectFirstArg)
4754 .addUse(SelectSecondArg)
4755 .constrainAllUses(TII, TRI, RBI);
4756 return true;
4757}
4758
4759// This function is used to extend a bool or a vector of bools into an integer
4760// or vector of integers.
4761bool SPIRVInstructionSelector::selectBoolToInt(Register ResVReg,
4762 SPIRVTypeInst ResType,
4763 Register BooleanVReg,
4764 MachineInstr &InsertAt,
4765 bool IsSigned) const {
4766 // To extend a bool, we need to use OpSelect between constants.
4767 Register ZeroReg = buildZerosVal(ResType, InsertAt);
4768 Register OneReg = buildOnesVal(IsSigned, ResType, InsertAt);
4769 bool IsScalarBool = GR.isScalarOfType(BooleanVReg, SPIRV::OpTypeBool);
4770 unsigned Opcode =
4771 IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond;
4772 BuildMI(*InsertAt.getParent(), InsertAt, InsertAt.getDebugLoc(),
4773 TII.get(Opcode))
4774 .addDef(ResVReg)
4775 .addUse(GR.getSPIRVTypeID(ResType))
4776 .addUse(BooleanVReg)
4777 .addUse(OneReg)
4778 .addUse(ZeroReg)
4779 .constrainAllUses(TII, TRI, RBI);
4780 return true;
4781}
4782
4783bool SPIRVInstructionSelector::selectIToF(Register ResVReg,
4784 SPIRVTypeInst ResType,
4785 MachineInstr &I, bool IsSigned,
4786 unsigned Opcode) const {
4787 Register SrcReg = I.getOperand(1).getReg();
4788 // We can convert bool value directly to float type without OpConvert*ToF,
4789 // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
4790 if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) {
4791 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
4792 SPIRVTypeInst TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII);
4793 if (isVectorType(ResType)) {
4794 const unsigned NumElts = GR.getScalarOrVectorComponentCount(ResType);
4795 TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII);
4796 }
4797 SrcReg = createVirtualRegister(TmpType, &GR, MRI, MRI->getMF());
4798 selectBoolToInt(SrcReg, TmpType, I.getOperand(1).getReg(), I, IsSigned);
4799 }
4800 return selectOpWithSrcs(ResVReg, ResType, I, {SrcReg}, Opcode);
4801}
4802
4803bool SPIRVInstructionSelector::selectExt(Register ResVReg,
4804 SPIRVTypeInst ResType, MachineInstr &I,
4805 bool IsSigned) const {
4806 Register SrcReg = I.getOperand(1).getReg();
4807 if (GR.isScalarOrVectorOfType(SrcReg, SPIRV::OpTypeBool))
4808 return selectBoolToInt(ResVReg, ResType, I.getOperand(1).getReg(), I,
4809 IsSigned);
4810
4811 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(SrcReg);
4812 if (ResType == SrcType)
4813 return BuildCOPY(ResVReg, SrcReg, I);
4814
4815 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
4816 return selectUnOp(ResVReg, ResType, I, Opcode);
4817}
4818
4819bool SPIRVInstructionSelector::selectSUCmp(Register ResVReg,
4820 SPIRVTypeInst ResType,
4821 MachineInstr &I,
4822 bool IsSigned) const {
4823 MachineIRBuilder MIRBuilder(I);
4824 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
4825 MachineBasicBlock &BB = *I.getParent();
4826 // Ensure we have bool.
4827 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
4828 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
4829 if (N > 1 || (ResType->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
4830 STI.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector)))
4831 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, N, I, TII);
4832 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
4833 // Build less-than-equal and less-than.
4834 Register IsLessEqReg =
4835 createVirtualRegister(BoolType, &GR, MRI, MIRBuilder.getMF());
4836 BuildMI(BB, I, I.getDebugLoc(),
4837 TII.get(IsSigned ? SPIRV::OpSLessThanEqual : SPIRV::OpULessThanEqual))
4838 .addDef(IsLessEqReg)
4839 .addUse(BoolTypeReg)
4840 .addUse(I.getOperand(1).getReg())
4841 .addUse(I.getOperand(2).getReg())
4842 .constrainAllUses(TII, TRI, RBI);
4843 Register IsLessReg =
4844 createVirtualRegister(BoolType, &GR, MRI, MIRBuilder.getMF());
4845 BuildMI(BB, I, I.getDebugLoc(),
4846 TII.get(IsSigned ? SPIRV::OpSLessThan : SPIRV::OpULessThan))
4847 .addDef(IsLessReg)
4848 .addUse(BoolTypeReg)
4849 .addUse(I.getOperand(1).getReg())
4850 .addUse(I.getOperand(2).getReg())
4851 .constrainAllUses(TII, TRI, RBI);
4852 // Build selects.
4853 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
4854 Register NegOneOrZeroReg =
4855 MRI->createVirtualRegister(GR.getRegClass(ResType));
4856 MRI->setType(NegOneOrZeroReg, LLT::scalar(64));
4857 GR.assignSPIRVTypeToVReg(ResType, NegOneOrZeroReg, MIRBuilder.getMF());
4858 unsigned SelectOpcode =
4859 (N > 1 || (ResType->getOpcode() == SPIRV::OpTypeVectorIdEXT &&
4860 STI.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector)))
4861 ? SPIRV::OpSelectVIVCond
4862 : SPIRV::OpSelectSISCond;
4863 BuildMI(BB, I, I.getDebugLoc(), TII.get(SelectOpcode))
4864 .addDef(NegOneOrZeroReg)
4865 .addUse(ResTypeReg)
4866 .addUse(IsLessReg)
4867 .addUse(buildOnesVal(true, ResType, I)) // -1
4868 .addUse(buildZerosVal(ResType, I))
4869 .constrainAllUses(TII, TRI, RBI);
4870 BuildMI(BB, I, I.getDebugLoc(), TII.get(SelectOpcode))
4871 .addDef(ResVReg)
4872 .addUse(ResTypeReg)
4873 .addUse(IsLessEqReg)
4874 .addUse(NegOneOrZeroReg) // -1 or 0
4875 .addUse(buildOnesVal(false, ResType, I))
4876 .constrainAllUses(TII, TRI, RBI);
4877 return true;
4878}
4879
4880bool SPIRVInstructionSelector::selectIntToBool(Register IntReg,
4881 Register ResVReg,
4882 MachineInstr &I,
4883 SPIRVTypeInst IntTy,
4884 SPIRVTypeInst BoolTy) const {
4885 // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
4886 Register BitIntReg = createVirtualRegister(IntTy, &GR, MRI, MRI->getMF());
4887 unsigned Opcode =
4888 isVectorType(IntTy) ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
4889 Register Zero = buildZerosVal(IntTy, I);
4890 Register One = buildOnesVal(false, IntTy, I);
4891 MachineBasicBlock &BB = *I.getParent();
4892 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
4893 .addDef(BitIntReg)
4894 .addUse(GR.getSPIRVTypeID(IntTy))
4895 .addUse(IntReg)
4896 .addUse(One)
4897 .constrainAllUses(TII, TRI, RBI);
4898 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
4899 .addDef(ResVReg)
4900 .addUse(GR.getSPIRVTypeID(BoolTy))
4901 .addUse(BitIntReg)
4902 .addUse(Zero)
4903 .constrainAllUses(TII, TRI, RBI);
4904 return true;
4905}
4906
4907bool SPIRVInstructionSelector::selectTrunc(Register ResVReg,
4908 SPIRVTypeInst ResType,
4909 MachineInstr &I) const {
4910 Register IntReg = I.getOperand(1).getReg();
4911 const SPIRVTypeInst ArgType = GR.getSPIRVTypeForVReg(IntReg);
4912 if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool))
4913 return selectIntToBool(IntReg, ResVReg, I, ArgType, ResType);
4914 if (ArgType == ResType)
4915 return BuildCOPY(ResVReg, IntReg, I);
4916 bool IsSigned = GR.isScalarOrVectorSigned(ResType);
4917 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
4918 return selectUnOp(ResVReg, ResType, I, Opcode);
4919}
4920
4921bool SPIRVInstructionSelector::selectConst(Register ResVReg,
4922 SPIRVTypeInst ResType,
4923 MachineInstr &I) const {
4924 unsigned Opcode = I.getOpcode();
4925 unsigned TpOpcode = ResType->getOpcode();
4926 Register Reg;
4927 if (ResType.isPointer() || TpOpcode == SPIRV::OpTypeEvent) {
4928 assert(Opcode == TargetOpcode::G_CONSTANT &&
4929 I.getOperand(1).getCImm()->isZero());
4930 MachineBasicBlock &DepMBB = I.getMF()->front();
4931 MachineIRBuilder MIRBuilder(DepMBB, DepMBB.getFirstNonPHI());
4932 Reg = GR.getOrCreateConstNullPtr(MIRBuilder, ResType);
4933 } else if (TpOpcode == SPIRV::OpTypeVectorIdEXT) {
4934 // We ended up here coming from a splat on a <1 x T> type, which
4935 // IRTranslator translated into a scalar, so we have to restore the
4936 // vectorness.
4937 assert(GR.getScalarOrVectorComponentCount(ResType) == 1 &&
4938 "Expected <1 x T> Vector!");
4939 if (Opcode == TargetOpcode::G_FCONSTANT)
4940 Reg = GR.getOrCreateConstVector(I.getOperand(1).getFPImm()->getValue(), I,
4941 ResType, TII);
4942 else // We handle vector of pointer here as well.
4943 Reg = GR.getOrCreateConstVector(I.getOperand(1).getCImm()->getValue(), I,
4944 ResType, TII);
4945 } else if (Opcode == TargetOpcode::G_FCONSTANT) {
4946 Reg = GR.getOrCreateConstFP(I.getOperand(1).getFPImm()->getValue(), I,
4947 ResType, TII, !STI.isShader());
4948
4949 } else {
4950 Reg = GR.getOrCreateConstInt(I.getOperand(1).getCImm()->getValue(), I,
4951 ResType, TII, !STI.isShader());
4952 }
4953 return Reg == ResVReg ? true : BuildCOPY(ResVReg, Reg, I);
4954}
4955
4956bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg,
4957 SPIRVTypeInst ResType,
4958 MachineInstr &I) const {
4959 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
4960 .addDef(ResVReg)
4961 .addUse(GR.getSPIRVTypeID(ResType))
4962 .constrainAllUses(TII, TRI, RBI);
4963 return true;
4964}
4965
4966bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg,
4967 SPIRVTypeInst ResType,
4968 MachineInstr &I) const {
4969 MachineBasicBlock &BB = *I.getParent();
4970 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeInsert))
4971 .addDef(ResVReg)
4972 .addUse(GR.getSPIRVTypeID(ResType))
4973 // object to insert
4974 .addUse(I.getOperand(3).getReg())
4975 // composite to insert into
4976 .addUse(I.getOperand(2).getReg());
4977 for (unsigned i = 4; i < I.getNumOperands(); i++)
4978 MIB.addImm(foldImm(I.getOperand(i), MRI));
4979 MIB.constrainAllUses(TII, TRI, RBI);
4980 return true;
4981}
4982
4983bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg,
4984 SPIRVTypeInst ResType,
4985 MachineInstr &I) const {
4986 Type *MaybeResTy = nullptr;
4987 StringRef ResName;
4988 if (GR.findValueAttrs(&I, MaybeResTy, ResName) &&
4989 MaybeResTy != GR.getTypeForSPIRVType(ResType)) {
4990 assert((!MaybeResTy || MaybeResTy->isAggregateType()) &&
4991 "Expected aggregate type for extractv instruction");
4992 ResType = GR.getOrCreateSPIRVType(MaybeResTy, I,
4993 SPIRV::AccessQualifier::ReadWrite, false);
4994 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *I.getMF());
4995 }
4996 MachineBasicBlock &BB = *I.getParent();
4997 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
4998 .addDef(ResVReg)
4999 .addUse(GR.getSPIRVTypeID(ResType))
5000 .addUse(I.getOperand(2).getReg());
5001 for (unsigned i = 3; i < I.getNumOperands(); i++)
5002 MIB.addImm(foldImm(I.getOperand(i), MRI));
5003 MIB.constrainAllUses(TII, TRI, RBI);
5004 return true;
5005}
5006
5007bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg,
5008 SPIRVTypeInst ResType,
5009 MachineInstr &I) const {
5010 if (getImm(I.getOperand(4), MRI))
5011 return selectInsertVal(ResVReg, ResType, I);
5012 MachineBasicBlock &BB = *I.getParent();
5013 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorInsertDynamic))
5014 .addDef(ResVReg)
5015 .addUse(GR.getSPIRVTypeID(ResType))
5016 .addUse(I.getOperand(2).getReg())
5017 .addUse(I.getOperand(3).getReg())
5018 .addUse(I.getOperand(4).getReg())
5019 .constrainAllUses(TII, TRI, RBI);
5020 return true;
5021}
5022
5023bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg,
5024 SPIRVTypeInst ResType,
5025 MachineInstr &I) const {
5026 if (getImm(I.getOperand(3), MRI))
5027 return selectExtractVal(ResVReg, ResType, I);
5028 MachineBasicBlock &BB = *I.getParent();
5029 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorExtractDynamic))
5030 .addDef(ResVReg)
5031 .addUse(GR.getSPIRVTypeID(ResType))
5032 .addUse(I.getOperand(2).getReg())
5033 .addUse(I.getOperand(3).getReg())
5034 .constrainAllUses(TII, TRI, RBI);
5035 return true;
5036}
5037
5038bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
5039 SPIRVTypeInst ResType,
5040 MachineInstr &I) const {
5041 const bool IsGEPInBounds = I.getOperand(2).getImm();
5042 // Pointers to opaque types stay typed even with the extension on, so emit the
5043 // untyped variant only when the result is actually an untyped pointer.
5044 const bool UseUntypedPointers =
5045 ResType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
5046
5047 // Determine the opcode based on pointer type and bounds checking.
5048 // When using untyped pointers, use OpUntyped*AccessChainKHR variants.
5049 unsigned Opcode;
5050 if (UseUntypedPointers) {
5051 if (STI.isLogicalSPIRV()) {
5052 Opcode = IsGEPInBounds ? SPIRV::OpUntypedInBoundsAccessChainKHR
5053 : SPIRV::OpUntypedAccessChainKHR;
5054 } else {
5055 Opcode = IsGEPInBounds ? SPIRV::OpUntypedInBoundsPtrAccessChainKHR
5056 : SPIRV::OpUntypedPtrAccessChainKHR;
5057 }
5058 } else {
5059 // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator
5060 // only relies on PtrAccessChain, so we'll try not to deviate. For Vulkan
5061 // however, we have to use Op[InBounds]AccessChain.
5062 // FIXME: fix llvm-spirv.
5063 if (STI.isLogicalSPIRV()) {
5064 Opcode =
5065 IsGEPInBounds ? SPIRV::OpInBoundsAccessChain : SPIRV::OpAccessChain;
5066 } else {
5067 Opcode = IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
5068 : SPIRV::OpPtrAccessChain;
5069 }
5070 }
5071
5072 Register BaseReg = I.getOperand(3).getReg();
5073 auto Res = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
5074 .addDef(ResVReg)
5075 .addUse(GR.getSPIRVTypeID(ResType));
5076
5077 // For untyped access chains, we need to add the base type operand.
5078 if (UseUntypedPointers) {
5079 // Get the element type from the base pointer register.
5080 // For untyped pointers, this was stored when processing
5081 // spv_assign_ptr_type.
5082 SPIRVTypeInst BaseType = GR.getUntypedPtrElementType(BaseReg);
5083 if (!BaseType) {
5084 // Otherwise try the pointee type for mixed typed-pointer usage.
5085 SPIRVTypeInst BasePtrType = GR.getSPIRVTypeForVReg(BaseReg);
5086 BaseType = BasePtrType ? GR.getPointeeType(BasePtrType) : nullptr;
5087 }
5088 if (!BaseType) {
5089 // The base may be a not-yet-selected global. Read its value type from
5090 // the defining G_GLOBAL_VALUE, following copies.
5091 Register DefReg = BaseReg;
5092 MachineInstr *Def = MRI->getVRegDef(DefReg);
5093 while (Def && Def->getOpcode() == TargetOpcode::COPY &&
5094 Def->getOperand(1).isReg())
5095 Def = MRI->getVRegDef(Def->getOperand(1).getReg());
5096 if (Def && Def->getOpcode() == TargetOpcode::G_GLOBAL_VALUE)
5097 if (const auto *GVar =
5098 dyn_cast<GlobalVariable>(Def->getOperand(1).getGlobal()))
5099 BaseType = GR.getOrCreateSPIRVType(GVar->getValueType(), I,
5100 SPIRV::AccessQualifier::ReadWrite,
5101 /*EmitIR=*/false);
5102 }
5103 if (!BaseType)
5104 return diagnoseUnsupported(
5105 I, "could not deduce the base type of an untyped access chain");
5106 Res.addUse(GR.getSPIRVTypeID(BaseType));
5107 }
5108
5109 // Object to get a pointer to.
5110 Res.addUse(BaseReg);
5111
5112 const bool IsAccessChainOpcode =
5113 (Opcode == SPIRV::OpAccessChain ||
5114 Opcode == SPIRV::OpInBoundsAccessChain ||
5115 Opcode == SPIRV::OpUntypedAccessChainKHR ||
5116 Opcode == SPIRV::OpUntypedInBoundsAccessChainKHR);
5117
5118 assert((!IsAccessChainOpcode || (getImm(I.getOperand(4), MRI) &&
5119 foldImm(I.getOperand(4), MRI) == 0)) &&
5120 "Cannot translate GEP to OpAccessChain.");
5121
5122 // Adding indices.
5123 const unsigned StartingIndex = IsAccessChainOpcode ? 5 : 4;
5124 for (unsigned i = StartingIndex; i < I.getNumExplicitOperands(); ++i)
5125 Res.addUse(I.getOperand(i).getReg());
5126 Res.constrainAllUses(TII, TRI, RBI);
5127
5128 // IRTranslator doesn't like <1 x T> vectors, and treats them as scalars. This
5129 // creates an information loss issue, and also broken code where a
5130 // OpCompositeExtract is applied to the scalar return of an OpPtrAccessChain,
5131 // when it was meant to be applied to the OpCompositeInsert created <1 x T>.
5132 // TODO: should we also re-create the index <1 x T>?
5133 if (MRI->hasOneUse(ResVReg)) {
5134 MachineInstr &Extract = *MRI->use_instr_begin(ResVReg);
5135 if (Extract.getOpcode() == SPIRV::OpCompositeExtract) {
5136 SPIRVTypeInst V = GR.getOrCreateSPIRVVectorType(ResType, 1, Extract, TII);
5137 // We cannot use GlobalRegistry::getOrCreateUndef directly here because it
5138 // tries to use UndefVal::get, which does not work for TypedPointerType,
5139 // which we can get here if we're dealing with <1 x T*>.
5140 Register Tmp = createVirtualRegister(V, &GR, MRI, *I.getMF());
5141 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
5142 .addDef(Tmp)
5143 .addUse(GR.getSPIRVTypeID(V))
5144 .constrainAllUses(TII, TRI, RBI);
5145 Register InsertReg = createVirtualRegister(V, &GR, MRI, *I.getMF());
5146 BuildMI(*I.getParent(), Extract, Extract.getDebugLoc(),
5147 TII.get(SPIRV::OpCompositeInsert))
5148 .addDef(InsertReg)
5149 .addUse(GR.getSPIRVTypeID(V))
5150 .addUse(ResVReg)
5151 .addUse(Tmp)
5152 .addImm(0)
5153 .constrainAllUses(TII, TRI, RBI);
5154 Extract.substituteRegister(ResVReg, InsertReg, 0, TRI);
5155 }
5156 }
5157 return true;
5158}
5159
5160// Maybe wrap a value into OpSpecConstantOp
5161bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
5162 MachineInstr &I, SmallVector<Register> &CompositeArgs) const {
5163 unsigned Lim = I.getNumExplicitOperands();
5164 for (unsigned i = I.getNumExplicitDefs() + 1; i < Lim; ++i) {
5165 Register OpReg = I.getOperand(i).getReg();
5166 MachineInstr *OpDefine = MRI->getVRegDef(OpReg);
5167 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
5168 if (!OpDefine || !OpType || isConstReg(MRI, OpDefine) ||
5169 OpDefine->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
5170 OpDefine->getOpcode() == TargetOpcode::G_INTTOPTR ||
5171 GR.isAggregateType(OpType)) {
5172 // The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed
5173 // by selectAddrSpaceCast(), and G_INTTOPTR is processed by selectUnOp()
5174 CompositeArgs.push_back(OpReg);
5175 continue;
5176 }
5177 MachineFunction *MF = I.getMF();
5178 Register WrapReg = GR.find(OpDefine, MF);
5179 if (WrapReg.isValid()) {
5180 CompositeArgs.push_back(WrapReg);
5181 continue;
5182 }
5183 SPIRVTypeInst WrapType = OpType;
5184 if (OpType->getOpcode() == SPIRV::OpTypePointer &&
5185 GR.getPointerStorageClass(OpType) ==
5186 SPIRV::StorageClass::CodeSectionINTEL) {
5187 WrapType = GR.changePointerStorageClass(OpType,
5188 SPIRV::StorageClass::Function, I);
5189 }
5190 WrapReg = MRI->createVirtualRegister(GR.getRegClass(WrapType));
5191 CompositeArgs.push_back(WrapReg);
5192 // Decorate the wrapper register and generate a new instruction
5193 MRI->setType(WrapReg, LLT::pointer(0, 64));
5194 GR.assignSPIRVTypeToVReg(WrapType, WrapReg, *MF);
5195 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
5196 TII.get(SPIRV::OpSpecConstantOp))
5197 .addDef(WrapReg)
5198 .addUse(GR.getSPIRVTypeID(WrapType))
5199 .addImm(static_cast<uint32_t>(SPIRV::Opcode::Bitcast))
5200 .addUse(OpReg);
5201 GR.add(OpDefine, MIB);
5202 MIB.constrainAllUses(TII, TRI, RBI);
5203 }
5204 return true;
5205}
5206
5207bool SPIRVInstructionSelector::selectDerivativeInst(
5208 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
5209 const unsigned DPdOpCode) const {
5210 // TODO: This should check specifically for Fragment Execution Model, but STI
5211 // doesn't provide that information yet. See #167562
5212 if (!errorIfInstrOutsideShader(I))
5213 return false;
5214
5215 // If the arg/result types are half then we need to wrap the instr in
5216 // conversions to float
5217 // This case occurs because a half arg/result is legal in HLSL but not spirv.
5218 Register SrcReg = I.getOperand(2).getReg();
5219 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(SrcReg);
5220 unsigned BitWidth = std::min(GR.getScalarOrVectorBitWidth(SrcType),
5221 GR.getScalarOrVectorBitWidth(ResType));
5222 if (BitWidth == 32)
5223 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DPdOpCode))
5224 .addDef(ResVReg)
5225 .addUse(GR.getSPIRVTypeID(ResType))
5226 .addUse(I.getOperand(2).getReg());
5227
5228 MachineIRBuilder MIRBuilder(I);
5229 unsigned componentCount = GR.getScalarOrVectorComponentCount(SrcType);
5230 SPIRVTypeInst F32ConvertTy = GR.getOrCreateSPIRVFloatType(32, I, TII);
5231 if (componentCount != 1)
5232 F32ConvertTy = GR.getOrCreateSPIRVVectorType(F32ConvertTy, componentCount,
5233 MIRBuilder, false);
5234
5235 const TargetRegisterClass *RegClass = GR.getRegClass(SrcType);
5236 Register ConvertToVReg = MRI->createVirtualRegister(RegClass);
5237 Register DpdOpVReg = MRI->createVirtualRegister(RegClass);
5238
5239 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFConvert))
5240 .addDef(ConvertToVReg)
5241 .addUse(GR.getSPIRVTypeID(F32ConvertTy))
5242 .addUse(SrcReg)
5243 .constrainAllUses(TII, TRI, RBI);
5244 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DPdOpCode))
5245 .addDef(DpdOpVReg)
5246 .addUse(GR.getSPIRVTypeID(F32ConvertTy))
5247 .addUse(ConvertToVReg)
5248 .constrainAllUses(TII, TRI, RBI);
5249 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFConvert))
5250 .addDef(ResVReg)
5251 .addUse(GR.getSPIRVTypeID(ResType))
5252 .addUse(DpdOpVReg)
5253 .constrainAllUses(TII, TRI, RBI);
5254 return true;
5255}
5256
5257bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
5258 SPIRVTypeInst ResType,
5259 MachineInstr &I) const {
5260 MachineBasicBlock &BB = *I.getParent();
5261 Intrinsic::ID IID = cast<GIntrinsic>(I).getIntrinsicID();
5262 switch (IID) {
5263 case Intrinsic::spv_load:
5264 return selectLoad(ResVReg, ResType, I);
5265 case Intrinsic::spv_atomic_load:
5266 return selectAtomicLoad(ResVReg, ResType, I);
5267 case Intrinsic::spv_store:
5268 return selectStore(I);
5269 case Intrinsic::spv_atomic_store:
5270 return selectAtomicStore(I);
5271 case Intrinsic::spv_extractv:
5272 return selectExtractVal(ResVReg, ResType, I);
5273 case Intrinsic::spv_insertv:
5274 return selectInsertVal(ResVReg, ResType, I);
5275 case Intrinsic::spv_extractelt:
5276 return selectExtractElt(ResVReg, ResType, I);
5277 case Intrinsic::spv_insertelt:
5278 return selectInsertElt(ResVReg, ResType, I);
5279 case Intrinsic::spv_gep:
5280 return selectGEP(ResVReg, ResType, I);
5281 case Intrinsic::spv_bitcast: {
5282 Register OpReg = I.getOperand(2).getReg();
5283 SPIRVTypeInst OpType =
5284 OpReg.isValid() ? GR.getSPIRVTypeForVReg(OpReg) : nullptr;
5285 if (!GR.isBitcastCompatible(ResType, OpType))
5286 report_fatal_error("incompatible result and operand types in a bitcast");
5287 return selectOpWithSrcs(ResVReg, ResType, I, {OpReg}, SPIRV::OpBitcast);
5288 }
5289 case Intrinsic::spv_unref_global:
5290 case Intrinsic::spv_init_global: {
5291 MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());
5292 MachineInstr *Init = I.getNumExplicitOperands() > 2
5293 ? MRI->getVRegDef(I.getOperand(2).getReg())
5294 : nullptr;
5295 assert(MI);
5296 Register GVarVReg = MI->getOperand(0).getReg();
5297 if (!selectGlobalValue(GVarVReg, *MI, Init))
5298 return false;
5299 // We violate SSA form by inserting OpVariable and still having a gMIR
5300 // instruction %vreg = G_GLOBAL_VALUE @gvar. We need to fix this by erasing
5301 // the duplicated definition.
5302 if (MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
5304 MI->eraseFromParent();
5305 }
5306 return true;
5307 }
5308 case Intrinsic::spv_undef: {
5309 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
5310 .addDef(ResVReg)
5311 .addUse(GR.getSPIRVTypeID(ResType));
5312 MIB.constrainAllUses(TII, TRI, RBI);
5313 return true;
5314 }
5315 case Intrinsic::spv_poison:
5316 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpPoisonKHR))
5317 .addDef(ResVReg)
5318 .addUse(GR.getSPIRVTypeID(ResType))
5319 .constrainAllUses(TII, TRI, RBI);
5320 return true;
5321 case Intrinsic::spv_freeze:
5322 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpFreezeKHR))
5323 .addDef(ResVReg)
5324 .addUse(GR.getSPIRVTypeID(ResType))
5325 .addUse(I.getOperand(2).getReg())
5326 .constrainAllUses(TII, TRI, RBI);
5327 return true;
5328 case Intrinsic::spv_named_boolean_spec_constant: {
5329 auto Opcode = I.getOperand(3).getImm() ? SPIRV::OpSpecConstantTrue
5330 : SPIRV::OpSpecConstantFalse;
5331
5332 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
5333 .addDef(I.getOperand(0).getReg())
5334 .addUse(GR.getSPIRVTypeID(ResType));
5335 MIB.constrainAllUses(TII, TRI, RBI);
5336 unsigned SpecId = I.getOperand(2).getImm();
5337 buildOpDecorate(I.getOperand(0).getReg(), *++MIB->getIterator(), TII,
5338 SPIRV::Decoration::SpecId, {SpecId});
5339
5340 return true;
5341 }
5342 case Intrinsic::spv_const_composite: {
5343 // If no values are attached, the composite is null constant.
5344 bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
5345 SmallVector<Register> CompositeArgs;
5346 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
5347
5348 // skip type MD node we already used when generated assign.type for this
5349 if (!IsNull) {
5350 if (!wrapIntoSpecConstantOp(I, CompositeArgs))
5351 return false;
5352 std::function<bool(Register)> HasSpecConstOperand =
5353 [&](Register Reg) -> bool {
5354 MachineInstr *Def = MRI->getVRegDef(Reg);
5355 if (!Def)
5356 return false;
5357 if (!isConstReg(MRI, Def))
5358 return true;
5359 // Recurse into not-yet-selected spv_const_composite intrinsics
5360 // to detect transitive spec constant operands.
5361 if (isSpvIntrinsic(*Def, Intrinsic::spv_const_composite)) {
5362 for (unsigned J = Def->getNumExplicitDefs() + 1;
5363 J < Def->getNumExplicitOperands(); ++J) {
5364 if (Def->getOperand(J).isReg() &&
5365 HasSpecConstOperand(Def->getOperand(J).getReg()))
5366 return true;
5367 }
5368 }
5369 return false;
5370 };
5371 bool HasSpecConst = llvm::any_of(CompositeArgs, HasSpecConstOperand);
5372 unsigned CompositeOpc = HasSpecConst ? SPIRV::OpSpecConstantComposite
5373 : SPIRV::OpConstantComposite;
5374 unsigned ContinuedOpc = HasSpecConst
5375 ? SPIRV::OpSpecConstantCompositeContinuedINTEL
5376 : SPIRV::OpConstantCompositeContinuedINTEL;
5377 MachineIRBuilder MIR(I);
5378 SmallVector<MachineInstr *, 4> Instructions = createContinuedInstructions(
5379 MIR, CompositeOpc, 3, ContinuedOpc, CompositeArgs, ResVReg,
5380 GR.getSPIRVTypeID(ResType));
5381 for (auto *Instr : Instructions) {
5382 Instr->setDebugLoc(I.getDebugLoc());
5384 }
5385 return true;
5386 } else {
5387 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
5388 .addDef(ResVReg)
5389 .addUse(GR.getSPIRVTypeID(ResType));
5390 MIB.constrainAllUses(TII, TRI, RBI);
5391 return true;
5392 }
5393 }
5394 case Intrinsic::spv_assign_name: {
5395 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName));
5396 MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg());
5397 for (unsigned i = I.getNumExplicitDefs() + 2;
5398 i < I.getNumExplicitOperands(); ++i) {
5399 MIB.addImm(I.getOperand(i).getImm());
5400 }
5401 MIB.constrainAllUses(TII, TRI, RBI);
5402 return true;
5403 }
5404 case Intrinsic::spv_switch: {
5405 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch));
5406 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
5407 if (I.getOperand(i).isReg())
5408 MIB.addReg(I.getOperand(i).getReg());
5409 else if (I.getOperand(i).isCImm())
5410 addNumImm(I.getOperand(i).getCImm()->getValue(), MIB);
5411 else if (I.getOperand(i).isMBB())
5412 MIB.addMBB(I.getOperand(i).getMBB());
5413 else
5414 llvm_unreachable("Unexpected OpSwitch operand");
5415 }
5416 MIB.constrainAllUses(TII, TRI, RBI);
5417 return true;
5418 }
5419 case Intrinsic::spv_loop_merge: {
5420 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopMerge));
5421 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
5422 if (I.getOperand(i).isMBB())
5423 MIB.addMBB(I.getOperand(i).getMBB());
5424 else
5425 MIB.addImm(foldImm(I.getOperand(i), MRI));
5426 }
5427 MIB.constrainAllUses(TII, TRI, RBI);
5428 return true;
5429 }
5430 case Intrinsic::spv_loop_control_intel: {
5431 auto MIB =
5432 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopControlINTEL));
5433 for (unsigned J = 1; J < I.getNumExplicitOperands(); ++J)
5434 MIB.addImm(foldImm(I.getOperand(J), MRI));
5435 MIB.constrainAllUses(TII, TRI, RBI);
5436 return true;
5437 }
5438 case Intrinsic::spv_selection_merge: {
5439 auto MIB =
5440 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSelectionMerge));
5441 assert(I.getOperand(1).isMBB() &&
5442 "operand 1 to spv_selection_merge must be a basic block");
5443 MIB.addMBB(I.getOperand(1).getMBB());
5444 MIB.addImm(getSelectionOperandForImm(I.getOperand(2).getImm()));
5445 MIB.constrainAllUses(TII, TRI, RBI);
5446 return true;
5447 }
5448 case Intrinsic::spv_cmpxchg:
5449 return selectAtomicCmpXchg(ResVReg, ResType, I);
5450 case Intrinsic::spv_unreachable:
5451 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUnreachable))
5452 .constrainAllUses(TII, TRI, RBI);
5453 return true;
5454 case Intrinsic::spv_abort:
5455 return selectAbort(I);
5456 case Intrinsic::spv_alloca:
5457 return selectFrameIndex(ResVReg, ResType, I);
5458 case Intrinsic::spv_alloca_array:
5459 return selectAllocaArray(ResVReg, ResType, I);
5460 case Intrinsic::spv_assume:
5461 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
5462 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAssumeTrueKHR))
5463 .addUse(I.getOperand(1).getReg())
5464 .constrainAllUses(TII, TRI, RBI);
5465 return true;
5466 }
5467 break;
5468 case Intrinsic::spv_expect:
5469 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
5470 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExpectKHR))
5471 .addDef(ResVReg)
5472 .addUse(GR.getSPIRVTypeID(ResType))
5473 .addUse(I.getOperand(2).getReg())
5474 .addUse(I.getOperand(3).getReg())
5475 .constrainAllUses(TII, TRI, RBI);
5476 return true;
5477 }
5478 break;
5479 case Intrinsic::arithmetic_fence:
5480 if (STI.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence)) {
5481 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpArithmeticFenceEXT))
5482 .addDef(ResVReg)
5483 .addUse(GR.getSPIRVTypeID(ResType))
5484 .addUse(I.getOperand(2).getReg())
5485 .constrainAllUses(TII, TRI, RBI);
5486 return true;
5487 } else
5488 return BuildCOPY(ResVReg, I.getOperand(2).getReg(), I);
5489 break;
5490 case Intrinsic::spv_thread_id:
5491 // The HLSL SV_DispatchThreadID semantic is lowered to llvm.spv.thread.id
5492 // intrinsic in LLVM IR for SPIR-V backend.
5493 //
5494 // In SPIR-V backend, llvm.spv.thread.id is now correctly translated to a
5495 // `GlobalInvocationId` builtin variable
5496 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalInvocationId, ResVReg,
5497 ResType, I);
5498 case Intrinsic::spv_thread_id_in_group:
5499 // The HLSL SV_GroupThreadId semantic is lowered to
5500 // llvm.spv.thread.id.in.group intrinsic in LLVM IR for SPIR-V backend.
5501 //
5502 // In SPIR-V backend, llvm.spv.thread.id.in.group is now correctly
5503 // translated to a `LocalInvocationId` builtin variable
5504 return loadVec3BuiltinInputID(SPIRV::BuiltIn::LocalInvocationId, ResVReg,
5505 ResType, I);
5506 case Intrinsic::spv_group_id:
5507 // The HLSL SV_GroupId semantic is lowered to
5508 // llvm.spv.group.id intrinsic in LLVM IR for SPIR-V backend.
5509 //
5510 // In SPIR-V backend, llvm.spv.group.id is now translated to a `WorkgroupId`
5511 // builtin variable
5512 return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupId, ResVReg, ResType,
5513 I);
5514 case Intrinsic::spv_flattened_thread_id_in_group:
5515 // The HLSL SV_GroupIndex semantic is lowered to
5516 // llvm.spv.flattened.thread.id.in.group() intrinsic in LLVM IR for SPIR-V
5517 // backend.
5518 //
5519 // In SPIR-V backend, llvm.spv.flattened.thread.id.in.group is translated to
5520 // a `LocalInvocationIndex` builtin variable
5521 return loadBuiltinInputID(SPIRV::BuiltIn::LocalInvocationIndex, ResVReg,
5522 ResType, I);
5523 case Intrinsic::spv_workgroup_size:
5524 return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupSize, ResVReg,
5525 ResType, I);
5526 case Intrinsic::spv_global_size:
5527 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalSize, ResVReg, ResType,
5528 I);
5529 case Intrinsic::spv_global_offset:
5530 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalOffset, ResVReg,
5531 ResType, I);
5532 case Intrinsic::spv_num_workgroups:
5533 return loadVec3BuiltinInputID(SPIRV::BuiltIn::NumWorkgroups, ResVReg,
5534 ResType, I);
5535 case Intrinsic::spv_subgroup_size:
5536 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupSize, ResVReg, ResType,
5537 I);
5538 case Intrinsic::spv_num_subgroups:
5539 return loadBuiltinInputID(SPIRV::BuiltIn::NumSubgroups, ResVReg, ResType,
5540 I);
5541 case Intrinsic::spv_subgroup_id:
5542 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupId, ResVReg, ResType, I);
5543 case Intrinsic::spv_subgroup_local_invocation_id:
5544 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupLocalInvocationId,
5545 ResVReg, ResType, I);
5546 case Intrinsic::spv_subgroup_max_size:
5547 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupMaxSize, ResVReg, ResType,
5548 I);
5549 case Intrinsic::spv_fdot:
5550 return selectFloatDot(ResVReg, ResType, I);
5551 case Intrinsic::spv_udot:
5552 case Intrinsic::spv_sdot:
5553 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
5554 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
5555 return selectIntegerDot(ResVReg, ResType, I,
5556 /*Signed=*/IID == Intrinsic::spv_sdot);
5557 return selectIntegerDotExpansion(ResVReg, ResType, I);
5558 case Intrinsic::spv_dot4add_i8packed:
5559 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
5560 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
5561 return selectDot4AddPacked<true>(ResVReg, ResType, I);
5562 return selectDot4AddPackedExpansion<true>(ResVReg, ResType, I);
5563 case Intrinsic::spv_dot4add_u8packed:
5564 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
5565 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
5566 return selectDot4AddPacked<false>(ResVReg, ResType, I);
5567 return selectDot4AddPackedExpansion<false>(ResVReg, ResType, I);
5568 case Intrinsic::spv_all:
5569 return selectAll(ResVReg, ResType, I);
5570 case Intrinsic::spv_any:
5571 return selectAny(ResVReg, ResType, I);
5572 case Intrinsic::spv_distance:
5573 return selectExtInst(ResVReg, ResType, I, CL::distance, GL::Distance);
5574 case Intrinsic::spv_lerp:
5575 return selectExtInst(ResVReg, ResType, I, CL::mix, GL::FMix);
5576 case Intrinsic::spv_length:
5577 return selectExtInst(ResVReg, ResType, I, CL::length, GL::Length);
5578 case Intrinsic::spv_degrees:
5579 return selectExtInst(ResVReg, ResType, I, CL::degrees, GL::Degrees);
5580 case Intrinsic::spv_faceforward:
5581 return selectExtInst(ResVReg, ResType, I, GL::FaceForward);
5582 case Intrinsic::spv_frac:
5583 return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
5584 case Intrinsic::spv_isinf:
5585 return selectOpIsInf(ResVReg, ResType, I);
5586 case Intrinsic::spv_isnan:
5587 return selectOpIsNan(ResVReg, ResType, I);
5588 case Intrinsic::spv_isfinite:
5589 return selectOpIsFinite(ResVReg, ResType, I);
5590 case Intrinsic::spv_isnormal:
5591 return selectOpIsNormal(ResVReg, ResType, I);
5592 case Intrinsic::spv_normalize:
5593 return selectExtInst(ResVReg, ResType, I, CL::normalize, GL::Normalize);
5594 case Intrinsic::spv_refract:
5595 return selectExtInst(ResVReg, ResType, I, GL::Refract);
5596 case Intrinsic::spv_reflect:
5597 return selectExtInst(ResVReg, ResType, I, GL::Reflect);
5598 case Intrinsic::spv_rsqrt:
5599 return selectExtInst(ResVReg, ResType, I, CL::rsqrt, GL::InverseSqrt);
5600 case Intrinsic::spv_sign:
5601 return selectSign(ResVReg, ResType, I);
5602 case Intrinsic::spv_smoothstep:
5603 return selectExtInst(ResVReg, ResType, I, CL::smoothstep, GL::SmoothStep);
5604 case Intrinsic::spv_firstbituhigh: // There is no CL equivalent of FindUMsb
5605 return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/false);
5606 case Intrinsic::spv_firstbitshigh: // There is no CL equivalent of FindSMsb
5607 return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/true);
5608 case Intrinsic::spv_firstbitlow: // There is no CL equivlent of FindILsb
5609 return selectFirstBitLow(ResVReg, ResType, I);
5610 case Intrinsic::spv_all_memory_barrier:
5611 return selectBarrierInst(I, SPIRV::Scope::Device,
5612 SPIRV::MemorySemantics::UniformMemory |
5613 SPIRV::MemorySemantics::ImageMemory |
5614 SPIRV::MemorySemantics::WorkgroupMemory,
5615 /*WithGroupSync*/ false);
5616 case Intrinsic::spv_all_memory_barrier_with_group_sync:
5617 return selectBarrierInst(I, SPIRV::Scope::Device,
5618 SPIRV::MemorySemantics::UniformMemory |
5619 SPIRV::MemorySemantics::ImageMemory |
5620 SPIRV::MemorySemantics::WorkgroupMemory,
5621 /*WithGroupSync*/ true);
5622 case Intrinsic::spv_device_memory_barrier:
5623 return selectBarrierInst(I, SPIRV::Scope::Device,
5624 SPIRV::MemorySemantics::UniformMemory |
5625 SPIRV::MemorySemantics::ImageMemory,
5626 /*WithGroupSync*/ false);
5627 case Intrinsic::spv_device_memory_barrier_with_group_sync:
5628 return selectBarrierInst(I, SPIRV::Scope::Device,
5629 SPIRV::MemorySemantics::UniformMemory |
5630 SPIRV::MemorySemantics::ImageMemory,
5631 /*WithGroupSync*/ true);
5632 case Intrinsic::spv_group_memory_barrier:
5633 return selectBarrierInst(I, SPIRV::Scope::Workgroup,
5634 SPIRV::MemorySemantics::WorkgroupMemory,
5635 /*WithGroupSync*/ false);
5636 case Intrinsic::spv_group_memory_barrier_with_group_sync:
5637 return selectBarrierInst(I, SPIRV::Scope::Workgroup,
5638 SPIRV::MemorySemantics::WorkgroupMemory,
5639 /*WithGroupSync*/ true);
5640 case Intrinsic::spv_generic_cast_to_ptr_explicit: {
5641 Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 1).getReg();
5642 SPIRV::StorageClass::StorageClass ResSC =
5643 GR.getPointerStorageClass(ResType);
5644 if (!isGenericCastablePtr(ResSC))
5645 return diagnoseUnsupported(I, "The target storage class is not castable "
5646 "from the Generic storage class");
5647 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpGenericCastToPtrExplicit))
5648 .addDef(ResVReg)
5649 .addUse(GR.getSPIRVTypeID(ResType))
5650 .addUse(PtrReg)
5651 .addImm(ResSC)
5652 .constrainAllUses(TII, TRI, RBI);
5653 return true;
5654 }
5655 case Intrinsic::spv_lifetime_start:
5656 case Intrinsic::spv_lifetime_end: {
5657 unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
5658 : SPIRV::OpLifetimeStop;
5659 int64_t Size = I.getOperand(I.getNumExplicitDefs() + 1).getImm();
5660 Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 2).getReg();
5661 if (Size == -1)
5662 Size = 0;
5663 BuildMI(BB, I, I.getDebugLoc(), TII.get(Op))
5664 .addUse(PtrReg)
5665 .addImm(Size)
5666 .constrainAllUses(TII, TRI, RBI);
5667 return true;
5668 }
5669 case Intrinsic::spv_saturate:
5670 return selectSaturate(ResVReg, ResType, I);
5671 case Intrinsic::spv_nclamp:
5672 return selectExtInst(ResVReg, ResType, I, CL::fclamp, GL::NClamp);
5673 case Intrinsic::spv_uclamp:
5674 return selectExtInst(ResVReg, ResType, I, CL::u_clamp, GL::UClamp);
5675 case Intrinsic::spv_sclamp:
5676 return selectExtInst(ResVReg, ResType, I, CL::s_clamp, GL::SClamp);
5677 case Intrinsic::spv_subgroup_prefix_bit_count:
5678 return selectWavePrefixBitCount(ResVReg, ResType, I);
5679 case Intrinsic::spv_wave_active_countbits:
5680 return selectWaveActiveCountBits(ResVReg, ResType, I);
5681 case Intrinsic::spv_wave_all_equal:
5682 return selectWaveActiveAllEqual(ResVReg, ResType, I);
5683 case Intrinsic::spv_wave_all:
5684 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAll);
5685 case Intrinsic::spv_wave_any:
5686 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAny);
5687 case Intrinsic::spv_subgroup_ballot:
5688 return selectWaveOpInst(ResVReg, ResType, I,
5689 SPIRV::OpGroupNonUniformBallot);
5690 case Intrinsic::spv_wave_is_first_lane:
5691 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformElect);
5692 case Intrinsic::spv_wave_reduce_or:
5693 return selectWaveReduceOp(ResVReg, ResType, I,
5694 SPIRV::OpGroupNonUniformBitwiseOr);
5695 case Intrinsic::spv_wave_reduce_xor:
5696 return selectWaveReduceOp(ResVReg, ResType, I,
5697 SPIRV::OpGroupNonUniformBitwiseXor);
5698 case Intrinsic::spv_wave_reduce_and:
5699 return selectWaveReduceOp(ResVReg, ResType, I,
5700 SPIRV::OpGroupNonUniformBitwiseAnd);
5701 case Intrinsic::spv_wave_reduce_umax:
5702 return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ true);
5703 case Intrinsic::spv_wave_reduce_max:
5704 return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ false);
5705 case Intrinsic::spv_wave_reduce_umin:
5706 return selectWaveReduceMin(ResVReg, ResType, I, /*IsUnsigned*/ true);
5707 case Intrinsic::spv_wave_reduce_min:
5708 return selectWaveReduceMin(ResVReg, ResType, I, /*IsUnsigned*/ false);
5709 case Intrinsic::spv_wave_reduce_sum:
5710 return selectWaveReduceSum(ResVReg, ResType, I);
5711 case Intrinsic::spv_wave_product:
5712 return selectWaveReduceProduct(ResVReg, ResType, I);
5713 case Intrinsic::spv_wave_readlane:
5714 return selectWaveOpInst(ResVReg, ResType, I,
5715 SPIRV::OpGroupNonUniformShuffle);
5716 case Intrinsic::spv_wave_prefix_sum:
5717 return selectWaveExclusiveScanSum(ResVReg, ResType, I);
5718 case Intrinsic::spv_wave_prefix_product:
5719 return selectWaveExclusiveScanProduct(ResVReg, ResType, I);
5720 case Intrinsic::spv_quad_read_across_x: {
5721 return selectQuadSwap(ResVReg, ResType, I, /*Direction*/ 0);
5722 }
5723 case Intrinsic::spv_quad_read_across_y: {
5724 return selectQuadSwap(ResVReg, ResType, I, /*Direction*/ 1);
5725 }
5726 case Intrinsic::spv_quad_read_across_diagonal: {
5727 return selectQuadSwap(ResVReg, ResType, I, /*Direction*/ 2);
5728 }
5729 case Intrinsic::spv_radians:
5730 return selectExtInst(ResVReg, ResType, I, CL::radians, GL::Radians);
5731 // Discard intrinsics which we do not expect to actually represent code after
5732 // lowering or intrinsics which are not implemented but should not crash when
5733 // found in a customer's LLVM IR input.
5734 case Intrinsic::instrprof_increment:
5735 case Intrinsic::instrprof_increment_step:
5736 case Intrinsic::instrprof_value_profile:
5737 break;
5738 // Discard internal intrinsics.
5739 case Intrinsic::spv_value_md:
5740 break;
5741 case Intrinsic::spv_resource_handlefrombinding: {
5742 return selectHandleFromBinding(ResVReg, ResType, I);
5743 }
5744 case Intrinsic::spv_resource_counterhandlefrombinding:
5745 return selectCounterHandleFromBinding(ResVReg, ResType, I);
5746 case Intrinsic::spv_resource_updatecounter:
5747 return selectUpdateCounter(ResVReg, ResType, I);
5748 case Intrinsic::spv_resource_store_typedbuffer: {
5749 return selectImageWriteIntrinsic(I);
5750 }
5751 case Intrinsic::spv_resource_load_typedbuffer: {
5752 return selectReadImageIntrinsic(ResVReg, ResType, I);
5753 }
5754 case Intrinsic::spv_resource_load_level: {
5755 return selectLoadLevelIntrinsic(ResVReg, ResType, I);
5756 }
5757 case Intrinsic::spv_resource_getdimensions_x:
5758 case Intrinsic::spv_resource_getdimensions_xy:
5759 case Intrinsic::spv_resource_getdimensions_xyz: {
5760 return selectGetDimensionsIntrinsic(ResVReg, ResType, I);
5761 }
5762 case Intrinsic::spv_resource_getdimensions_levels_x:
5763 case Intrinsic::spv_resource_getdimensions_levels_xy:
5764 case Intrinsic::spv_resource_getdimensions_levels_xyz: {
5765 return selectGetDimensionsLevelsIntrinsic(ResVReg, ResType, I);
5766 }
5767 case Intrinsic::spv_resource_getdimensions_ms_xy:
5768 case Intrinsic::spv_resource_getdimensions_ms_xyz: {
5769 return selectGetDimensionsMSIntrinsic(ResVReg, ResType, I);
5770 }
5771 case Intrinsic::spv_resource_calculate_lod:
5772 case Intrinsic::spv_resource_calculate_lod_unclamped:
5773 return selectCalculateLodIntrinsic(ResVReg, ResType, I);
5774 case Intrinsic::spv_resource_sample:
5775 case Intrinsic::spv_resource_sample_clamp:
5776 return selectSampleBasicIntrinsic(ResVReg, ResType, I);
5777 case Intrinsic::spv_resource_samplebias:
5778 case Intrinsic::spv_resource_samplebias_clamp:
5779 return selectSampleBiasIntrinsic(ResVReg, ResType, I);
5780 case Intrinsic::spv_resource_samplegrad:
5781 case Intrinsic::spv_resource_samplegrad_clamp:
5782 return selectSampleGradIntrinsic(ResVReg, ResType, I);
5783 case Intrinsic::spv_resource_samplelevel:
5784 return selectSampleLevelIntrinsic(ResVReg, ResType, I);
5785 case Intrinsic::spv_resource_samplecmp:
5786 case Intrinsic::spv_resource_samplecmp_clamp:
5787 return selectSampleCmpIntrinsic(ResVReg, ResType, I);
5788 case Intrinsic::spv_resource_samplecmplevelzero:
5789 return selectSampleCmpLevelZeroIntrinsic(ResVReg, ResType, I);
5790 case Intrinsic::spv_resource_gather:
5791 case Intrinsic::spv_resource_gather_cmp:
5792 return selectGatherIntrinsic(ResVReg, ResType, I);
5793 case Intrinsic::spv_resource_getbasepointer:
5794 case Intrinsic::spv_resource_getpointer: {
5795 return selectResourceGetPointer(ResVReg, ResType, I);
5796 }
5797 case Intrinsic::spv_pushconstant_getpointer: {
5798 return selectPushConstantGetPointer(ResVReg, ResType, I);
5799 }
5800 case Intrinsic::spv_discard: {
5801 return selectDiscard(ResVReg, ResType, I);
5802 }
5803 case Intrinsic::spv_resource_nonuniformindex: {
5804 return selectResourceNonUniformIndex(ResVReg, ResType, I);
5805 }
5806 case Intrinsic::spv_unpackhalf2x16: {
5807 return selectExtInst(ResVReg, ResType, I, GL::UnpackHalf2x16);
5808 }
5809 case Intrinsic::spv_packhalf2x16: {
5810 return selectExtInst(ResVReg, ResType, I, GL::PackHalf2x16);
5811 }
5812 case Intrinsic::spv_ddx:
5813 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdx);
5814 case Intrinsic::spv_ddy:
5815 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdy);
5816 case Intrinsic::spv_ddx_coarse:
5817 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxCoarse);
5818 case Intrinsic::spv_ddy_coarse:
5819 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
5820 case Intrinsic::spv_ddx_fine:
5821 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxFine);
5822 case Intrinsic::spv_ddy_fine:
5823 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyFine);
5824 case Intrinsic::spv_fwidth:
5825 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpFwidth);
5826 case Intrinsic::spv_masked_gather:
5827 if (STI.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter))
5828 return selectMaskedGather(ResVReg, ResType, I);
5829 return diagnoseUnsupported(
5830 I, "llvm.masked.gather requires SPV_INTEL_masked_gather_scatter");
5831 case Intrinsic::spv_masked_scatter:
5832 if (STI.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter))
5833 return selectMaskedScatter(I);
5834 return diagnoseUnsupported(
5835 I, "llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter");
5836 case Intrinsic::returnaddress:
5837 case Intrinsic::frameaddress: {
5838 // SPIR-V does not have a stack or return address. Lower to null.
5839 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
5840 .addDef(ResVReg)
5841 .addUse(GR.getSPIRVTypeID(ResType));
5842 MIB.constrainAllUses(TII, TRI, RBI);
5843 return true;
5844 }
5845 default:
5846 return diagnoseUnsupported(I, "intrinsic selection not implemented.");
5847 }
5848 return true;
5849}
5850
5851bool SPIRVInstructionSelector::selectHandleFromBinding(Register &ResVReg,
5852 SPIRVTypeInst ResType,
5853 MachineInstr &I) const {
5854 // The images need to be loaded in the same basic block as their use. We defer
5855 // loading the image to the intrinsic that uses it.
5856 if (ResType->getOpcode() == SPIRV::OpTypeImage)
5857 return true;
5858
5859 return loadHandleBeforePosition(ResVReg, GR.getSPIRVTypeForVReg(ResVReg),
5860 *cast<GIntrinsic>(&I), I);
5861}
5862
5863bool SPIRVInstructionSelector::selectCounterHandleFromBinding(
5864 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5865 auto &Intr = cast<GIntrinsic>(I);
5866 assert(Intr.getIntrinsicID() ==
5867 Intrinsic::spv_resource_counterhandlefrombinding);
5868
5869 // Extract information from the intrinsic call.
5870 Register MainHandleReg = Intr.getOperand(2).getReg();
5871 auto *MainHandleDef = cast<GIntrinsic>(getVRegDef(*MRI, MainHandleReg));
5872 assert(MainHandleDef->getIntrinsicID() ==
5873 Intrinsic::spv_resource_handlefrombinding);
5874
5875 uint32_t Set = getIConstVal(Intr.getOperand(4).getReg(), MRI);
5876 uint32_t Binding = getIConstVal(Intr.getOperand(3).getReg(), MRI);
5877 uint32_t ArraySize = getIConstVal(MainHandleDef->getOperand(4).getReg(), MRI);
5878 Register IndexReg = MainHandleDef->getOperand(5).getReg();
5879 std::string CounterName =
5880 getStringValueFromReg(MainHandleDef->getOperand(6).getReg(), *MRI) +
5881 ".counter";
5882
5883 // Create the counter variable.
5884 MachineIRBuilder MIRBuilder(I);
5885 Register CounterVarReg =
5886 buildPointerToResource(SPIRVTypeInst(GR.getPointeeType(ResType)),
5887 GR.getPointerStorageClass(ResType), Set, Binding,
5888 ArraySize, IndexReg, CounterName, MIRBuilder);
5889
5890 return BuildCOPY(ResVReg, CounterVarReg, I);
5891}
5892
5893bool SPIRVInstructionSelector::selectUpdateCounter(Register &ResVReg,
5894 SPIRVTypeInst ResType,
5895 MachineInstr &I) const {
5896 auto &Intr = cast<GIntrinsic>(I);
5897 assert(Intr.getIntrinsicID() == Intrinsic::spv_resource_updatecounter);
5898
5899 Register CounterHandleReg = Intr.getOperand(2).getReg();
5900 Register IncrReg = Intr.getOperand(3).getReg();
5901
5902 // The counter handle is a pointer to the counter variable (which is a struct
5903 // containing an i32). We need to get a pointer to that i32 member to do the
5904 // atomic operation.
5905#ifndef NDEBUG
5906 SPIRVTypeInst CounterVarType = GR.getSPIRVTypeForVReg(CounterHandleReg);
5907 SPIRVTypeInst CounterVarPointeeType = GR.getPointeeType(CounterVarType);
5908 assert(CounterVarPointeeType &&
5909 CounterVarPointeeType->getOpcode() == SPIRV::OpTypeStruct &&
5910 "Counter variable must be a struct");
5911 assert(GR.getPointerStorageClass(CounterVarType) ==
5912 SPIRV::StorageClass::StorageBuffer &&
5913 "Counter variable must be in the storage buffer storage class");
5914 assert(CounterVarPointeeType->getNumOperands() == 2 &&
5915 "Counter variable must have exactly 1 member in the struct");
5916 const SPIRVTypeInst MemberType =
5917 GR.getSPIRVTypeForVReg(CounterVarPointeeType->getOperand(1).getReg());
5918 assert(MemberType->getOpcode() == SPIRV::OpTypeInt &&
5919 "Counter variable struct must have a single i32 member");
5920#endif
5921
5922 // The struct has a single i32 member.
5923 MachineIRBuilder MIRBuilder(I);
5924 const Type *LLVMIntType =
5925 Type::getInt32Ty(I.getMF()->getFunction().getContext());
5926
5927 SPIRVTypeInst IntPtrType = GR.getOrCreateSPIRVPointerType(
5928 LLVMIntType, MIRBuilder, SPIRV::StorageClass::StorageBuffer);
5929
5930 Register Zero = buildI32Constant(0, I);
5931
5932 Register PtrToCounter =
5933 MRI->createVirtualRegister(GR.getRegClass(IntPtrType));
5934 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain))
5935 .addDef(PtrToCounter)
5936 .addUse(GR.getSPIRVTypeID(IntPtrType))
5937 .addUse(CounterHandleReg)
5938 .addUse(Zero)
5939 .constrainAllUses(TII, TRI, RBI);
5940
5941 // For UAV/SSBO counters, the scope is Device. The counter variable is not
5942 // used as a flag. So the memory semantics can be None.
5943 Register Scope = buildI32Constant(SPIRV::Scope::Device, I);
5944 Register Semantics = buildI32Constant(SPIRV::MemorySemantics::None, I);
5945
5946 int64_t IncrVal = getIConstValSext(IncrReg, MRI);
5947 Register Incr = buildI32Constant(static_cast<uint32_t>(IncrVal), I);
5948
5949 Register AtomicRes = MRI->createVirtualRegister(GR.getRegClass(ResType));
5950 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAtomicIAdd))
5951 .addDef(AtomicRes)
5952 .addUse(GR.getSPIRVTypeID(ResType))
5953 .addUse(PtrToCounter)
5954 .addUse(Scope)
5955 .addUse(Semantics)
5956 .addUse(Incr)
5957 .constrainAllUses(TII, TRI, RBI);
5958 if (IncrVal >= 0) {
5959 return BuildCOPY(ResVReg, AtomicRes, I);
5960 }
5961
5962 // In HLSL, IncrementCounter returns the value *before* the increment, while
5963 // DecrementCounter returns the value *after* the decrement. Both are lowered
5964 // to the same atomic intrinsic which returns the value *before* the
5965 // operation. So for decrements (negative IncrVal), we must subtract the
5966 // increment value from the result to get the post-decrement value.
5967 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
5968 .addDef(ResVReg)
5969 .addUse(GR.getSPIRVTypeID(ResType))
5970 .addUse(AtomicRes)
5971 .addUse(Incr)
5972 .constrainAllUses(TII, TRI, RBI);
5973 return true;
5974}
5975bool SPIRVInstructionSelector::selectReadImageIntrinsic(Register &ResVReg,
5976 SPIRVTypeInst ResType,
5977 MachineInstr &I) const {
5978
5979 // If the load of the image is in a different basic block, then
5980 // this will generate invalid code. A proper solution is to move
5981 // the OpLoad from selectHandleFromBinding here. However, to do
5982 // that we will need to change the return type of the intrinsic.
5983 // We will do that when we can, but for now trying to move forward with other
5984 // issues.
5985 Register ImageReg = I.getOperand(2).getReg();
5986 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
5987 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
5988 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
5989 *ImageDef, I)) {
5990 return false;
5991 }
5992
5993 Register IdxReg = I.getOperand(3).getReg();
5994 DebugLoc Loc = I.getDebugLoc();
5995 MachineInstr &Pos = I;
5996
5997 return generateImageReadOrFetch(ResVReg, ResType, NewImageReg, IdxReg, Loc,
5998 Pos);
5999}
6000
6001bool SPIRVInstructionSelector::generateSampleImage(
6002 Register ResVReg, SPIRVTypeInst ResType, Register ImageReg,
6003 Register SamplerReg, Register CoordinateReg, const ImageOperands &ImOps,
6004 DebugLoc Loc, MachineInstr &Pos) const {
6005 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
6006 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
6007 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
6008 *ImageDef, Pos)) {
6009 return false;
6010 }
6011
6012 auto *SamplerDef = cast<GIntrinsic>(getVRegDef(*MRI, SamplerReg));
6013 Register NewSamplerReg =
6014 MRI->createVirtualRegister(MRI->getRegClass(SamplerReg));
6015 if (!loadHandleBeforePosition(NewSamplerReg,
6016 GR.getSPIRVTypeForVReg(SamplerReg), *SamplerDef,
6017 Pos)) {
6018 return false;
6019 }
6020
6021 MachineIRBuilder MIRBuilder(Pos);
6022 SPIRVTypeInst SampledImageType = GR.getOrCreateOpTypeSampledImage(
6023 GR.getSPIRVTypeForVReg(ImageReg), MIRBuilder);
6024 Register SampledImageReg =
6025 MRI->createVirtualRegister(GR.getRegClass(SampledImageType));
6026
6027 BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpSampledImage))
6028 .addDef(SampledImageReg)
6029 .addUse(GR.getSPIRVTypeID(SampledImageType))
6030 .addUse(NewImageReg)
6031 .addUse(NewSamplerReg)
6032 .constrainAllUses(TII, TRI, RBI);
6033
6034 bool IsExplicitLod = ImOps.GradX.has_value() || ImOps.GradY.has_value() ||
6035 ImOps.Lod.has_value();
6036 unsigned Opcode = IsExplicitLod ? SPIRV::OpImageSampleExplicitLod
6037 : SPIRV::OpImageSampleImplicitLod;
6038 if (ImOps.Compare)
6039 Opcode = IsExplicitLod ? SPIRV::OpImageSampleDrefExplicitLod
6040 : SPIRV::OpImageSampleDrefImplicitLod;
6041
6042 auto MIB = BuildMI(*Pos.getParent(), Pos, Loc, TII.get(Opcode))
6043 .addDef(ResVReg)
6044 .addUse(GR.getSPIRVTypeID(ResType))
6045 .addUse(SampledImageReg)
6046 .addUse(CoordinateReg);
6047
6048 if (ImOps.Compare)
6049 MIB.addUse(*ImOps.Compare);
6050
6051 uint32_t ImageOperands = 0;
6052 if (ImOps.Bias)
6053 ImageOperands |= SPIRV::ImageOperand::Bias;
6054 if (ImOps.Lod)
6055 ImageOperands |= SPIRV::ImageOperand::Lod;
6056 if (ImOps.GradX && ImOps.GradY)
6057 ImageOperands |= SPIRV::ImageOperand::Grad;
6058 if (ImOps.Offset && !isScalarOrVectorIntConstantZero(*ImOps.Offset)) {
6059 if (isConstReg(MRI, *ImOps.Offset))
6060 ImageOperands |= SPIRV::ImageOperand::ConstOffset;
6061 else {
6062 Pos.emitGenericError(
6063 "Non-constant offsets are not supported in sample instructions.");
6064 return false;
6065 }
6066 }
6067 if (ImOps.MinLod)
6068 ImageOperands |= SPIRV::ImageOperand::MinLod;
6069
6070 if (ImageOperands != 0) {
6071 MIB.addImm(ImageOperands);
6072 if (ImageOperands & SPIRV::ImageOperand::Bias)
6073 MIB.addUse(*ImOps.Bias);
6074 if (ImageOperands & SPIRV::ImageOperand::Lod)
6075 MIB.addUse(*ImOps.Lod);
6076 if (ImageOperands & SPIRV::ImageOperand::Grad) {
6077 MIB.addUse(*ImOps.GradX);
6078 MIB.addUse(*ImOps.GradY);
6079 }
6080 if (ImageOperands &
6081 (SPIRV::ImageOperand::ConstOffset | SPIRV::ImageOperand::Offset))
6082 MIB.addUse(*ImOps.Offset);
6083 if (ImageOperands & SPIRV::ImageOperand::MinLod)
6084 MIB.addUse(*ImOps.MinLod);
6085 }
6086
6087 MIB.constrainAllUses(TII, TRI, RBI);
6088 return true;
6089}
6090
6091bool SPIRVInstructionSelector::selectImageQuerySize(
6092 Register ImageReg, Register &ResVReg, MachineInstr &I,
6093 std::optional<Register> LodReg) const {
6094 unsigned Opcode =
6095 LodReg ? SPIRV::OpImageQuerySizeLod : SPIRV::OpImageQuerySize;
6096 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(ImageReg);
6097 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
6098 "ImageReg is not an image type.");
6099
6100 auto Dim = static_cast<SPIRV::Dim::Dim>(ImageType->getOperand(2).getImm());
6101 bool IsArray = ImageType->getOperand(4).getImm() != 0;
6102 unsigned NumComponents = 0;
6103 switch (Dim) {
6104 case SPIRV::Dim::DIM_1D:
6105 case SPIRV::Dim::DIM_Buffer:
6106 NumComponents = IsArray ? 2 : 1;
6107 break;
6108 case SPIRV::Dim::DIM_2D:
6109 case SPIRV::Dim::DIM_Cube:
6110 case SPIRV::Dim::DIM_Rect:
6111 NumComponents = IsArray ? 3 : 2;
6112 break;
6113 case SPIRV::Dim::DIM_3D:
6114 NumComponents = 3;
6115 break;
6116 default:
6117 I.emitGenericError("Unsupported image dimension for OpImageQuerySize.");
6118 return false;
6119 }
6120
6121 SPIRVTypeInst I32Ty = GR.getOrCreateSPIRVIntegerType(32, I, TII);
6122 SPIRVTypeInst ResType =
6123 NumComponents == 1
6124 ? I32Ty
6125 : GR.getOrCreateSPIRVVectorType(I32Ty, NumComponents, I, TII);
6126
6127 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
6128 .addDef(ResVReg)
6129 .addUse(GR.getSPIRVTypeID(ResType))
6130 .addUse(ImageReg);
6131 if (LodReg)
6132 MIB.addUse(*LodReg);
6133 MIB.constrainAllUses(TII, TRI, RBI);
6134 return true;
6135}
6136
6137bool SPIRVInstructionSelector::selectGetDimensionsIntrinsic(
6138 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6139 Register ImageReg = I.getOperand(2).getReg();
6140 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
6141 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
6142 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
6143 *ImageDef, I)) {
6144 return false;
6145 }
6146 return selectImageQuerySize(NewImageReg, ResVReg, I);
6147}
6148
6149bool SPIRVInstructionSelector::selectGetDimensionsLevelsIntrinsic(
6150 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6151 Register ImageReg = I.getOperand(2).getReg();
6152 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
6153 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
6154 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
6155 *ImageDef, I)) {
6156 return false;
6157 }
6158
6159 Register SizeReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
6160 Register LodReg = I.getOperand(3).getReg();
6161
6162 assert(GR.getSPIRVTypeForVReg(NewImageReg)->getOperand(6).getImm() == 1 &&
6163 "OpImageQuerySizeLod and OpImageQueryLevels require a sampled image");
6164
6165 if (!selectImageQuerySize(NewImageReg, SizeReg, I, LodReg)) {
6166 return false;
6167 }
6168
6169 SPIRVTypeInst I32Ty = GR.getOrCreateSPIRVIntegerType(32, I, TII);
6170 Register LevelsReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
6171 BuildMI(*I.getParent(), I, I.getDebugLoc(),
6172 TII.get(SPIRV::OpImageQueryLevels))
6173 .addDef(LevelsReg)
6174 .addUse(GR.getSPIRVTypeID(I32Ty))
6175 .addUse(NewImageReg)
6176 .constrainAllUses(TII, TRI, RBI);
6177
6178 BuildMI(*I.getParent(), I, I.getDebugLoc(),
6179 TII.get(SPIRV::OpCompositeConstruct))
6180 .addDef(ResVReg)
6181 .addUse(GR.getSPIRVTypeID(ResType))
6182 .addUse(SizeReg)
6183 .addUse(LevelsReg)
6184 .constrainAllUses(TII, TRI, RBI);
6185
6186 return true;
6187}
6188
6189bool SPIRVInstructionSelector::selectGetDimensionsMSIntrinsic(
6190 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6191 Register ImageReg = I.getOperand(2).getReg();
6192 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
6193 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
6194 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
6195 *ImageDef, I)) {
6196 return false;
6197 }
6198
6199 Register SizeReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
6200
6201 assert(GR.getSPIRVTypeForVReg(NewImageReg)->getOperand(5).getImm() == 1 &&
6202 "OpImageQuerySamples requires a multisampled image");
6203
6204 if (!selectImageQuerySize(NewImageReg, SizeReg, I)) {
6205 return false;
6206 }
6207
6208 Register SamplesReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
6209
6210 SPIRVTypeInst I32Ty = GR.getOrCreateSPIRVIntegerType(32, I, TII);
6211 BuildMI(*I.getParent(), I, I.getDebugLoc(),
6212 TII.get(SPIRV::OpImageQuerySamples))
6213 .addDef(SamplesReg)
6214 .addUse(GR.getSPIRVTypeID(I32Ty))
6215 .addUse(NewImageReg)
6216 .constrainAllUses(TII, TRI, RBI);
6217
6218 BuildMI(*I.getParent(), I, I.getDebugLoc(),
6219 TII.get(SPIRV::OpCompositeConstruct))
6220 .addDef(ResVReg)
6221 .addUse(GR.getSPIRVTypeID(ResType))
6222 .addUse(SizeReg)
6223 .addUse(SamplesReg)
6224 .constrainAllUses(TII, TRI, RBI);
6225
6226 return true;
6227}
6228
6229bool SPIRVInstructionSelector::selectCalculateLodIntrinsic(
6230 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6231 Register ImageReg = I.getOperand(2).getReg();
6232 Register SamplerReg = I.getOperand(3).getReg();
6233 Register CoordinateReg = I.getOperand(4).getReg();
6234
6235 auto *ImageDef = dyn_cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
6236 if (!ImageDef)
6237 return false;
6238 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
6239 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
6240 *ImageDef, I)) {
6241 return false;
6242 }
6243
6244 auto *SamplerDef = dyn_cast<GIntrinsic>(getVRegDef(*MRI, SamplerReg));
6245 if (!SamplerDef)
6246 return false;
6247 Register NewSamplerReg =
6248 MRI->createVirtualRegister(MRI->getRegClass(SamplerReg));
6249 if (!loadHandleBeforePosition(
6250 NewSamplerReg, GR.getSPIRVTypeForVReg(SamplerReg), *SamplerDef, I)) {
6251 return false;
6252 }
6253
6254 MachineIRBuilder MIRBuilder(I);
6255 SPIRVTypeInst SampledImageType = GR.getOrCreateOpTypeSampledImage(
6256 GR.getSPIRVTypeForVReg(ImageReg), MIRBuilder);
6257 Register SampledImageReg =
6258 MRI->createVirtualRegister(GR.getRegClass(SampledImageType));
6259
6260 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpSampledImage))
6261 .addDef(SampledImageReg)
6262 .addUse(GR.getSPIRVTypeID(SampledImageType))
6263 .addUse(NewImageReg)
6264 .addUse(NewSamplerReg)
6265 .constrainAllUses(TII, TRI, RBI);
6266
6267 SPIRVTypeInst Vec2Ty = GR.getOrCreateSPIRVVectorType(ResType, 2, I, TII);
6268 Register QueryResultReg = MRI->createVirtualRegister(GR.getRegClass(Vec2Ty));
6269
6270 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpImageQueryLod))
6271 .addDef(QueryResultReg)
6272 .addUse(GR.getSPIRVTypeID(Vec2Ty))
6273 .addUse(SampledImageReg)
6274 .addUse(CoordinateReg)
6275 .constrainAllUses(TII, TRI, RBI);
6276
6277 unsigned ExtractedIndex =
6278 cast<GIntrinsic>(I).getIntrinsicID() ==
6279 Intrinsic::spv_resource_calculate_lod_unclamped
6280 ? 1
6281 : 0;
6282
6283 MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
6284 TII.get(SPIRV::OpCompositeExtract))
6285 .addDef(ResVReg)
6286 .addUse(GR.getSPIRVTypeID(ResType))
6287 .addUse(QueryResultReg)
6288 .addImm(ExtractedIndex);
6289
6290 MIB.constrainAllUses(TII, TRI, RBI);
6291 return true;
6292}
6293
6294bool SPIRVInstructionSelector::selectSampleBasicIntrinsic(
6295 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6296 Register ImageReg = I.getOperand(2).getReg();
6297 Register SamplerReg = I.getOperand(3).getReg();
6298 Register CoordinateReg = I.getOperand(4).getReg();
6299 ImageOperands ImOps;
6300 if (I.getNumOperands() > 5)
6301 ImOps.Offset = I.getOperand(5).getReg();
6302 if (I.getNumOperands() > 6)
6303 ImOps.MinLod = I.getOperand(6).getReg();
6304 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6305 CoordinateReg, ImOps, I.getDebugLoc(), I);
6306}
6307
6308bool SPIRVInstructionSelector::selectSampleBiasIntrinsic(
6309 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6310 Register ImageReg = I.getOperand(2).getReg();
6311 Register SamplerReg = I.getOperand(3).getReg();
6312 Register CoordinateReg = I.getOperand(4).getReg();
6313 ImageOperands ImOps;
6314 ImOps.Bias = I.getOperand(5).getReg();
6315 if (I.getNumOperands() > 6)
6316 ImOps.Offset = I.getOperand(6).getReg();
6317 if (I.getNumOperands() > 7)
6318 ImOps.MinLod = I.getOperand(7).getReg();
6319 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6320 CoordinateReg, ImOps, I.getDebugLoc(), I);
6321}
6322
6323bool SPIRVInstructionSelector::selectSampleGradIntrinsic(
6324 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6325 Register ImageReg = I.getOperand(2).getReg();
6326 Register SamplerReg = I.getOperand(3).getReg();
6327 Register CoordinateReg = I.getOperand(4).getReg();
6328 ImageOperands ImOps;
6329 ImOps.GradX = I.getOperand(5).getReg();
6330 ImOps.GradY = I.getOperand(6).getReg();
6331 if (I.getNumOperands() > 7)
6332 ImOps.Offset = I.getOperand(7).getReg();
6333 if (I.getNumOperands() > 8)
6334 ImOps.MinLod = I.getOperand(8).getReg();
6335 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6336 CoordinateReg, ImOps, I.getDebugLoc(), I);
6337}
6338
6339bool SPIRVInstructionSelector::selectSampleLevelIntrinsic(
6340 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6341 Register ImageReg = I.getOperand(2).getReg();
6342 Register SamplerReg = I.getOperand(3).getReg();
6343 Register CoordinateReg = I.getOperand(4).getReg();
6344 ImageOperands ImOps;
6345 ImOps.Lod = I.getOperand(5).getReg();
6346 if (I.getNumOperands() > 6)
6347 ImOps.Offset = I.getOperand(6).getReg();
6348 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6349 CoordinateReg, ImOps, I.getDebugLoc(), I);
6350}
6351
6352bool SPIRVInstructionSelector::selectSampleCmpIntrinsic(Register &ResVReg,
6353 SPIRVTypeInst ResType,
6354 MachineInstr &I) const {
6355 Register ImageReg = I.getOperand(2).getReg();
6356 Register SamplerReg = I.getOperand(3).getReg();
6357 Register CoordinateReg = I.getOperand(4).getReg();
6358 ImageOperands ImOps;
6359 ImOps.Compare = I.getOperand(5).getReg();
6360 if (I.getNumOperands() > 6)
6361 ImOps.Offset = I.getOperand(6).getReg();
6362 if (I.getNumOperands() > 7)
6363 ImOps.MinLod = I.getOperand(7).getReg();
6364 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6365 CoordinateReg, ImOps, I.getDebugLoc(), I);
6366}
6367
6368bool SPIRVInstructionSelector::selectLoadLevelIntrinsic(Register &ResVReg,
6369 SPIRVTypeInst ResType,
6370 MachineInstr &I) const {
6371 Register ImageReg = I.getOperand(2).getReg();
6372 Register CoordinateReg = I.getOperand(3).getReg();
6373 Register LodReg = I.getOperand(4).getReg();
6374
6375 ImageOperands ImOps;
6376 ImOps.Lod = LodReg;
6377 if (I.getNumOperands() > 5)
6378 ImOps.Offset = I.getOperand(5).getReg();
6379
6380 auto *ImageDef = dyn_cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
6381 if (!ImageDef)
6382 return false;
6383
6384 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
6385 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
6386 *ImageDef, I)) {
6387 return false;
6388 }
6389
6390 return generateImageReadOrFetch(ResVReg, ResType, NewImageReg, CoordinateReg,
6391 I.getDebugLoc(), I, &ImOps);
6392}
6393
6394bool SPIRVInstructionSelector::selectSampleCmpLevelZeroIntrinsic(
6395 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6396 Register ImageReg = I.getOperand(2).getReg();
6397 Register SamplerReg = I.getOperand(3).getReg();
6398 Register CoordinateReg = I.getOperand(4).getReg();
6399 ImageOperands ImOps;
6400 ImOps.Compare = I.getOperand(5).getReg();
6401 if (I.getNumOperands() > 6)
6402 ImOps.Offset = I.getOperand(6).getReg();
6403 SPIRVTypeInst FloatTy = GR.getOrCreateSPIRVFloatType(32, I, TII);
6404 ImOps.Lod = GR.getOrCreateConstFP(APFloat(0.0f), I, FloatTy, TII);
6405 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
6406 CoordinateReg, ImOps, I.getDebugLoc(), I);
6407}
6408
6409bool SPIRVInstructionSelector::selectGatherIntrinsic(Register &ResVReg,
6410 SPIRVTypeInst ResType,
6411 MachineInstr &I) const {
6412 Register ImageReg = I.getOperand(2).getReg();
6413 Register SamplerReg = I.getOperand(3).getReg();
6414 Register CoordinateReg = I.getOperand(4).getReg();
6415 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(ImageReg);
6416 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
6417 "ImageReg is not an image type.");
6418
6419 Register ComponentOrCompareReg;
6420 Register OffsetReg;
6421
6422 ComponentOrCompareReg = I.getOperand(5).getReg();
6423 OffsetReg = I.getOperand(6).getReg();
6424 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
6425 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
6426 if (!loadHandleBeforePosition(NewImageReg, ImageType, *ImageDef, I)) {
6427 return false;
6428 }
6429
6430 auto Dim = static_cast<SPIRV::Dim::Dim>(ImageType->getOperand(2).getImm());
6431 if (Dim != SPIRV::Dim::DIM_2D && Dim != SPIRV::Dim::DIM_Cube &&
6432 Dim != SPIRV::Dim::DIM_Rect) {
6433 I.emitGenericError(
6434 "Gather operations are only supported for 2D, Cube, and Rect images.");
6435 return false;
6436 }
6437
6438 auto *SamplerDef = cast<GIntrinsic>(getVRegDef(*MRI, SamplerReg));
6439 Register NewSamplerReg =
6440 MRI->createVirtualRegister(MRI->getRegClass(SamplerReg));
6441 if (!loadHandleBeforePosition(
6442 NewSamplerReg, GR.getSPIRVTypeForVReg(SamplerReg), *SamplerDef, I)) {
6443 return false;
6444 }
6445
6446 MachineIRBuilder MIRBuilder(I);
6447 SPIRVTypeInst SampledImageType =
6448 GR.getOrCreateOpTypeSampledImage(ImageType, MIRBuilder);
6449 Register SampledImageReg =
6450 MRI->createVirtualRegister(GR.getRegClass(SampledImageType));
6451
6452 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpSampledImage))
6453 .addDef(SampledImageReg)
6454 .addUse(GR.getSPIRVTypeID(SampledImageType))
6455 .addUse(NewImageReg)
6456 .addUse(NewSamplerReg)
6457 .constrainAllUses(TII, TRI, RBI);
6458
6459 auto IntrId = cast<GIntrinsic>(I).getIntrinsicID();
6460 bool IsGatherCmp = IntrId == Intrinsic::spv_resource_gather_cmp;
6461 unsigned Opcode =
6462 IsGatherCmp ? SPIRV::OpImageDrefGather : SPIRV::OpImageGather;
6463
6464 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
6465 .addDef(ResVReg)
6466 .addUse(GR.getSPIRVTypeID(ResType))
6467 .addUse(SampledImageReg)
6468 .addUse(CoordinateReg)
6469 .addUse(ComponentOrCompareReg);
6470
6471 uint32_t ImageOperands = 0;
6472 if (OffsetReg && !isScalarOrVectorIntConstantZero(OffsetReg)) {
6473 if (Dim == SPIRV::Dim::DIM_Cube) {
6474 I.emitGenericError(
6475 "Gather operations with offset are not supported for Cube images.");
6476 return false;
6477 }
6478 if (isConstReg(MRI, OffsetReg))
6479 ImageOperands |= SPIRV::ImageOperand::ConstOffset;
6480 else {
6481 ImageOperands |= SPIRV::ImageOperand::Offset;
6482 }
6483 }
6484
6485 if (ImageOperands != 0) {
6486 MIB.addImm(ImageOperands);
6487 if (ImageOperands &
6488 (SPIRV::ImageOperand::ConstOffset | SPIRV::ImageOperand::Offset))
6489 MIB.addUse(OffsetReg);
6490 }
6491
6492 MIB.constrainAllUses(TII, TRI, RBI);
6493 return true;
6494}
6495
6496bool SPIRVInstructionSelector::generateImageReadOrFetch(
6497 Register &ResVReg, SPIRVTypeInst ResType, Register ImageReg,
6498 Register IdxReg, DebugLoc Loc, MachineInstr &Pos,
6499 const ImageOperands *ImOps) const {
6500 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(ImageReg);
6501 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
6502 "ImageReg is not an image type.");
6503
6504 bool IsSignedInteger =
6505 sampledTypeIsSignedInteger(GR.getTypeForSPIRVType(ImageType));
6506 // Check if the "sampled" operand of the image type is 1.
6507 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpImageFetch
6508 auto SampledOp = ImageType->getOperand(6);
6509 bool IsFetch = (SampledOp.getImm() == 1);
6510
6511 auto AddOperands = [&](MachineInstrBuilder &MIB) {
6512 uint32_t ImageOperandsMask = 0;
6513 if (IsSignedInteger)
6514 ImageOperandsMask |= 0x1000; // SignExtend
6515
6516 if (IsFetch && ImOps) {
6517 if (ImOps->Lod)
6518 ImageOperandsMask |= SPIRV::ImageOperand::Lod;
6519 if (ImOps->Offset && !isScalarOrVectorIntConstantZero(*ImOps->Offset)) {
6520 if (isConstReg(MRI, *ImOps->Offset))
6521 ImageOperandsMask |= SPIRV::ImageOperand::ConstOffset;
6522 else
6523 ImageOperandsMask |= SPIRV::ImageOperand::Offset;
6524 }
6525 }
6526
6527 if (ImageOperandsMask != 0) {
6528 MIB.addImm(ImageOperandsMask);
6529 if (IsFetch && ImOps) {
6530 if (ImOps->Lod)
6531 MIB.addUse(*ImOps->Lod);
6532 if (ImOps->Offset &&
6533 (ImageOperandsMask &
6534 (SPIRV::ImageOperand::Offset | SPIRV::ImageOperand::ConstOffset)))
6535 MIB.addUse(*ImOps->Offset);
6536 }
6537 }
6538 };
6539
6540 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
6541
6542 // A wide element (e.g. int64_t2) is emulated with a narrower packed image, so
6543 // its sampled type is different from the result.
6544 SPIRVTypeInst SampledType =
6545 GR.getSPIRVTypeForVReg(ImageType->getOperand(1).getReg());
6546 bool IsPacked = SampledType != GR.getScalarOrVectorComponentType(ResType);
6547 SPIRVTypeInst ReadType =
6548 widenTypeToVec4(IsPacked ? SampledType : ResType, Pos);
6549 bool ReadTypeMatchesResult = ReadType == ResType;
6550 // Read directly into the result, or into a temporary to bitcast/extract.
6551 Register ReadReg = ReadTypeMatchesResult
6552 ? ResVReg
6553 : MRI->createVirtualRegister(GR.getRegClass(ReadType));
6554
6555 auto BMI =
6556 BuildMI(*Pos.getParent(), Pos, Loc,
6557 TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
6558 .addDef(ReadReg)
6559 .addUse(GR.getSPIRVTypeID(ReadType))
6560 .addUse(ImageReg)
6561 .addUse(IdxReg);
6562 AddOperands(BMI);
6563 BMI.constrainAllUses(TII, TRI, RBI);
6564
6565 if (ReadTypeMatchesResult)
6566 return true;
6567
6568 if (IsPacked) {
6569 // Reinterpret the packed vector as the wide result type.
6570 BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpBitcast))
6571 .addDef(ResVReg)
6572 .addUse(GR.getSPIRVTypeID(ResType))
6573 .addUse(ReadReg)
6574 .constrainAllUses(TII, TRI, RBI);
6575 return true;
6576 }
6577
6578 if (ResultSize == 1) {
6579 BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpCompositeExtract))
6580 .addDef(ResVReg)
6581 .addUse(GR.getSPIRVTypeID(ResType))
6582 .addUse(ReadReg)
6583 .addImm(0)
6584 .constrainAllUses(TII, TRI, RBI);
6585 return true;
6586 }
6587 return extractSubvector(ResVReg, ResType, ReadReg, Pos);
6588}
6589
6590bool SPIRVInstructionSelector::selectResourceGetPointer(Register &ResVReg,
6591 SPIRVTypeInst ResType,
6592 MachineInstr &I) const {
6593 Register ResourcePtr = I.getOperand(2).getReg();
6594 SPIRVTypeInst RegType = GR.getSPIRVTypeForVReg(ResourcePtr, I.getMF());
6595 if (RegType->getOpcode() == SPIRV::OpTypeImage) {
6596 // For texel buffers, the index into the image is part of the OpImageRead or
6597 // OpImageWrite instructions. So we will do nothing in this case. This
6598 // intrinsic will be combined with the load or store when selecting the load
6599 // or store.
6600 return true;
6601 }
6602
6603 assert(ResType->getOpcode() == SPIRV::OpTypePointer);
6604 MachineIRBuilder MIRBuilder(I);
6605
6606 Register ZeroReg =
6607 buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I);
6608 auto MIB =
6609 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain))
6610 .addDef(ResVReg)
6611 .addUse(GR.getSPIRVTypeID(ResType))
6612 .addUse(ResourcePtr)
6613 .addUse(ZeroReg);
6614
6615 if (I.getNumExplicitOperands() > 3) {
6616 Register IndexReg = I.getOperand(3).getReg();
6617 MIB.addUse(IndexReg);
6618 }
6619 MIB.constrainAllUses(TII, TRI, RBI);
6620 return true;
6621}
6622
6623bool SPIRVInstructionSelector::selectPushConstantGetPointer(
6624 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6625 MRI->replaceRegWith(ResVReg, I.getOperand(2).getReg());
6626 return true;
6627}
6628
6629bool SPIRVInstructionSelector::selectResourceNonUniformIndex(
6630 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
6631 Register ObjReg = I.getOperand(2).getReg();
6632 if (!BuildCOPY(ResVReg, ObjReg, I))
6633 return false;
6634
6635 buildOpDecorate(ResVReg, I, TII, SPIRV::Decoration::NonUniformEXT, {});
6636 // Check for the registers that use the index marked as non-uniform
6637 // and recursively mark them as non-uniform.
6638 // Per the spec, it's necessary that the final argument used for
6639 // load/store/sample/atomic must be decorated, so we need to propagate the
6640 // decoration through access chains and copies.
6641 // https://docs.vulkan.org/samples/latest/samples/extensions/descriptor_indexing/README.html#_when_to_use_non_uniform_indexing_qualifier
6642 decorateUsesAsNonUniform(ResVReg);
6643 return true;
6644}
6645
6646void SPIRVInstructionSelector::decorateUsesAsNonUniform(
6647 Register &NonUniformReg) const {
6649 {NonUniformReg, nullptr}};
6650 llvm::SmallSet<Register, 8> Visited;
6651 while (WorkList.size() > 0) {
6652 auto [CurrentReg, DefMI] = WorkList.pop_back_val();
6653
6654 if (!Visited.insert(CurrentReg).second)
6655 continue;
6656
6657 bool IsDecorated = false;
6658 for (MachineInstr &Use : MRI->use_instructions(CurrentReg)) {
6659 if (Use.getOpcode() == SPIRV::OpDecorate &&
6660 Use.getOperand(1).getImm() == SPIRV::Decoration::NonUniformEXT) {
6661 IsDecorated = true;
6662 continue;
6663 }
6664 // Check if the instruction has the result register and add it to the
6665 // worklist.
6666 if (Use.getOperand(0).isReg() && Use.getOperand(0).isDef()) {
6667 Register ResultReg = Use.getOperand(0).getReg();
6668 if (ResultReg == CurrentReg)
6669 continue;
6670 WorkList.push_back({ResultReg, &Use});
6671 }
6672 }
6673
6674 if (!IsDecorated) {
6675 MachineBasicBlock &MBB = *DefMI->getParent();
6676 MachineInstr &InsertPt =
6678 buildOpDecorate(CurrentReg, InsertPt, TII,
6679 SPIRV::Decoration::NonUniformEXT, {});
6680 }
6681 }
6682}
6683
6684bool SPIRVInstructionSelector::extractSubvector(
6685 Register &ResVReg, SPIRVTypeInst ResType, Register &ReadReg,
6686 MachineInstr &InsertionPoint) const {
6687 SPIRVTypeInst InputType = GR.getResultType(ReadReg);
6688 [[maybe_unused]] uint64_t InputSize =
6689 GR.getScalarOrVectorComponentCount(InputType);
6690 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
6691 [[maybe_unused]] bool IsLongVectorEXT =
6692 STI.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
6693 assert((InputSize > 1 || IsLongVectorEXT) && "The input must be a vector.");
6694 assert((ResultSize > 1 || IsLongVectorEXT) && "The result must be a vector.");
6695 assert(ResultSize < InputSize &&
6696 "Cannot extract more element than there are in the input.");
6697 SmallVector<Register> ComponentRegisters;
6698 SPIRVTypeInst ScalarType = GR.getScalarOrVectorComponentType(ResType);
6699 const TargetRegisterClass *ScalarRegClass = GR.getRegClass(ScalarType);
6700 for (uint64_t I = 0; I < ResultSize; I++) {
6701 Register ComponentReg = MRI->createVirtualRegister(ScalarRegClass);
6702 BuildMI(*InsertionPoint.getParent(), InsertionPoint,
6703 InsertionPoint.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
6704 .addDef(ComponentReg)
6705 .addUse(ScalarType->getOperand(0).getReg())
6706 .addUse(ReadReg)
6707 .addImm(I)
6708 .constrainAllUses(TII, TRI, RBI);
6709 ComponentRegisters.emplace_back(ComponentReg);
6710 }
6711
6712 MachineInstrBuilder MIB = BuildMI(*InsertionPoint.getParent(), InsertionPoint,
6713 InsertionPoint.getDebugLoc(),
6714 TII.get(SPIRV::OpCompositeConstruct))
6715 .addDef(ResVReg)
6716 .addUse(GR.getSPIRVTypeID(ResType));
6717
6718 for (Register ComponentReg : ComponentRegisters)
6719 MIB.addUse(ComponentReg);
6720 MIB.constrainAllUses(TII, TRI, RBI);
6721 return true;
6722}
6723
6724bool SPIRVInstructionSelector::selectImageWriteIntrinsic(
6725 MachineInstr &I) const {
6726 // If the load of the image is in a different basic block, then
6727 // this will generate invalid code. A proper solution is to move
6728 // the OpLoad from selectHandleFromBinding here. However, to do
6729 // that we will need to change the return type of the intrinsic.
6730 // We will do that when we can, but for now trying to move forward with other
6731 // issues.
6732 Register ImageReg = I.getOperand(1).getReg();
6733 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
6734 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
6735 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
6736 *ImageDef, I)) {
6737 return false;
6738 }
6739
6740 Register CoordinateReg = I.getOperand(2).getReg();
6741 Register DataReg = I.getOperand(3).getReg();
6742 assert(isVectorType(GR.getResultType(DataReg)));
6744 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpImageWrite))
6745 .addUse(NewImageReg)
6746 .addUse(CoordinateReg)
6747 .addUse(DataReg)
6748 .constrainAllUses(TII, TRI, RBI);
6749 return true;
6750}
6751
6752Register SPIRVInstructionSelector::buildPointerToResource(
6753 SPIRVTypeInst SpirvResType, SPIRV::StorageClass::StorageClass SC,
6754 uint32_t Set, uint32_t Binding, uint32_t ArraySize, Register IndexReg,
6755 StringRef Name, MachineIRBuilder MIRBuilder) const {
6756 const Type *ResType = GR.getTypeForSPIRVType(SpirvResType);
6757 if (ArraySize == 1) {
6758 SPIRVTypeInst PtrType =
6759 GR.getOrCreateSPIRVPointerType(ResType, MIRBuilder, SC);
6760 assert(GR.getPointeeType(PtrType) == SpirvResType &&
6761 "SpirvResType did not have an explicit layout.");
6762 return GR.getOrCreateGlobalVariableWithBinding(PtrType, Set, Binding, Name,
6763 MIRBuilder);
6764 }
6765
6766 const Type *VarType = ArrayType::get(const_cast<Type *>(ResType), ArraySize);
6767 SPIRVTypeInst VarPointerType =
6768 GR.getOrCreateSPIRVPointerType(VarType, MIRBuilder, SC);
6770 VarPointerType, Set, Binding, Name, MIRBuilder);
6771
6772 SPIRVTypeInst ResPointerType =
6773 GR.getOrCreateSPIRVPointerType(ResType, MIRBuilder, SC);
6774 Register AcReg = MRI->createVirtualRegister(GR.getRegClass(ResPointerType));
6775
6776 MIRBuilder.buildInstr(SPIRV::OpAccessChain)
6777 .addDef(AcReg)
6778 .addUse(GR.getSPIRVTypeID(ResPointerType))
6779 .addUse(VarReg)
6780 .addUse(IndexReg);
6781
6782 return AcReg;
6783}
6784
6785bool SPIRVInstructionSelector::selectFirstBitSet16(
6786 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
6787 unsigned ExtendOpcode, unsigned BitSetOpcode) const {
6788 Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
6789 if (!selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()},
6790 ExtendOpcode))
6791 return false;
6792
6793 return selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode);
6794}
6795
6796bool SPIRVInstructionSelector::selectFirstBitSet32(
6797 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
6798 unsigned BitSetOpcode) const {
6799 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
6800 .addDef(ResVReg)
6801 .addUse(GR.getSPIRVTypeID(ResType))
6802 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
6803 .addImm(BitSetOpcode)
6804 .addUse(SrcReg)
6805 .constrainAllUses(TII, TRI, RBI);
6806 return true;
6807}
6808
6809bool SPIRVInstructionSelector::selectFirstBitSet64(
6810 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
6811 unsigned BitSetOpcode, bool SwapPrimarySide) const {
6812 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType);
6813 SPIRVTypeInst BaseType = GR.retrieveScalarOrVectorIntType(ResType);
6814 bool ZeroAsNull = !STI.isShader();
6815 Register ConstIntZero =
6816 GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull);
6817 Register ConstIntOne =
6818 GR.getOrCreateConstInt(1, I, BaseType, TII, ZeroAsNull);
6819
6820 // SPIRV doesn't support vectors with more than 4 components. Since the
6821 // algoritm below converts i64 -> i32x2 and i64x4 -> i32x8 it can only
6822 // operate on vectors with 2 or less components. When largers vectors are
6823 // seen. Split them, recurse, then recombine them.
6824 // TODO: handle the case where SPV_EXT_long_vector is enabled.
6825 if (ComponentCount > 2) {
6826 auto Func = [this, SwapPrimarySide](Register ResVReg, SPIRVTypeInst ResType,
6827 MachineInstr &I, Register SrcReg,
6828 unsigned Opcode) -> bool {
6829 return this->selectFirstBitSet64(ResVReg, ResType, I, SrcReg, Opcode,
6830 SwapPrimarySide);
6831 };
6832
6833 return handle64BitOverflow(ResVReg, ResType, I, SrcReg, BitSetOpcode, Func);
6834 }
6835
6836 // 1. Split int64 into 2 pieces using a bitcast
6837 MachineIRBuilder MIRBuilder(I);
6838 SPIRVTypeInst PostCastType = GR.getOrCreateSPIRVVectorType(
6839 BaseType, 2 * ComponentCount, MIRBuilder, false);
6840 Register BitcastReg =
6841 MRI->createVirtualRegister(GR.getRegClass(PostCastType));
6842
6843 if (!selectOpWithSrcs(BitcastReg, PostCastType, I, {SrcReg},
6844 SPIRV::OpBitcast))
6845 return false;
6846
6847 // 2. Find the first set bit from the primary side for all the pieces in #1
6848 Register FBSReg = MRI->createVirtualRegister(GR.getRegClass(PostCastType));
6849 if (!selectFirstBitSet32(FBSReg, PostCastType, I, BitcastReg, BitSetOpcode))
6850 return false;
6851
6852 // 3. Split result vector into high bits and low bits
6853 Register HighReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
6854 Register LowReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
6855
6856 bool IsScalarRes = !isVectorType(ResType);
6857 if (IsScalarRes) {
6858 // if scalar do a vector extract
6859 if (!selectOpWithSrcs(HighReg, ResType, I, {FBSReg, ConstIntOne},
6860 SPIRV::OpVectorExtractDynamic))
6861 return false;
6862 if (!selectOpWithSrcs(LowReg, ResType, I, {FBSReg, ConstIntZero},
6863 SPIRV::OpVectorExtractDynamic))
6864 return false;
6865 } else {
6866 // if vector do a shufflevector
6867 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
6868 TII.get(SPIRV::OpVectorShuffle))
6869 .addDef(HighReg)
6870 .addUse(GR.getSPIRVTypeID(ResType))
6871 .addUse(FBSReg)
6872 // Per the spec, repeat the vector if only one vec is needed
6873 .addUse(FBSReg);
6874
6875 // high bits are stored in even natural indexes. Extract them from FBSReg
6876 for (unsigned J = 1; J < ComponentCount * 2; J += 2) {
6877 MIB.addImm(J);
6878 }
6879
6880 MIB.constrainAllUses(TII, TRI, RBI);
6881
6882 MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
6883 TII.get(SPIRV::OpVectorShuffle))
6884 .addDef(LowReg)
6885 .addUse(GR.getSPIRVTypeID(ResType))
6886 .addUse(FBSReg)
6887 // Per the spec, repeat the vector if only one vec is needed
6888 .addUse(FBSReg);
6889
6890 // low bits are stored in odd natural indices. Extract them from FBSReg
6891 for (unsigned J = 0; J < ComponentCount * 2; J += 2) {
6892 MIB.addImm(J);
6893 }
6894 MIB.constrainAllUses(TII, TRI, RBI);
6895 }
6896
6897 // 4. Check the result. When primary bits == -1 use secondary, otherwise use
6898 // primary
6899 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
6900 Register NegOneReg;
6901 Register Reg0;
6902 Register Reg32;
6903 unsigned SelectOp;
6904 unsigned AddOp;
6905
6906 if (IsScalarRes) {
6907 NegOneReg =
6908 GR.getOrCreateConstInt((unsigned)-1, I, ResType, TII, ZeroAsNull);
6909 Reg0 = GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
6910 Reg32 = GR.getOrCreateConstInt(32, I, ResType, TII, ZeroAsNull);
6911 SelectOp = SPIRV::OpSelectSISCond;
6912 AddOp = SPIRV::OpIAddS;
6913 } else {
6914 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, ComponentCount,
6915 MIRBuilder, false);
6916 NegOneReg =
6917 GR.getOrCreateConstVector((unsigned)-1, I, ResType, TII, ZeroAsNull);
6918 Reg0 = GR.getOrCreateConstVector(0, I, ResType, TII, ZeroAsNull);
6919 Reg32 = GR.getOrCreateConstVector(32, I, ResType, TII, ZeroAsNull);
6920 SelectOp = SPIRV::OpSelectVIVCond;
6921 AddOp = SPIRV::OpIAddV;
6922 }
6923
6924 Register PrimaryReg = HighReg;
6925 Register SecondaryReg = LowReg;
6926 Register RegPrimaryOffset = Reg32;
6927 Register RegSecondaryOffset = Reg0;
6928
6929 // By default the emitted opcodes check for the set bit from the MSB side.
6930 // Setting SwapPrimarySide checks the set bit from the LSB side
6931 if (SwapPrimarySide) {
6932 PrimaryReg = LowReg;
6933 SecondaryReg = HighReg;
6934 RegPrimaryOffset = Reg0;
6935 RegSecondaryOffset = Reg32;
6936 }
6937
6938 Register RegSecondaryHasVal =
6939 MRI->createVirtualRegister(GR.getRegClass(BoolType));
6940 if (!selectOpWithSrcs(RegSecondaryHasVal, BoolType, I,
6941 {SecondaryReg, NegOneReg}, SPIRV::OpINotEqual))
6942 return false;
6943
6944 Register RegPrimaryHasVal =
6945 MRI->createVirtualRegister(GR.getRegClass(BoolType));
6946 if (!selectOpWithSrcs(RegPrimaryHasVal, BoolType, I, {PrimaryReg, NegOneReg},
6947 SPIRV::OpINotEqual))
6948 return false;
6949
6950 // Pass 1: seed with secondary (lower-priority fallback)
6951 // ReturnBits = secondaryHasVal ? SecondaryBits : -1
6952 // Add = secondaryHasVal ? SecondaryOffset : 0
6953 Register RegReturnBits = MRI->createVirtualRegister(GR.getRegClass(ResType));
6954 if (!selectOpWithSrcs(RegReturnBits, ResType, I,
6955 {RegSecondaryHasVal, SecondaryReg, NegOneReg},
6956 SelectOp))
6957 return false;
6958
6959 Register RegAdd;
6960 if (SwapPrimarySide) {
6961 RegAdd = MRI->createVirtualRegister(GR.getRegClass(ResType));
6962 if (!selectOpWithSrcs(RegAdd, ResType, I,
6963 {RegSecondaryHasVal, RegSecondaryOffset, Reg0},
6964 SelectOp))
6965 return false;
6966 } else {
6967 RegAdd = Reg0;
6968 }
6969
6970 // Pass 2: override with primary (higher priority) if it has a valid result
6971 // ReturnBits2 = primaryHasVal ? PrimaryBits : ReturnBits
6972 // Add2 = primaryHasVal ? PrimaryOffset : Add
6973 Register RegReturnBits2 = MRI->createVirtualRegister(GR.getRegClass(ResType));
6974 if (!selectOpWithSrcs(RegReturnBits2, ResType, I,
6975 {RegPrimaryHasVal, PrimaryReg, RegReturnBits},
6976 SelectOp))
6977 return false;
6978
6979 Register RegAdd2 = MRI->createVirtualRegister(GR.getRegClass(ResType));
6980 if (!selectOpWithSrcs(RegAdd2, ResType, I,
6981 {RegPrimaryHasVal, RegPrimaryOffset, RegAdd}, SelectOp))
6982 return false;
6983
6984 return selectOpWithSrcs(ResVReg, ResType, I, {RegReturnBits2, RegAdd2},
6985 AddOp);
6986}
6987
6988bool SPIRVInstructionSelector::selectFirstBitHigh(Register ResVReg,
6989 SPIRVTypeInst ResType,
6990 MachineInstr &I,
6991 bool IsSigned) const {
6992 // FindUMsb and FindSMsb intrinsics only support 32 bit integers
6993 Register OpReg = I.getOperand(2).getReg();
6994 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
6995 // zero or sign extend
6996 unsigned ExtendOpcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
6997 unsigned BitSetOpcode = IsSigned ? GL::FindSMsb : GL::FindUMsb;
6998
6999 switch (GR.getScalarOrVectorBitWidth(OpType)) {
7000 case 16:
7001 return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode);
7002 case 32:
7003 return selectFirstBitSet32(ResVReg, ResType, I, OpReg, BitSetOpcode);
7004 case 64:
7005 return selectFirstBitSet64(ResVReg, ResType, I, OpReg, BitSetOpcode,
7006 /*SwapPrimarySide=*/false);
7007 default:
7008 return diagnoseUnsupported(
7009 I,
7010 "spv_firstbituhigh and spv_firstbitshigh only support 16,32,64 bits.");
7011 }
7012}
7013
7014bool SPIRVInstructionSelector::selectFirstBitLow(Register ResVReg,
7015 SPIRVTypeInst ResType,
7016 MachineInstr &I) const {
7017 // FindILsb intrinsic only supports 32 bit integers
7018 Register OpReg = I.getOperand(2).getReg();
7019 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
7020 // OpUConvert treats the operand bits as an unsigned i16 and zero extends it
7021 // to an unsigned i32. As this leaves all the least significant bits unchanged
7022 // so the first set bit from the LSB side doesn't change.
7023 unsigned ExtendOpcode = SPIRV::OpUConvert;
7024 unsigned BitSetOpcode = GL::FindILsb;
7025
7026 switch (GR.getScalarOrVectorBitWidth(OpType)) {
7027 case 16:
7028 return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode);
7029 case 32:
7030 return selectFirstBitSet32(ResVReg, ResType, I, OpReg, BitSetOpcode);
7031 case 64:
7032 return selectFirstBitSet64(ResVReg, ResType, I, OpReg, BitSetOpcode,
7033 /*SwapPrimarySide=*/true);
7034 default:
7035 return diagnoseUnsupported(I,
7036 "spv_firstbitlow only supports 16,32,64 bits.");
7037 }
7038}
7039
7040bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg,
7041 SPIRVTypeInst ResType,
7042 MachineInstr &I) const {
7043 // there was an allocation size parameter to the allocation instruction
7044 // that is not 1
7045 MachineBasicBlock &BB = *I.getParent();
7046 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVariableLengthArrayINTEL))
7047 .addDef(ResVReg)
7048 .addUse(GR.getSPIRVTypeID(ResType))
7049 .addUse(I.getOperand(2).getReg())
7050 .constrainAllUses(TII, TRI, RBI);
7051 if (!STI.isShader()) {
7052 unsigned Alignment = I.getOperand(3).getImm();
7053 buildOpDecorate(ResVReg, I, TII, SPIRV::Decoration::Alignment, {Alignment});
7054 }
7055 return true;
7056}
7057
7058// Returns true iff `Ty` is a concrete SPIR-V type per the SPV_KHR_abort
7059// definition: a numerical scalar (int/float), a (physical) pointer, a vector,
7060// matrix or any aggregate (array/struct) recursively containing only such
7061// types. OpTypeBool, OpTypeVoid, opaque handles and similar abstract
7062// non-concrete types are rejected.
7064 const SPIRVGlobalRegistry &GR) {
7065 SmallVector<SPIRVTypeInst, 4> Worklist{Ty};
7066 while (!Worklist.empty()) {
7067 SPIRVTypeInst T = Worklist.pop_back_val();
7068 switch (T->getOpcode()) {
7069 case SPIRV::OpTypeInt:
7070 case SPIRV::OpTypeFloat:
7071 case SPIRV::OpTypePointer:
7072 break;
7073 case SPIRV::OpTypeVector:
7074 case SPIRV::OpTypeVectorIdEXT:
7075 case SPIRV::OpTypeMatrix:
7076 case SPIRV::OpTypeArray: {
7077 Register OperandReg = T->getOperand(1).getReg();
7078 SPIRVTypeInst ElementT = GR.getSPIRVTypeForVReg(OperandReg);
7079 Worklist.push_back(ElementT);
7080 } break;
7081 case SPIRV::OpTypeStruct:
7082 for (unsigned Idx = 1, E = T->getNumOperands(); Idx < E; ++Idx) {
7083 Register OperandReg = T->getOperand(Idx).getReg();
7084 SPIRVTypeInst ElementT = GR.getSPIRVTypeForVReg(OperandReg);
7085 Worklist.push_back(ElementT);
7086 }
7087 break;
7088 default:
7089 return false;
7090 }
7091 }
7092 return true;
7093}
7094
7095bool SPIRVInstructionSelector::selectAbort(MachineInstr &I) const {
7096 assert(I.getNumExplicitOperands() == 2);
7097
7098 Register MsgReg = I.getOperand(1).getReg();
7099 SPIRVTypeInst MsgType = GR.getSPIRVTypeForVReg(MsgReg);
7100 assert(MsgType && "Message argument of llvm.spv.abort has no SPIR-V type");
7101
7102 if (!isConcreteSPIRVType(MsgType, GR))
7103 return diagnoseUnsupported(
7104 I,
7105 "llvm.spv.abort message type must be a concrete SPIR-V type (numerical "
7106 "scalar, pointer, vector, matrix, or aggregate of such types)");
7107
7108 MachineBasicBlock &BB = *I.getParent();
7109 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAbortKHR))
7110 .addUse(GR.getSPIRVTypeID(MsgType))
7111 .addUse(MsgReg)
7112 .constrainAllUses(TII, TRI, RBI);
7113 return true;
7114}
7115
7116bool SPIRVInstructionSelector::selectTrap(MachineInstr &I) const {
7117 // When the SPV_KHR_abort extension is disabled, drop the G_TRAP and
7118 // G_UBSANTRAP silently.
7119 if (!STI.canUseExtension(SPIRV::Extension::SPV_KHR_abort))
7120 return true;
7121
7122 // Use the 32-bit integer constant for the abort "message" argument:
7123 // - G_UBSANTRAP operand is zero-extended to 32 bits.
7124 // - "All ones" constant is used for G_TRAP.
7125 uint32_t MsgVal = ~0u;
7126 if (I.getOpcode() == TargetOpcode::G_UBSANTRAP)
7127 MsgVal = static_cast<uint32_t>(I.getOperand(0).getImm());
7128
7129 SPIRVTypeInst MsgType = GR.getOrCreateSPIRVIntegerType(32, I, TII);
7130 Register MsgReg = buildI32ConstantInEntryBlock(MsgVal, I, MsgType);
7131
7132 MachineBasicBlock &BB = *I.getParent();
7133 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAbortKHR))
7134 .addUse(GR.getSPIRVTypeID(MsgType))
7135 .addUse(MsgReg)
7136 .constrainAllUses(TII, TRI, RBI);
7137 return true;
7138}
7139
7140bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg,
7141 SPIRVTypeInst ResType,
7142 MachineInstr &I) const {
7143 // Change order of instructions if needed: all OpVariable instructions in a
7144 // function must be the first instructions in the first block
7145 auto It = getOpVariableMBBIt(*I.getMF());
7146
7147 // Pointers to opaque types stay typed even with the extension on, so emit the
7148 // untyped variant only when the result is actually an untyped pointer.
7149 bool UseUntypedPointers =
7150 ResType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
7151 unsigned Opcode =
7152 UseUntypedPointers ? SPIRV::OpUntypedVariableKHR : SPIRV::OpVariable;
7153
7154 auto MIB = BuildMI(*It->getParent(), It, It->getDebugLoc(), TII.get(Opcode))
7155 .addDef(ResVReg)
7156 .addUse(GR.getSPIRVTypeID(ResType))
7157 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function));
7158
7159 // OpUntypedVariableKHR takes an extra Data Type operand right after the
7160 // storage class.
7161 if (UseUntypedPointers) {
7162 // Get the element type that was stored when processing spv_assign_ptr_type.
7163 SPIRVTypeInst DataType = GR.getUntypedPtrElementType(ResVReg);
7164 if (!DataType)
7165 return diagnoseUnsupported(
7166 I, "could not deduce the data type of an untyped variable");
7167 MIB.addUse(GR.getSPIRVTypeID(DataType));
7168 }
7169 MIB.constrainAllUses(TII, TRI, RBI);
7170
7171 if (!STI.isShader()) {
7172 unsigned Alignment = I.getOperand(2).getImm();
7173 buildOpDecorate(ResVReg, *It, TII, SPIRV::Decoration::Alignment,
7174 {Alignment});
7175 }
7176 return true;
7177}
7178
7179bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const {
7180 // InstructionSelector walks backwards through the instructions. We can use
7181 // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
7182 // first, so can generate an OpBranchConditional here. If there is no
7183 // G_BRCOND, we just use OpBranch for a regular unconditional branch.
7184 const MachineInstr *PrevI = I.getPrevNode();
7185 MachineBasicBlock &MBB = *I.getParent();
7186 if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) {
7187 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
7188 .addUse(PrevI->getOperand(0).getReg())
7189 .addMBB(PrevI->getOperand(1).getMBB())
7190 .addMBB(I.getOperand(0).getMBB())
7191 .constrainAllUses(TII, TRI, RBI);
7192 return true;
7193 }
7194 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch))
7195 .addMBB(I.getOperand(0).getMBB())
7196 .constrainAllUses(TII, TRI, RBI);
7197 return true;
7198}
7199
7200bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const {
7201 // InstructionSelector walks backwards through the instructions. For an
7202 // explicit conditional branch with no fallthrough, we use both a G_BR and a
7203 // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
7204 // generate the OpBranchConditional in selectBranch above.
7205 //
7206 // If an OpBranchConditional has been generated, we simply return, as the work
7207 // is alread done. If there is no OpBranchConditional, LLVM must be relying on
7208 // implicit fallthrough to the next basic block, so we need to create an
7209 // OpBranchConditional with an explicit "false" argument pointing to the next
7210 // basic block that LLVM would fall through to.
7211 const MachineInstr *NextI = I.getNextNode();
7212 // Check if this has already been successfully selected.
7213 if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional)
7214 return true;
7215 // Must be relying on implicit block fallthrough, so generate an
7216 // OpBranchConditional with the "next" basic block as the "false" target.
7217 MachineBasicBlock &MBB = *I.getParent();
7218 unsigned NextMBBNum = MBB.getNextNode()->getNumber();
7219 MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum);
7220 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
7221 .addUse(I.getOperand(0).getReg())
7222 .addMBB(I.getOperand(1).getMBB())
7223 .addMBB(NextMBB)
7224 .constrainAllUses(TII, TRI, RBI);
7225 return true;
7226}
7227
7228bool SPIRVInstructionSelector::selectPhi(Register ResVReg,
7229 MachineInstr &I) const {
7230 auto MIB =
7231 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::PHI))
7232 .addDef(ResVReg);
7233 const unsigned NumOps = I.getNumOperands();
7234 for (unsigned i = 1; i < NumOps; i += 2) {
7235 MIB.addUse(I.getOperand(i + 0).getReg());
7236 MIB.addMBB(I.getOperand(i + 1).getMBB());
7237 }
7238 MIB.constrainAllUses(TII, TRI, RBI);
7239 return true;
7240}
7241
7242bool SPIRVInstructionSelector::selectGlobalValue(
7243 Register ResVReg, MachineInstr &I, const MachineInstr *Init) const {
7244 // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
7245 MachineIRBuilder MIRBuilder(I);
7246 const GlobalValue *GV = I.getOperand(1).getGlobal();
7248
7249 std::string GlobalIdent;
7250 if (!GV->hasName()) {
7251 unsigned &ID = UnnamedGlobalIDs[GV];
7252 if (ID == 0)
7253 ID = UnnamedGlobalIDs.size();
7254 GlobalIdent = "__unnamed_" + Twine(ID).str();
7255 } else {
7256 GlobalIdent = GV->getName();
7257 }
7258
7259 // Behaviour of functions as operands depends on availability of the
7260 // corresponding extension (SPV_INTEL_function_pointers):
7261 // - If there is an extension to operate with functions as operands:
7262 // We create a proper constant operand and evaluate a correct type for a
7263 // function pointer.
7264 // - Without the required extension:
7265 // We have functions as operands in tests with blocks of instruction e.g. in
7266 // transcoding/global_block.ll. These operands are not used and should be
7267 // substituted by zero constants. Their type is expected to be always
7268 // OpTypePointer Function %uchar.
7269 if (isa<Function>(GV)) {
7270 const Constant *ConstVal = GV;
7271 MachineBasicBlock &BB = *I.getParent();
7272 Register NewReg = GR.find(ConstVal, GR.CurMF);
7273 if (!NewReg.isValid()) {
7274 const Function *GVFun =
7275 STI.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
7276 ? dyn_cast<Function>(GV)
7277 : nullptr;
7278 SPIRVTypeInst ResType = GR.getOrCreateSPIRVPointerType(
7279 GVType, I,
7280 GVFun ? SPIRV::StorageClass::CodeSectionINTEL
7282 if (GVFun) {
7283 // References to a function via function pointers generate virtual
7284 // registers without a definition. We will resolve it later, during
7285 // module analysis stage.
7286 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
7287 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
7288 Register FuncVReg =
7289 MRI->createGenericVirtualRegister(GR.getRegType(ResType));
7290 MRI->setRegClass(FuncVReg, &SPIRV::pIDRegClass);
7291 GR.assignSPIRVTypeToVReg(ResType, FuncVReg, *GR.CurMF);
7292 MachineInstrBuilder MIB1 =
7293 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
7294 .addDef(FuncVReg)
7295 .addUse(ResTypeReg);
7296 MachineInstrBuilder MIB2 =
7297 BuildMI(BB, I, I.getDebugLoc(),
7298 TII.get(SPIRV::OpConstantFunctionPointerINTEL))
7299 .addDef(ResVReg)
7300 .addUse(ResTypeReg)
7301 .addUse(FuncVReg);
7302 GR.add(ConstVal, MIB2);
7303 // mapping the function pointer to the used Function
7304 GR.recordFunctionPointer(&MIB2.getInstr()->getOperand(2), GVFun);
7305 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF);
7306 MIB1.constrainAllUses(TII, TRI, RBI);
7307 MIB2.constrainAllUses(TII, TRI, RBI);
7308 return true;
7309 }
7310 MachineInstrBuilder MIB3 =
7311 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
7312 .addDef(ResVReg)
7313 .addUse(GR.getSPIRVTypeID(ResType));
7314 GR.add(ConstVal, MIB3);
7316 cast<Function>(GV));
7317 MIB3.constrainAllUses(TII, TRI, RBI);
7318 return true;
7319 }
7320 assert(NewReg != ResVReg);
7321 return BuildCOPY(ResVReg, NewReg, I);
7322 }
7324 assert(GlobalVar->getName() != "llvm.global.annotations");
7325
7326 // Skip empty declaration for GVs with initializers till we get the decl with
7327 // passed initializer.
7328 if (hasInitializer(GlobalVar) && !Init)
7329 return true;
7330
7331 const std::optional<SPIRV::LinkageType::LinkageType> LnkType =
7332 getSpirvLinkageTypeFor(STI, *GV);
7333
7334 if (LnkType && *LnkType == SPIRV::LinkageType::Import)
7335 Init = nullptr;
7336
7337 const unsigned AddrSpace = GV->getAddressSpace();
7338 SPIRV::StorageClass::StorageClass StorageClass =
7339 addressSpaceToStorageClass(AddrSpace, STI);
7340 SPIRVTypeInst ResType =
7343 ResVReg, ResType, GlobalIdent, GV, StorageClass, Init,
7344 GlobalVar->isConstant(), LnkType, MIRBuilder, true);
7345 // TODO: For AMDGCN, we pipe externally_initialized through via
7346 // HostAccessINTEL, with ReadWrite (3) access, which is we then handle during
7347 // reverse translation. We should remove this once SPIR-V gains the ability to
7348 // express the concept.
7349 if (GlobalVar->isExternallyInitialized() &&
7350 STI.getTargetTriple().getVendor() == Triple::AMD) {
7351 constexpr unsigned ReadWriteINTEL = 3u;
7352 buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::HostAccessINTEL,
7353 {ReadWriteINTEL});
7354 MachineInstrBuilder MIB(*MF, --MIRBuilder.getInsertPt());
7355 addStringImm(GV->getName(), MIB);
7356 }
7357 return Reg.isValid();
7358}
7359
7360bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
7361 SPIRVTypeInst ResType,
7362 MachineInstr &I) const {
7363 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
7364 return selectExtInst(ResVReg, ResType, I, CL::log10);
7365 }
7366
7367 // There is no log10 instruction in the GLSL Extended Instruction set, so it
7368 // is implemented as:
7369 // log10(x) = log2(x) * (1 / log2(10))
7370 // = log2(x) * 0.30103
7371
7372 MachineIRBuilder MIRBuilder(I);
7373 MachineBasicBlock &BB = *I.getParent();
7374
7375 // Build log2(x).
7376 Register VarReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
7377 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
7378 .addDef(VarReg)
7379 .addUse(GR.getSPIRVTypeID(ResType))
7380 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
7381 .addImm(GL::Log2)
7382 .add(I.getOperand(1))
7383 .constrainAllUses(TII, TRI, RBI);
7384
7385 // Build 0.30103.
7386 assert(isVectorType(ResType) || ResType.isAnyTypeFloat());
7387 // TODO: Add matrix implementation once supported by the HLSL frontend.
7388 SPIRVTypeInst SpirvScalarType = GR.getScalarOrVectorComponentType(ResType);
7389 // The literal must match the precision of the scalar type, otherwise the
7390 // OpConstant will contain non-zero high-order bits and fail SPIR-V
7391 // validation when the type is narrower than 32 bits (e.g. half).
7392 APFloat ScaleVal(0.30103);
7393 bool LosesInfo;
7394 ScaleVal.convert(
7395 getZeroFP(GR.getTypeForSPIRVType(SpirvScalarType)).getSemantics(),
7396 APFloat::rmNearestTiesToEven, &LosesInfo);
7397 Register ScaleReg = GR.buildConstantFP(ScaleVal, MIRBuilder, SpirvScalarType);
7398
7399 // Multiply log2(x) by 0.30103 to get log10(x) result.
7400 auto Opcode =
7401 isVectorType(ResType) ? SPIRV::OpVectorTimesScalar : SPIRV::OpFMulS;
7402 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
7403 .addDef(ResVReg)
7404 .addUse(GR.getSPIRVTypeID(ResType))
7405 .addUse(VarReg)
7406 .addUse(ScaleReg)
7407 .constrainAllUses(TII, TRI, RBI);
7408 return true;
7409}
7410
7411bool SPIRVInstructionSelector::selectFpowi(Register ResVReg,
7412 SPIRVTypeInst ResType,
7413 MachineInstr &I) const {
7414 // On OpenCL targets, pown(gentype x, intn n) maps directly.
7415 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std))
7416 return selectExtInst(ResVReg, ResType, I, CL::pown);
7417
7418 // On GLSL (Vulkan) targets, there is no integer-exponent power instruction.
7419 // Lower as: Pow(base, OpConvertSToF(exp)).
7420 if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
7421 Register BaseReg = I.getOperand(1).getReg();
7422 Register ExpReg = I.getOperand(2).getReg();
7423 Register FloatExpReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
7424 if (!selectOpWithSrcs(FloatExpReg, ResType, I, {ExpReg},
7425 SPIRV::OpConvertSToF))
7426 return false;
7427 return selectExtInst(ResVReg, ResType, I, GL::Pow,
7428 /*setMIFlags=*/true, /*useMISrc=*/false,
7429 {BaseReg, FloatExpReg});
7430 }
7431 return false;
7432}
7433
7434bool SPIRVInstructionSelector::selectModf(Register ResVReg,
7435 SPIRVTypeInst ResType,
7436 MachineInstr &I) const {
7437 // llvm.modf has a single arg --the number to be decomposed-- and returns a
7438 // struct { restype, restype }, while OpenCLLIB::modf has two args --the
7439 // number to be decomposed and a pointer--, returns the fractional part and
7440 // the integral part is stored in the pointer argument. Therefore, we can't
7441 // use directly the OpenCLLIB::modf intrinsic. However, we can do some
7442 // scaffolding to make it work. The idea is to create an alloca instruction
7443 // to get a ptr, pass this ptr to OpenCL::modf, and then load the value
7444 // from this ptr to place it in the struct. llvm.modf returns the fractional
7445 // part as the first element of the result, and the integral part as the
7446 // second element of the result.
7447
7448 // At this point, the return type is not a struct anymore, but rather two
7449 // independent elements of SPIRVResType. We can get each independent element
7450 // from I.getDefs() or I.getOperands().
7451 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
7452 MachineIRBuilder MIRBuilder(I);
7453 SPIRVTypeInst FloatType =
7454 GR.getSPIRVTypeForVReg(I.getOperand(I.getNumExplicitDefs()).getReg());
7455 // Get pointer type for alloca variable.
7456 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
7457 FloatType, MIRBuilder, SPIRV::StorageClass::Function);
7458 // Create new register for the pointer type of alloca variable.
7459 Register PtrTyReg =
7460 MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
7461 MIRBuilder.getMRI()->setType(
7462 PtrTyReg,
7463 LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Function),
7464 GR.getPointerSize()));
7465
7466 // Assign SPIR-V type of the pointer type of the alloca variable to the
7467 // new register.
7468 GR.assignSPIRVTypeToVReg(PtrType, PtrTyReg, MIRBuilder.getMF());
7470 MachineBasicBlock &EntryBB = I.getMF()->front();
7471 const bool IsUntyped =
7472 PtrType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR;
7473 auto AllocaMIB =
7474 BuildMI(EntryBB, VarPos, I.getDebugLoc(),
7475 TII.get(IsUntyped ? SPIRV::OpUntypedVariableKHR
7476 : SPIRV::OpVariable))
7477 .addDef(PtrTyReg)
7478 .addUse(GR.getSPIRVTypeID(PtrType))
7479 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function));
7480 if (IsUntyped)
7481 AllocaMIB.addUse(GR.getSPIRVTypeID(ResType)); // Data Type
7482 Register Variable = AllocaMIB->getOperand(0).getReg();
7483
7484 MachineBasicBlock &BB = *I.getParent();
7485 // Create the OpenCLLIB::modf instruction.
7486 auto MIB =
7487 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
7488 .addDef(ResVReg)
7489 .addUse(GR.getSPIRVTypeID(FloatType))
7490 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
7491 .addImm(CL::modf)
7492 .setMIFlags(I.getFlags())
7493 .add(I.getOperand(I.getNumExplicitDefs())) // Floating point value.
7494 .addUse(Variable); // Pointer to integral part.
7495 // Assign the integral part stored in the ptr to the second element of the
7496 // result.
7497 Register IntegralPartReg = I.getOperand(1).getReg();
7498 if (IntegralPartReg.isValid() && !MRI->use_nodbg_empty(IntegralPartReg)) {
7499 // Load the value from the pointer to integral part.
7500 auto LoadMIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
7501 .addDef(IntegralPartReg)
7502 .addUse(GR.getSPIRVTypeID(FloatType))
7503 .addUse(Variable);
7504 LoadMIB.constrainAllUses(TII, TRI, RBI);
7505 }
7506
7507 MIB.constrainAllUses(TII, TRI, RBI);
7508 return true;
7509 } else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
7510 assert(false && "GLSL::Modf is deprecated.");
7511 // FIXME: GL::Modf is deprecated, use Modfstruct instead.
7512 return false;
7513 }
7514 return false;
7515}
7516
7517// Generate the instructions to load 3-element vector builtin input
7518// IDs/Indices.
7519// Like: GlobalInvocationId, LocalInvocationId, etc....
7520
7521bool SPIRVInstructionSelector::loadVec3BuiltinInputID(
7522 SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg,
7523 SPIRVTypeInst ResType, MachineInstr &I) const {
7524 MachineIRBuilder MIRBuilder(I);
7525 const SPIRVTypeInst Vec3Ty =
7526 GR.getOrCreateSPIRVVectorType(ResType, 3, MIRBuilder, false);
7527 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
7528 Vec3Ty, MIRBuilder, SPIRV::StorageClass::Input);
7529
7530 // Create new register for the input ID builtin variable.
7531 Register NewRegister =
7532 MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
7533 MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 64));
7534 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
7535
7536 // Build global variable with the necessary decorations for the input ID
7537 // builtin variable.
7539 NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr,
7540 SPIRV::StorageClass::Input, nullptr, true, std::nullopt, MIRBuilder,
7541 false);
7542
7543 // Create new register for loading value.
7544 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
7545 Register LoadedRegister = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
7546 MIRBuilder.getMRI()->setType(LoadedRegister, LLT::pointer(0, 64));
7547 GR.assignSPIRVTypeToVReg(Vec3Ty, LoadedRegister, MIRBuilder.getMF());
7548
7549 // Load v3uint value from the global variable.
7550 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
7551 .addDef(LoadedRegister)
7552 .addUse(GR.getSPIRVTypeID(Vec3Ty))
7553 .addUse(Variable);
7554
7555 // Get the input ID index. Expecting operand is a constant immediate value,
7556 // wrapped in a type assignment.
7557 assert(I.getOperand(2).isReg());
7558 const uint32_t ThreadId = foldImm(I.getOperand(2), MRI);
7559
7560 // Extract the input ID from the loaded vector value.
7561 MachineBasicBlock &BB = *I.getParent();
7562 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
7563 .addDef(ResVReg)
7564 .addUse(GR.getSPIRVTypeID(ResType))
7565 .addUse(LoadedRegister)
7566 .addImm(ThreadId);
7567 MIB.constrainAllUses(TII, TRI, RBI);
7568 return true;
7569}
7570
7571// Generate the instructions to load 32-bit integer builtin input IDs/Indices.
7572// Like LocalInvocationIndex
7573bool SPIRVInstructionSelector::loadBuiltinInputID(
7574 SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg,
7575 SPIRVTypeInst ResType, MachineInstr &I) const {
7576 MachineIRBuilder MIRBuilder(I);
7577 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
7578 ResType, MIRBuilder, SPIRV::StorageClass::Input);
7579
7580 // Create new register for the input ID builtin variable.
7581 Register NewRegister =
7582 MIRBuilder.getMRI()->createVirtualRegister(GR.getRegClass(PtrType));
7583 MIRBuilder.getMRI()->setType(
7584 NewRegister,
7585 LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Input),
7586 GR.getPointerSize()));
7587 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
7588
7589 // Build global variable with the necessary decorations for the input ID
7590 // builtin variable.
7592 NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr,
7593 SPIRV::StorageClass::Input, nullptr, true, std::nullopt, MIRBuilder,
7594 false);
7595
7596 // Load uint value from the global variable.
7597 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
7598 .addDef(ResVReg)
7599 .addUse(GR.getSPIRVTypeID(ResType))
7600 .addUse(Variable);
7601
7602 MIB.constrainAllUses(TII, TRI, RBI);
7603 return true;
7604}
7605
7606SPIRVTypeInst SPIRVInstructionSelector::widenTypeToVec4(SPIRVTypeInst Type,
7607 MachineInstr &I) const {
7608 MachineIRBuilder MIRBuilder(I);
7609 if (!isVectorType(Type))
7610 return GR.getOrCreateSPIRVVectorType(Type, 4, MIRBuilder, false);
7611
7613 return Type;
7614
7615 SPIRVTypeInst ScalarType = GR.getScalarOrVectorComponentType(Type);
7616 return GR.getOrCreateSPIRVVectorType(ScalarType, 4, MIRBuilder, false);
7617}
7618
7619bool SPIRVInstructionSelector::loadHandleBeforePosition(
7620 Register &HandleReg, SPIRVTypeInst ResType, GIntrinsic &HandleDef,
7621 MachineInstr &Pos) const {
7622
7623 assert(HandleDef.getIntrinsicID() ==
7624 Intrinsic::spv_resource_handlefrombinding);
7625 uint32_t Set = foldImm(HandleDef.getOperand(2), MRI);
7626 uint32_t Binding = foldImm(HandleDef.getOperand(3), MRI);
7627 uint32_t ArraySize = foldImm(HandleDef.getOperand(4), MRI);
7628 Register IndexReg = HandleDef.getOperand(5).getReg();
7629 std::string Name =
7630 getStringValueFromReg(HandleDef.getOperand(6).getReg(), *MRI);
7631
7632 bool IsStructuredBuffer = ResType->getOpcode() == SPIRV::OpTypePointer;
7633 MachineIRBuilder MIRBuilder(HandleDef);
7634 SPIRVTypeInst VarType = ResType;
7635 SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::UniformConstant;
7636
7637 if (IsStructuredBuffer) {
7638 VarType = GR.getPointeeType(ResType);
7639 SC = GR.getPointerStorageClass(ResType);
7640 }
7641
7642 if (ResType->getOpcode() == SPIRV::OpTypeImage && ArraySize == 0)
7643 MIRBuilder.buildInstr(SPIRV::OpCapability)
7644 .addImm(SPIRV::Capability::RuntimeDescriptorArrayEXT);
7645
7646 Register VarReg =
7647 buildPointerToResource(SPIRVTypeInst(VarType), SC, Set, Binding,
7648 ArraySize, IndexReg, Name, MIRBuilder);
7649
7650 // The handle for the buffer is the pointer to the resource. For an image, the
7651 // handle is the image object. So images get an extra load.
7652 uint32_t LoadOpcode =
7653 IsStructuredBuffer ? SPIRV::OpCopyObject : SPIRV::OpLoad;
7654 GR.assignSPIRVTypeToVReg(ResType, HandleReg, *Pos.getMF());
7655 BuildMI(*Pos.getParent(), Pos, HandleDef.getDebugLoc(), TII.get(LoadOpcode))
7656 .addDef(HandleReg)
7657 .addUse(GR.getSPIRVTypeID(ResType))
7658 .addUse(VarReg)
7659 .constrainAllUses(TII, TRI, RBI);
7660 return true;
7661}
7662
7663bool SPIRVInstructionSelector::errorIfInstrOutsideShader(
7664 MachineInstr &I) const {
7665 if (!STI.isShader())
7666 return diagnoseUnsupported(
7667 I, "this instruction is only supported in shaders.");
7668 return true;
7669}
7670
7671namespace llvm {
7672InstructionSelector *
7674 const SPIRVSubtarget &Subtarget,
7675 const RegisterBankInfo &RBI) {
7676 return new SPIRVInstructionSelector(TM, Subtarget, RBI);
7677}
7678} // 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 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:231
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:226
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:743
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:770
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:746
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition InstrTypes.h:755
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:744
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:745
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:764
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:763
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:767
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition InstrTypes.h:754
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:748
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition InstrTypes.h:751
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition InstrTypes.h:752
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:747
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:749
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:768
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition InstrTypes.h:756
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:766
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition InstrTypes.h:753
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
unsigned size() const
Definition DenseMap.h:172
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp: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:348
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Helper class to build MachineInstr.
MachineBasicBlock::iterator getInsertPt()
Current insertion point for new instructions.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
void constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
LLVM_ABI unsigned getNumExplicitDefs() const
Returns the number of non-implicit definitions.
LLVM_ABI void 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.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:477
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
@ HalfTyID
16-bit floating point type
Definition Type.h:57
@ FloatTyID
32-bit floating point type
Definition Type.h:59
@ BFloatTyID
16-bit floating point type (7-bit significand)
Definition Type.h:58
@ DoubleTyID
64-bit floating point type
Definition Type.h:60
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:368
bool isStructTy() const
True if this is an instance of StructType.
Definition Type.h:276
bool isAggregateType() const
Return true if the type is an aggregate type.
Definition Type.h:319
TypeID getTypeID() const
Return the type id for the type.
Definition Type.h:138
Value * getOperand(unsigned i) const
Definition User.h:207
bool hasName() const
Definition Value.h:261
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
An efficient, type-erasing, non-owning reference to a callable.
self_iterator getIterator()
Definition ilist_node.h:123
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition ilist_node.h:348
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char IsConst[]
Key for Kernel::Arg::Metadata::mIsConst.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
NodeAddr< InstrNode * > Instr
Definition RDFGraph.h:389
NodeAddr< UseNode * > Use
Definition RDFGraph.h:385
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:393
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
Definition SFrame.h:77
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:1739
void addStringImm(StringRef Str, MCInst &Inst)
MachineBasicBlock::iterator getOpVariableMBBIt(MachineFunction &MF)
int64_t getIConstValSext(Register ConstReg, const MachineRegisterInfo *MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool isTypeFoldingSupported(unsigned Opcode)
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:633
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:1746
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
Type * toTypedPointer(Type *Ty)
Definition SPIRVUtils.h: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