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