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