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