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