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