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