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