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