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