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