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