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