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