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 // OpPtrEqual/OpPtrNotEqual require both operands to share an identical
3972 // pointer type. If they are not OpBitcast is inserted.
3973 Register Op1 = I.getOperand(3).getReg();
3974 SPIRVTypeInst Ty0 = GR.getSPIRVTypeForVReg(CmpOperand);
3975 if (Ty0 != GR.getSPIRVTypeForVReg(Op1)) {
3976 Register NewOp1 = createVirtualRegister(Ty0, &GR, MRI, MRI->getMF());
3977 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpBitcast))
3978 .addDef(NewOp1)
3979 .addUse(GR.getSPIRVTypeID(Ty0))
3980 .addUse(Op1)
3981 .constrainAllUses(TII, TRI, RBI);
3982 I.getOperand(3).setReg(NewOp1);
3983 }
3984 } else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool))
3985 CmpOpc = getBoolCmpOpcode(Pred);
3986 else
3987 CmpOpc = getICmpOpcode(Pred);
3988 return selectCmp(ResVReg, ResType, CmpOpc, I);
3989}
3990
3992SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I,
3993 SPIRVTypeInst ResType) const {
3994 Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32);
3995 SPIRVTypeInst SpvI32Ty =
3996 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII);
3997 // Find a constant in DT or build a new one.
3998 auto ConstInt = ConstantInt::get(LLVMTy, Val);
3999 Register NewReg = GR.find(ConstInt, GR.CurMF);
4000 if (!NewReg.isValid()) {
4001 NewReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
4002 MachineBasicBlock &BB = *I.getParent();
4003 MachineInstr *MI =
4004 Val == 0
4005 ? BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
4006 .addDef(NewReg)
4007 .addUse(GR.getSPIRVTypeID(SpvI32Ty))
4008 : BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
4009 .addDef(NewReg)
4010 .addUse(GR.getSPIRVTypeID(SpvI32Ty))
4011 .addImm(APInt(32, Val).getZExtValue());
4013 GR.add(ConstInt, MI);
4014 }
4015 return NewReg;
4016}
4017
4018// Like buildI32Constant, but always inserts the constant definition in the
4019// entry block so it dominates all uses regardless of block ordering.
4020Register SPIRVInstructionSelector::buildI32ConstantInEntryBlock(
4021 uint32_t Val, MachineInstr &I, SPIRVTypeInst ResType) const {
4022 Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32);
4023 SPIRVTypeInst SpvI32Ty =
4024 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII);
4025 auto *ConstInt = ConstantInt::get(LLVMTy, Val);
4026 Register NewReg = GR.find(ConstInt, GR.CurMF);
4027 if (!NewReg.isValid()) {
4028 NewReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
4029 auto InsertIt = getOpVariableMBBIt(*I.getMF());
4030 MachineBasicBlock &EntryBB = *InsertIt->getParent();
4031 MachineInstr *MI = nullptr;
4032 Register TypeReg = GR.getSPIRVTypeID(SpvI32Ty);
4033 DebugLoc DbgLoc = I.getDebugLoc();
4034 if (Val == 0) {
4035 MI = BuildMI(EntryBB, InsertIt, DbgLoc, TII.get(SPIRV::OpConstantNull))
4036 .addDef(NewReg)
4037 .addUse(TypeReg);
4038 } else {
4039 uint64_t ImmVal = APInt(32, Val).getZExtValue();
4040 MI = BuildMI(EntryBB, InsertIt, DbgLoc, TII.get(SPIRV::OpConstantI))
4041 .addDef(NewReg)
4042 .addUse(TypeReg)
4043 .addImm(ImmVal);
4044 }
4046 GR.add(ConstInt, MI);
4047 }
4048 return NewReg;
4049}
4050
4051bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
4052 SPIRVTypeInst ResType,
4053 MachineInstr &I) const {
4054 unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate());
4055 return selectCmp(ResVReg, ResType, CmpOp, I);
4056}
4057
4058bool SPIRVInstructionSelector::selectExp10(Register ResVReg,
4059 SPIRVTypeInst ResType,
4060 MachineInstr &I) const {
4061 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
4062 return selectExtInst(ResVReg, ResType, I, CL::exp10);
4063 }
4064
4065 if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
4066 /// There is no exp10 in GLSL. Use exp10(x) = exp2(x * log2(10)) instead
4067 /// log2(10) ~= 3.3219280948874l
4068
4069 if (ResType->getOpcode() != SPIRV::OpTypeVector &&
4070 ResType->getOpcode() != SPIRV::OpTypeFloat)
4071 return false;
4072
4073 MachineIRBuilder MIRBuilder(I);
4074
4075 SPIRVTypeInst SpirvScalarType = GR.getScalarOrVectorComponentType(ResType);
4076
4077 // Match the literal precision to the scalar type so the OpConstant
4078 // literal does not contain non-zero high-order bits that would fail
4079 // SPIR-V validation when the type is narrower than 32 bits (e.g. half).
4080 APFloat ConstVal(3.3219280948873623);
4081 bool LosesInfo;
4082 ConstVal.convert(
4083 getZeroFP(GR.getTypeForSPIRVType(SpirvScalarType)).getSemantics(),
4084 APFloat::rmNearestTiesToEven, &LosesInfo);
4085 Register ConstReg =
4086 GR.buildConstantFP(ConstVal, MIRBuilder, SpirvScalarType);
4087 Register ArgReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
4088 auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector
4089 ? SPIRV::OpVectorTimesScalar
4090 : SPIRV::OpFMulS;
4091
4092 if (!selectOpWithSrcs(ArgReg, ResType, I,
4093 {I.getOperand(1).getReg(), ConstReg}, Opcode))
4094 return false;
4095 if (!selectExtInst(ResVReg, ResType, I,
4096 {{SPIRV::InstructionSet::GLSL_std_450, GL::Exp2}}, false,
4097 false, {ArgReg}))
4098 return false;
4099
4100 return true;
4101 }
4102
4103 return false;
4104}
4105
4106Register SPIRVInstructionSelector::buildZerosVal(SPIRVTypeInst ResType,
4107 MachineInstr &I) const {
4108 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
4109 bool ZeroAsNull = !STI.isShader();
4110 if (ResType->getOpcode() == SPIRV::OpTypeVector)
4111 return GR.getOrCreateConstVector(0UL, I, ResType, TII, ZeroAsNull);
4112 return GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
4113}
4114
4115bool SPIRVInstructionSelector::isScalarOrVectorIntConstantZero(
4116 Register Reg) const {
4117 SPIRVTypeInst Type = GR.getSPIRVTypeForVReg(Reg);
4118 if (!Type)
4119 return false;
4120 SPIRVTypeInst CompType = GR.getScalarOrVectorComponentType(Type);
4121 if (!CompType || CompType->getOpcode() != SPIRV::OpTypeInt)
4122 return false;
4123
4124 auto IsZero = [this](Register Reg) {
4125 MachineInstr *Def = getDefInstrMaybeConstant(Reg, MRI);
4126 if (!Def)
4127 return false;
4128
4129 if (Def->getOpcode() == SPIRV::OpConstantNull)
4130 return true;
4131
4132 if (Def->getOpcode() == TargetOpcode::G_CONSTANT ||
4133 Def->getOpcode() == SPIRV::OpConstantI)
4134 return getIConstVal(Reg, MRI) == 0;
4135
4136 return false;
4137 };
4138
4139 if (IsZero(Reg))
4140 return true;
4141
4142 MachineInstr *Def = MRI->getVRegDef(Reg);
4143 if (!Def)
4144 return false;
4145
4146 if (Def->getOpcode() == TargetOpcode::G_BUILD_VECTOR ||
4147 (Def->getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS &&
4148 cast<GIntrinsic>(Def)->getIntrinsicID() ==
4149 Intrinsic::spv_const_composite)) {
4150 unsigned StartOp = Def->getOpcode() == TargetOpcode::G_BUILD_VECTOR ? 1 : 2;
4151 for (unsigned i = StartOp; i < Def->getNumOperands(); ++i) {
4152 if (!IsZero(Def->getOperand(i).getReg()))
4153 return false;
4154 }
4155 return true;
4156 }
4157
4158 return false;
4159}
4160
4161Register SPIRVInstructionSelector::buildZerosValF(SPIRVTypeInst ResType,
4162 MachineInstr &I) const {
4163 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
4164 bool ZeroAsNull = !STI.isShader();
4165 APFloat VZero = getZeroFP(GR.getTypeForSPIRVType(ResType));
4166 if (ResType->getOpcode() == SPIRV::OpTypeVector)
4167 return GR.getOrCreateConstVector(VZero, I, ResType, TII, ZeroAsNull);
4168 return GR.getOrCreateConstFP(VZero, I, ResType, TII, ZeroAsNull);
4169}
4170
4171Register SPIRVInstructionSelector::buildOnesValF(SPIRVTypeInst ResType,
4172 MachineInstr &I) const {
4173 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
4174 bool ZeroAsNull = !STI.isShader();
4175 APFloat VOne = getOneFP(GR.getTypeForSPIRVType(ResType));
4176 if (ResType->getOpcode() == SPIRV::OpTypeVector)
4177 return GR.getOrCreateConstVector(VOne, I, ResType, TII, ZeroAsNull);
4178 return GR.getOrCreateConstFP(VOne, I, ResType, TII, ZeroAsNull);
4179}
4180
4181Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
4182 SPIRVTypeInst ResType,
4183 MachineInstr &I) const {
4184 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
4185 APInt One =
4186 AllOnes ? APInt::getAllOnes(BitWidth) : APInt::getOneBitSet(BitWidth, 0);
4187 if (ResType->getOpcode() == SPIRV::OpTypeVector)
4188 return GR.getOrCreateConstVector(One, I, ResType, TII);
4189 return GR.getOrCreateConstInt(One, I, ResType, TII);
4190}
4191
4192bool SPIRVInstructionSelector::selectSelect(Register ResVReg,
4193 SPIRVTypeInst ResType,
4194 MachineInstr &I) const {
4195 Register SelectFirstArg = I.getOperand(2).getReg();
4196 Register SelectSecondArg = I.getOperand(3).getReg();
4197 assert(ResType == GR.getSPIRVTypeForVReg(SelectFirstArg) &&
4198 ResType == GR.getSPIRVTypeForVReg(SelectSecondArg));
4199
4200 bool IsFloatTy =
4201 GR.isScalarOrVectorOfType(SelectFirstArg, SPIRV::OpTypeFloat);
4202 bool IsPtrTy =
4203 GR.isScalarOrVectorOfType(SelectFirstArg, SPIRV::OpTypePointer);
4204 bool IsVectorTy = GR.getSPIRVTypeForVReg(SelectFirstArg)->getOpcode() ==
4205 SPIRV::OpTypeVector;
4206
4207 bool IsScalarBool =
4208 GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool);
4209 unsigned Opcode;
4210 if (IsVectorTy) {
4211 if (IsFloatTy) {
4212 Opcode = IsScalarBool ? SPIRV::OpSelectVFSCond : SPIRV::OpSelectVFVCond;
4213 } else if (IsPtrTy) {
4214 Opcode = IsScalarBool ? SPIRV::OpSelectVPSCond : SPIRV::OpSelectVPVCond;
4215 } else {
4216 Opcode = IsScalarBool ? SPIRV::OpSelectVISCond : SPIRV::OpSelectVIVCond;
4217 }
4218 } else {
4219 assert(IsScalarBool && "OpSelect with a scalar result requires a scalar "
4220 "boolean condition");
4221 if (IsFloatTy) {
4222 Opcode = SPIRV::OpSelectSFSCond;
4223 } else if (IsPtrTy) {
4224 Opcode = SPIRV::OpSelectSPSCond;
4225 } else {
4226 Opcode = SPIRV::OpSelectSISCond;
4227 }
4228 }
4229 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
4230 .addDef(ResVReg)
4231 .addUse(GR.getSPIRVTypeID(ResType))
4232 .addUse(I.getOperand(1).getReg())
4233 .addUse(SelectFirstArg)
4234 .addUse(SelectSecondArg)
4235 .constrainAllUses(TII, TRI, RBI);
4236 return true;
4237}
4238
4239// This function is used to extend a bool or a vector of bools into an integer
4240// or vector of integers.
4241bool SPIRVInstructionSelector::selectBoolToInt(Register ResVReg,
4242 SPIRVTypeInst ResType,
4243 Register BooleanVReg,
4244 MachineInstr &InsertAt,
4245 bool IsSigned) const {
4246 // To extend a bool, we need to use OpSelect between constants.
4247 Register ZeroReg = buildZerosVal(ResType, InsertAt);
4248 Register OneReg = buildOnesVal(IsSigned, ResType, InsertAt);
4249 bool IsScalarBool = GR.isScalarOfType(BooleanVReg, SPIRV::OpTypeBool);
4250 unsigned Opcode =
4251 IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond;
4252 BuildMI(*InsertAt.getParent(), InsertAt, InsertAt.getDebugLoc(),
4253 TII.get(Opcode))
4254 .addDef(ResVReg)
4255 .addUse(GR.getSPIRVTypeID(ResType))
4256 .addUse(BooleanVReg)
4257 .addUse(OneReg)
4258 .addUse(ZeroReg)
4259 .constrainAllUses(TII, TRI, RBI);
4260 return true;
4261}
4262
4263bool SPIRVInstructionSelector::selectIToF(Register ResVReg,
4264 SPIRVTypeInst ResType,
4265 MachineInstr &I, bool IsSigned,
4266 unsigned Opcode) const {
4267 Register SrcReg = I.getOperand(1).getReg();
4268 // We can convert bool value directly to float type without OpConvert*ToF,
4269 // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
4270 if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) {
4271 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
4272 SPIRVTypeInst TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII);
4273 if (ResType->getOpcode() == SPIRV::OpTypeVector) {
4274 const unsigned NumElts = GR.getScalarOrVectorComponentCount(ResType);
4275 TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII);
4276 }
4277 SrcReg = createVirtualRegister(TmpType, &GR, MRI, MRI->getMF());
4278 selectBoolToInt(SrcReg, TmpType, I.getOperand(1).getReg(), I, false);
4279 }
4280 return selectOpWithSrcs(ResVReg, ResType, I, {SrcReg}, Opcode);
4281}
4282
4283bool SPIRVInstructionSelector::selectExt(Register ResVReg,
4284 SPIRVTypeInst ResType, MachineInstr &I,
4285 bool IsSigned) const {
4286 Register SrcReg = I.getOperand(1).getReg();
4287 if (GR.isScalarOrVectorOfType(SrcReg, SPIRV::OpTypeBool))
4288 return selectBoolToInt(ResVReg, ResType, I.getOperand(1).getReg(), I,
4289 IsSigned);
4290
4291 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(SrcReg);
4292 if (ResType == SrcType)
4293 return BuildCOPY(ResVReg, SrcReg, I);
4294
4295 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
4296 return selectUnOp(ResVReg, ResType, I, Opcode);
4297}
4298
4299bool SPIRVInstructionSelector::selectSUCmp(Register ResVReg,
4300 SPIRVTypeInst ResType,
4301 MachineInstr &I,
4302 bool IsSigned) const {
4303 MachineIRBuilder MIRBuilder(I);
4304 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
4305 MachineBasicBlock &BB = *I.getParent();
4306 // Ensure we have bool.
4307 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
4308 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
4309 if (N > 1)
4310 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, N, I, TII);
4311 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
4312 // Build less-than-equal and less-than.
4313 Register IsLessEqReg =
4314 createVirtualRegister(BoolType, &GR, MRI, MIRBuilder.getMF());
4315 BuildMI(BB, I, I.getDebugLoc(),
4316 TII.get(IsSigned ? SPIRV::OpSLessThanEqual : SPIRV::OpULessThanEqual))
4317 .addDef(IsLessEqReg)
4318 .addUse(BoolTypeReg)
4319 .addUse(I.getOperand(1).getReg())
4320 .addUse(I.getOperand(2).getReg())
4321 .constrainAllUses(TII, TRI, RBI);
4322 Register IsLessReg =
4323 createVirtualRegister(BoolType, &GR, MRI, MIRBuilder.getMF());
4324 BuildMI(BB, I, I.getDebugLoc(),
4325 TII.get(IsSigned ? SPIRV::OpSLessThan : SPIRV::OpULessThan))
4326 .addDef(IsLessReg)
4327 .addUse(BoolTypeReg)
4328 .addUse(I.getOperand(1).getReg())
4329 .addUse(I.getOperand(2).getReg())
4330 .constrainAllUses(TII, TRI, RBI);
4331 // Build selects.
4332 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
4333 Register NegOneOrZeroReg =
4334 MRI->createVirtualRegister(GR.getRegClass(ResType));
4335 MRI->setType(NegOneOrZeroReg, LLT::scalar(64));
4336 GR.assignSPIRVTypeToVReg(ResType, NegOneOrZeroReg, MIRBuilder.getMF());
4337 unsigned SelectOpcode =
4338 N > 1 ? SPIRV::OpSelectVIVCond : SPIRV::OpSelectSISCond;
4339 BuildMI(BB, I, I.getDebugLoc(), TII.get(SelectOpcode))
4340 .addDef(NegOneOrZeroReg)
4341 .addUse(ResTypeReg)
4342 .addUse(IsLessReg)
4343 .addUse(buildOnesVal(true, ResType, I)) // -1
4344 .addUse(buildZerosVal(ResType, I))
4345 .constrainAllUses(TII, TRI, RBI);
4346 BuildMI(BB, I, I.getDebugLoc(), TII.get(SelectOpcode))
4347 .addDef(ResVReg)
4348 .addUse(ResTypeReg)
4349 .addUse(IsLessEqReg)
4350 .addUse(NegOneOrZeroReg) // -1 or 0
4351 .addUse(buildOnesVal(false, ResType, I))
4352 .constrainAllUses(TII, TRI, RBI);
4353 return true;
4354}
4355
4356bool SPIRVInstructionSelector::selectIntToBool(Register IntReg,
4357 Register ResVReg,
4358 MachineInstr &I,
4359 SPIRVTypeInst IntTy,
4360 SPIRVTypeInst BoolTy) const {
4361 // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
4362 Register BitIntReg = createVirtualRegister(IntTy, &GR, MRI, MRI->getMF());
4363 bool IsVectorTy = IntTy->getOpcode() == SPIRV::OpTypeVector;
4364 unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
4365 Register Zero = buildZerosVal(IntTy, I);
4366 Register One = buildOnesVal(false, IntTy, I);
4367 MachineBasicBlock &BB = *I.getParent();
4368 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
4369 .addDef(BitIntReg)
4370 .addUse(GR.getSPIRVTypeID(IntTy))
4371 .addUse(IntReg)
4372 .addUse(One)
4373 .constrainAllUses(TII, TRI, RBI);
4374 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
4375 .addDef(ResVReg)
4376 .addUse(GR.getSPIRVTypeID(BoolTy))
4377 .addUse(BitIntReg)
4378 .addUse(Zero)
4379 .constrainAllUses(TII, TRI, RBI);
4380 return true;
4381}
4382
4383bool SPIRVInstructionSelector::selectTrunc(Register ResVReg,
4384 SPIRVTypeInst ResType,
4385 MachineInstr &I) const {
4386 Register IntReg = I.getOperand(1).getReg();
4387 const SPIRVTypeInst ArgType = GR.getSPIRVTypeForVReg(IntReg);
4388 if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool))
4389 return selectIntToBool(IntReg, ResVReg, I, ArgType, ResType);
4390 if (ArgType == ResType)
4391 return BuildCOPY(ResVReg, IntReg, I);
4392 bool IsSigned = GR.isScalarOrVectorSigned(ResType);
4393 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
4394 return selectUnOp(ResVReg, ResType, I, Opcode);
4395}
4396
4397bool SPIRVInstructionSelector::selectConst(Register ResVReg,
4398 SPIRVTypeInst ResType,
4399 MachineInstr &I) const {
4400 unsigned Opcode = I.getOpcode();
4401 unsigned TpOpcode = ResType->getOpcode();
4402 Register Reg;
4403 if (TpOpcode == SPIRV::OpTypePointer || TpOpcode == SPIRV::OpTypeEvent) {
4404 assert(Opcode == TargetOpcode::G_CONSTANT &&
4405 I.getOperand(1).getCImm()->isZero());
4406 MachineBasicBlock &DepMBB = I.getMF()->front();
4407 MachineIRBuilder MIRBuilder(DepMBB, DepMBB.getFirstNonPHI());
4408 Reg = GR.getOrCreateConstNullPtr(MIRBuilder, ResType);
4409 } else if (Opcode == TargetOpcode::G_FCONSTANT) {
4410 Reg = GR.getOrCreateConstFP(I.getOperand(1).getFPImm()->getValue(), I,
4411 ResType, TII, !STI.isShader());
4412 } else {
4413 Reg = GR.getOrCreateConstInt(I.getOperand(1).getCImm()->getValue(), I,
4414 ResType, TII, !STI.isShader());
4415 }
4416 return Reg == ResVReg ? true : BuildCOPY(ResVReg, Reg, I);
4417}
4418
4419bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg,
4420 SPIRVTypeInst ResType,
4421 MachineInstr &I) const {
4422 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
4423 .addDef(ResVReg)
4424 .addUse(GR.getSPIRVTypeID(ResType))
4425 .constrainAllUses(TII, TRI, RBI);
4426 return true;
4427}
4428
4429bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg,
4430 SPIRVTypeInst ResType,
4431 MachineInstr &I) const {
4432 MachineBasicBlock &BB = *I.getParent();
4433 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeInsert))
4434 .addDef(ResVReg)
4435 .addUse(GR.getSPIRVTypeID(ResType))
4436 // object to insert
4437 .addUse(I.getOperand(3).getReg())
4438 // composite to insert into
4439 .addUse(I.getOperand(2).getReg());
4440 for (unsigned i = 4; i < I.getNumOperands(); i++)
4441 MIB.addImm(foldImm(I.getOperand(i), MRI));
4442 MIB.constrainAllUses(TII, TRI, RBI);
4443 return true;
4444}
4445
4446bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg,
4447 SPIRVTypeInst ResType,
4448 MachineInstr &I) const {
4449 Type *MaybeResTy = nullptr;
4450 StringRef ResName;
4451 if (GR.findValueAttrs(&I, MaybeResTy, ResName) &&
4452 MaybeResTy != GR.getTypeForSPIRVType(ResType)) {
4453 assert((!MaybeResTy || MaybeResTy->isAggregateType()) &&
4454 "Expected aggregate type for extractv instruction");
4455 ResType = GR.getOrCreateSPIRVType(MaybeResTy, I,
4456 SPIRV::AccessQualifier::ReadWrite, false);
4457 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *I.getMF());
4458 }
4459 MachineBasicBlock &BB = *I.getParent();
4460 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
4461 .addDef(ResVReg)
4462 .addUse(GR.getSPIRVTypeID(ResType))
4463 .addUse(I.getOperand(2).getReg());
4464 for (unsigned i = 3; i < I.getNumOperands(); i++)
4465 MIB.addImm(foldImm(I.getOperand(i), MRI));
4466 MIB.constrainAllUses(TII, TRI, RBI);
4467 return true;
4468}
4469
4470bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg,
4471 SPIRVTypeInst ResType,
4472 MachineInstr &I) const {
4473 if (getImm(I.getOperand(4), MRI))
4474 return selectInsertVal(ResVReg, ResType, I);
4475 MachineBasicBlock &BB = *I.getParent();
4476 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorInsertDynamic))
4477 .addDef(ResVReg)
4478 .addUse(GR.getSPIRVTypeID(ResType))
4479 .addUse(I.getOperand(2).getReg())
4480 .addUse(I.getOperand(3).getReg())
4481 .addUse(I.getOperand(4).getReg())
4482 .constrainAllUses(TII, TRI, RBI);
4483 return true;
4484}
4485
4486bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg,
4487 SPIRVTypeInst ResType,
4488 MachineInstr &I) const {
4489 if (getImm(I.getOperand(3), MRI))
4490 return selectExtractVal(ResVReg, ResType, I);
4491 MachineBasicBlock &BB = *I.getParent();
4492 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorExtractDynamic))
4493 .addDef(ResVReg)
4494 .addUse(GR.getSPIRVTypeID(ResType))
4495 .addUse(I.getOperand(2).getReg())
4496 .addUse(I.getOperand(3).getReg())
4497 .constrainAllUses(TII, TRI, RBI);
4498 return true;
4499}
4500
4501bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
4502 SPIRVTypeInst ResType,
4503 MachineInstr &I) const {
4504 const bool IsGEPInBounds = I.getOperand(2).getImm();
4505
4506 // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator only
4507 // relies on PtrAccessChain, so we'll try not to deviate. For Vulkan however,
4508 // we have to use Op[InBounds]AccessChain.
4509 const unsigned Opcode = STI.isLogicalSPIRV()
4510 ? (IsGEPInBounds ? SPIRV::OpInBoundsAccessChain
4511 : SPIRV::OpAccessChain)
4512 : (IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
4513 : SPIRV::OpPtrAccessChain);
4514
4515 auto Res = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
4516 .addDef(ResVReg)
4517 .addUse(GR.getSPIRVTypeID(ResType))
4518 // Object to get a pointer to.
4519 .addUse(I.getOperand(3).getReg());
4520 assert(
4521 (Opcode == SPIRV::OpPtrAccessChain ||
4522 Opcode == SPIRV::OpInBoundsPtrAccessChain ||
4523 (getImm(I.getOperand(4), MRI) && foldImm(I.getOperand(4), MRI) == 0)) &&
4524 "Cannot translate GEP to OpAccessChain. First index must be 0.");
4525
4526 // Adding indices.
4527 const unsigned StartingIndex =
4528 (Opcode == SPIRV::OpAccessChain || Opcode == SPIRV::OpInBoundsAccessChain)
4529 ? 5
4530 : 4;
4531 for (unsigned i = StartingIndex; i < I.getNumExplicitOperands(); ++i)
4532 Res.addUse(I.getOperand(i).getReg());
4533 Res.constrainAllUses(TII, TRI, RBI);
4534 return true;
4535}
4536
4537// Maybe wrap a value into OpSpecConstantOp
4538bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
4539 MachineInstr &I, SmallVector<Register> &CompositeArgs) const {
4540 unsigned Lim = I.getNumExplicitOperands();
4541 for (unsigned i = I.getNumExplicitDefs() + 1; i < Lim; ++i) {
4542 Register OpReg = I.getOperand(i).getReg();
4543 MachineInstr *OpDefine = MRI->getVRegDef(OpReg);
4544 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
4545 if (!OpDefine || !OpType || isConstReg(MRI, OpDefine) ||
4546 OpDefine->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
4547 OpDefine->getOpcode() == TargetOpcode::G_INTTOPTR ||
4548 GR.isAggregateType(OpType)) {
4549 // The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed
4550 // by selectAddrSpaceCast(), and G_INTTOPTR is processed by selectUnOp()
4551 CompositeArgs.push_back(OpReg);
4552 continue;
4553 }
4554 MachineFunction *MF = I.getMF();
4555 Register WrapReg = GR.find(OpDefine, MF);
4556 if (WrapReg.isValid()) {
4557 CompositeArgs.push_back(WrapReg);
4558 continue;
4559 }
4560 // Create a new register for the wrapper
4561 WrapReg = MRI->createVirtualRegister(GR.getRegClass(OpType));
4562 CompositeArgs.push_back(WrapReg);
4563 // Decorate the wrapper register and generate a new instruction
4564 MRI->setType(WrapReg, LLT::pointer(0, 64));
4565 GR.assignSPIRVTypeToVReg(OpType, WrapReg, *MF);
4566 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
4567 TII.get(SPIRV::OpSpecConstantOp))
4568 .addDef(WrapReg)
4569 .addUse(GR.getSPIRVTypeID(OpType))
4570 .addImm(static_cast<uint32_t>(SPIRV::Opcode::Bitcast))
4571 .addUse(OpReg);
4572 GR.add(OpDefine, MIB);
4573 MIB.constrainAllUses(TII, TRI, RBI);
4574 }
4575 return true;
4576}
4577
4578bool SPIRVInstructionSelector::selectDerivativeInst(
4579 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
4580 const unsigned DPdOpCode) const {
4581 // TODO: This should check specifically for Fragment Execution Model, but STI
4582 // doesn't provide that information yet. See #167562
4583 errorIfInstrOutsideShader(I);
4584
4585 // If the arg/result types are half then we need to wrap the instr in
4586 // conversions to float
4587 // This case occurs because a half arg/result is legal in HLSL but not spirv.
4588 Register SrcReg = I.getOperand(2).getReg();
4589 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(SrcReg);
4590 unsigned BitWidth = std::min(GR.getScalarOrVectorBitWidth(SrcType),
4591 GR.getScalarOrVectorBitWidth(ResType));
4592 if (BitWidth == 32)
4593 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DPdOpCode))
4594 .addDef(ResVReg)
4595 .addUse(GR.getSPIRVTypeID(ResType))
4596 .addUse(I.getOperand(2).getReg());
4597
4598 MachineIRBuilder MIRBuilder(I);
4599 unsigned componentCount = GR.getScalarOrVectorComponentCount(SrcType);
4600 SPIRVTypeInst F32ConvertTy = GR.getOrCreateSPIRVFloatType(32, I, TII);
4601 if (componentCount != 1)
4602 F32ConvertTy = GR.getOrCreateSPIRVVectorType(F32ConvertTy, componentCount,
4603 MIRBuilder, false);
4604
4605 const TargetRegisterClass *RegClass = GR.getRegClass(SrcType);
4606 Register ConvertToVReg = MRI->createVirtualRegister(RegClass);
4607 Register DpdOpVReg = MRI->createVirtualRegister(RegClass);
4608
4609 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFConvert))
4610 .addDef(ConvertToVReg)
4611 .addUse(GR.getSPIRVTypeID(F32ConvertTy))
4612 .addUse(SrcReg)
4613 .constrainAllUses(TII, TRI, RBI);
4614 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DPdOpCode))
4615 .addDef(DpdOpVReg)
4616 .addUse(GR.getSPIRVTypeID(F32ConvertTy))
4617 .addUse(ConvertToVReg)
4618 .constrainAllUses(TII, TRI, RBI);
4619 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFConvert))
4620 .addDef(ResVReg)
4621 .addUse(GR.getSPIRVTypeID(ResType))
4622 .addUse(DpdOpVReg)
4623 .constrainAllUses(TII, TRI, RBI);
4624 return true;
4625}
4626
4627bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
4628 SPIRVTypeInst ResType,
4629 MachineInstr &I) const {
4630 MachineBasicBlock &BB = *I.getParent();
4631 Intrinsic::ID IID = cast<GIntrinsic>(I).getIntrinsicID();
4632 switch (IID) {
4633 case Intrinsic::spv_load:
4634 return selectLoad(ResVReg, ResType, I);
4635 case Intrinsic::spv_atomic_load:
4636 return selectAtomicLoad(ResVReg, ResType, I);
4637 case Intrinsic::spv_store:
4638 return selectStore(I);
4639 case Intrinsic::spv_atomic_store:
4640 return selectAtomicStore(I);
4641 case Intrinsic::spv_extractv:
4642 return selectExtractVal(ResVReg, ResType, I);
4643 case Intrinsic::spv_insertv:
4644 return selectInsertVal(ResVReg, ResType, I);
4645 case Intrinsic::spv_extractelt:
4646 return selectExtractElt(ResVReg, ResType, I);
4647 case Intrinsic::spv_insertelt:
4648 return selectInsertElt(ResVReg, ResType, I);
4649 case Intrinsic::spv_gep:
4650 return selectGEP(ResVReg, ResType, I);
4651 case Intrinsic::spv_bitcast: {
4652 Register OpReg = I.getOperand(2).getReg();
4653 SPIRVTypeInst OpType =
4654 OpReg.isValid() ? GR.getSPIRVTypeForVReg(OpReg) : nullptr;
4655 if (!GR.isBitcastCompatible(ResType, OpType))
4656 report_fatal_error("incompatible result and operand types in a bitcast");
4657 return selectOpWithSrcs(ResVReg, ResType, I, {OpReg}, SPIRV::OpBitcast);
4658 }
4659 case Intrinsic::spv_unref_global:
4660 case Intrinsic::spv_init_global: {
4661 MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());
4662 MachineInstr *Init = I.getNumExplicitOperands() > 2
4663 ? MRI->getVRegDef(I.getOperand(2).getReg())
4664 : nullptr;
4665 assert(MI);
4666 Register GVarVReg = MI->getOperand(0).getReg();
4667 if (!selectGlobalValue(GVarVReg, *MI, Init))
4668 return false;
4669 // We violate SSA form by inserting OpVariable and still having a gMIR
4670 // instruction %vreg = G_GLOBAL_VALUE @gvar. We need to fix this by erasing
4671 // the duplicated definition.
4672 if (MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
4674 MI->eraseFromParent();
4675 }
4676 return true;
4677 }
4678 case Intrinsic::spv_undef: {
4679 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
4680 .addDef(ResVReg)
4681 .addUse(GR.getSPIRVTypeID(ResType));
4682 MIB.constrainAllUses(TII, TRI, RBI);
4683 return true;
4684 }
4685 case Intrinsic::spv_named_boolean_spec_constant: {
4686 auto Opcode = I.getOperand(3).getImm() ? SPIRV::OpSpecConstantTrue
4687 : SPIRV::OpSpecConstantFalse;
4688
4689 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
4690 .addDef(I.getOperand(0).getReg())
4691 .addUse(GR.getSPIRVTypeID(ResType));
4692 MIB.constrainAllUses(TII, TRI, RBI);
4693 unsigned SpecId = I.getOperand(2).getImm();
4694 buildOpDecorate(I.getOperand(0).getReg(), *++MIB->getIterator(), TII,
4695 SPIRV::Decoration::SpecId, {SpecId});
4696
4697 return true;
4698 }
4699 case Intrinsic::spv_const_composite: {
4700 // If no values are attached, the composite is null constant.
4701 bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
4702 SmallVector<Register> CompositeArgs;
4703 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
4704
4705 // skip type MD node we already used when generated assign.type for this
4706 if (!IsNull) {
4707 if (!wrapIntoSpecConstantOp(I, CompositeArgs))
4708 return false;
4709 std::function<bool(Register)> HasSpecConstOperand =
4710 [&](Register Reg) -> bool {
4711 MachineInstr *Def = MRI->getVRegDef(Reg);
4712 if (!Def)
4713 return false;
4714 if (!isConstReg(MRI, Def))
4715 return true;
4716 // Recurse into not-yet-selected spv_const_composite intrinsics
4717 // to detect transitive spec constant operands.
4718 if (isSpvIntrinsic(*Def, Intrinsic::spv_const_composite)) {
4719 for (unsigned J = Def->getNumExplicitDefs() + 1;
4720 J < Def->getNumExplicitOperands(); ++J) {
4721 if (Def->getOperand(J).isReg() &&
4722 HasSpecConstOperand(Def->getOperand(J).getReg()))
4723 return true;
4724 }
4725 }
4726 return false;
4727 };
4728 bool HasSpecConst = llvm::any_of(CompositeArgs, HasSpecConstOperand);
4729 unsigned CompositeOpc = HasSpecConst ? SPIRV::OpSpecConstantComposite
4730 : SPIRV::OpConstantComposite;
4731 unsigned ContinuedOpc = HasSpecConst
4732 ? SPIRV::OpSpecConstantCompositeContinuedINTEL
4733 : SPIRV::OpConstantCompositeContinuedINTEL;
4734 MachineIRBuilder MIR(I);
4735 SmallVector<MachineInstr *, 4> Instructions = createContinuedInstructions(
4736 MIR, CompositeOpc, 3, ContinuedOpc, CompositeArgs, ResVReg,
4737 GR.getSPIRVTypeID(ResType));
4738 for (auto *Instr : Instructions) {
4739 Instr->setDebugLoc(I.getDebugLoc());
4741 }
4742 return true;
4743 } else {
4744 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
4745 .addDef(ResVReg)
4746 .addUse(GR.getSPIRVTypeID(ResType));
4747 MIB.constrainAllUses(TII, TRI, RBI);
4748 return true;
4749 }
4750 }
4751 case Intrinsic::spv_assign_name: {
4752 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName));
4753 MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg());
4754 for (unsigned i = I.getNumExplicitDefs() + 2;
4755 i < I.getNumExplicitOperands(); ++i) {
4756 MIB.addImm(I.getOperand(i).getImm());
4757 }
4758 MIB.constrainAllUses(TII, TRI, RBI);
4759 return true;
4760 }
4761 case Intrinsic::spv_switch: {
4762 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch));
4763 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
4764 if (I.getOperand(i).isReg())
4765 MIB.addReg(I.getOperand(i).getReg());
4766 else if (I.getOperand(i).isCImm())
4767 addNumImm(I.getOperand(i).getCImm()->getValue(), MIB);
4768 else if (I.getOperand(i).isMBB())
4769 MIB.addMBB(I.getOperand(i).getMBB());
4770 else
4771 llvm_unreachable("Unexpected OpSwitch operand");
4772 }
4773 MIB.constrainAllUses(TII, TRI, RBI);
4774 return true;
4775 }
4776 case Intrinsic::spv_loop_merge: {
4777 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopMerge));
4778 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
4779 if (I.getOperand(i).isMBB())
4780 MIB.addMBB(I.getOperand(i).getMBB());
4781 else
4782 MIB.addImm(foldImm(I.getOperand(i), MRI));
4783 }
4784 MIB.constrainAllUses(TII, TRI, RBI);
4785 return true;
4786 }
4787 case Intrinsic::spv_loop_control_intel: {
4788 auto MIB =
4789 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopControlINTEL));
4790 for (unsigned J = 1; J < I.getNumExplicitOperands(); ++J)
4791 MIB.addImm(foldImm(I.getOperand(J), MRI));
4792 MIB.constrainAllUses(TII, TRI, RBI);
4793 return true;
4794 }
4795 case Intrinsic::spv_selection_merge: {
4796 auto MIB =
4797 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSelectionMerge));
4798 assert(I.getOperand(1).isMBB() &&
4799 "operand 1 to spv_selection_merge must be a basic block");
4800 MIB.addMBB(I.getOperand(1).getMBB());
4801 MIB.addImm(getSelectionOperandForImm(I.getOperand(2).getImm()));
4802 MIB.constrainAllUses(TII, TRI, RBI);
4803 return true;
4804 }
4805 case Intrinsic::spv_cmpxchg:
4806 return selectAtomicCmpXchg(ResVReg, ResType, I);
4807 case Intrinsic::spv_unreachable:
4808 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUnreachable))
4809 .constrainAllUses(TII, TRI, RBI);
4810 return true;
4811 case Intrinsic::spv_abort:
4812 return selectAbort(I);
4813 case Intrinsic::spv_alloca:
4814 return selectFrameIndex(ResVReg, ResType, I);
4815 case Intrinsic::spv_alloca_array:
4816 return selectAllocaArray(ResVReg, ResType, I);
4817 case Intrinsic::spv_assume:
4818 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
4819 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAssumeTrueKHR))
4820 .addUse(I.getOperand(1).getReg())
4821 .constrainAllUses(TII, TRI, RBI);
4822 return true;
4823 }
4824 break;
4825 case Intrinsic::spv_expect:
4826 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
4827 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExpectKHR))
4828 .addDef(ResVReg)
4829 .addUse(GR.getSPIRVTypeID(ResType))
4830 .addUse(I.getOperand(2).getReg())
4831 .addUse(I.getOperand(3).getReg())
4832 .constrainAllUses(TII, TRI, RBI);
4833 return true;
4834 }
4835 break;
4836 case Intrinsic::arithmetic_fence:
4837 if (STI.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence)) {
4838 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpArithmeticFenceEXT))
4839 .addDef(ResVReg)
4840 .addUse(GR.getSPIRVTypeID(ResType))
4841 .addUse(I.getOperand(2).getReg())
4842 .constrainAllUses(TII, TRI, RBI);
4843 return true;
4844 } else
4845 return BuildCOPY(ResVReg, I.getOperand(2).getReg(), I);
4846 break;
4847 case Intrinsic::spv_thread_id:
4848 // The HLSL SV_DispatchThreadID semantic is lowered to llvm.spv.thread.id
4849 // intrinsic in LLVM IR for SPIR-V backend.
4850 //
4851 // In SPIR-V backend, llvm.spv.thread.id is now correctly translated to a
4852 // `GlobalInvocationId` builtin variable
4853 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalInvocationId, ResVReg,
4854 ResType, I);
4855 case Intrinsic::spv_thread_id_in_group:
4856 // The HLSL SV_GroupThreadId semantic is lowered to
4857 // llvm.spv.thread.id.in.group intrinsic in LLVM IR for SPIR-V backend.
4858 //
4859 // In SPIR-V backend, llvm.spv.thread.id.in.group is now correctly
4860 // translated to a `LocalInvocationId` builtin variable
4861 return loadVec3BuiltinInputID(SPIRV::BuiltIn::LocalInvocationId, ResVReg,
4862 ResType, I);
4863 case Intrinsic::spv_group_id:
4864 // The HLSL SV_GroupId semantic is lowered to
4865 // llvm.spv.group.id intrinsic in LLVM IR for SPIR-V backend.
4866 //
4867 // In SPIR-V backend, llvm.spv.group.id is now translated to a `WorkgroupId`
4868 // builtin variable
4869 return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupId, ResVReg, ResType,
4870 I);
4871 case Intrinsic::spv_flattened_thread_id_in_group:
4872 // The HLSL SV_GroupIndex semantic is lowered to
4873 // llvm.spv.flattened.thread.id.in.group() intrinsic in LLVM IR for SPIR-V
4874 // backend.
4875 //
4876 // In SPIR-V backend, llvm.spv.flattened.thread.id.in.group is translated to
4877 // a `LocalInvocationIndex` builtin variable
4878 return loadBuiltinInputID(SPIRV::BuiltIn::LocalInvocationIndex, ResVReg,
4879 ResType, I);
4880 case Intrinsic::spv_workgroup_size:
4881 return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupSize, ResVReg,
4882 ResType, I);
4883 case Intrinsic::spv_global_size:
4884 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalSize, ResVReg, ResType,
4885 I);
4886 case Intrinsic::spv_global_offset:
4887 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalOffset, ResVReg,
4888 ResType, I);
4889 case Intrinsic::spv_num_workgroups:
4890 return loadVec3BuiltinInputID(SPIRV::BuiltIn::NumWorkgroups, ResVReg,
4891 ResType, I);
4892 case Intrinsic::spv_subgroup_size:
4893 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupSize, ResVReg, ResType,
4894 I);
4895 case Intrinsic::spv_num_subgroups:
4896 return loadBuiltinInputID(SPIRV::BuiltIn::NumSubgroups, ResVReg, ResType,
4897 I);
4898 case Intrinsic::spv_subgroup_id:
4899 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupId, ResVReg, ResType, I);
4900 case Intrinsic::spv_subgroup_local_invocation_id:
4901 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupLocalInvocationId,
4902 ResVReg, ResType, I);
4903 case Intrinsic::spv_subgroup_max_size:
4904 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupMaxSize, ResVReg, ResType,
4905 I);
4906 case Intrinsic::spv_fdot:
4907 return selectFloatDot(ResVReg, ResType, I);
4908 case Intrinsic::spv_udot:
4909 case Intrinsic::spv_sdot:
4910 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
4911 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
4912 return selectIntegerDot(ResVReg, ResType, I,
4913 /*Signed=*/IID == Intrinsic::spv_sdot);
4914 return selectIntegerDotExpansion(ResVReg, ResType, I);
4915 case Intrinsic::spv_dot4add_i8packed:
4916 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
4917 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
4918 return selectDot4AddPacked<true>(ResVReg, ResType, I);
4919 return selectDot4AddPackedExpansion<true>(ResVReg, ResType, I);
4920 case Intrinsic::spv_dot4add_u8packed:
4921 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
4922 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
4923 return selectDot4AddPacked<false>(ResVReg, ResType, I);
4924 return selectDot4AddPackedExpansion<false>(ResVReg, ResType, I);
4925 case Intrinsic::spv_all:
4926 return selectAll(ResVReg, ResType, I);
4927 case Intrinsic::spv_any:
4928 return selectAny(ResVReg, ResType, I);
4929 case Intrinsic::spv_cross:
4930 return selectExtInst(ResVReg, ResType, I, CL::cross, GL::Cross);
4931 case Intrinsic::spv_distance:
4932 return selectExtInst(ResVReg, ResType, I, CL::distance, GL::Distance);
4933 case Intrinsic::spv_lerp:
4934 return selectExtInst(ResVReg, ResType, I, CL::mix, GL::FMix);
4935 case Intrinsic::spv_length:
4936 return selectExtInst(ResVReg, ResType, I, CL::length, GL::Length);
4937 case Intrinsic::spv_degrees:
4938 return selectExtInst(ResVReg, ResType, I, CL::degrees, GL::Degrees);
4939 case Intrinsic::spv_faceforward:
4940 return selectExtInst(ResVReg, ResType, I, GL::FaceForward);
4941 case Intrinsic::spv_frac:
4942 return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
4943 case Intrinsic::spv_isinf:
4944 return selectOpIsInf(ResVReg, ResType, I);
4945 case Intrinsic::spv_isnan:
4946 return selectOpIsNan(ResVReg, ResType, I);
4947 case Intrinsic::spv_normalize:
4948 return selectExtInst(ResVReg, ResType, I, CL::normalize, GL::Normalize);
4949 case Intrinsic::spv_refract:
4950 return selectExtInst(ResVReg, ResType, I, GL::Refract);
4951 case Intrinsic::spv_reflect:
4952 return selectExtInst(ResVReg, ResType, I, GL::Reflect);
4953 case Intrinsic::spv_rsqrt:
4954 return selectExtInst(ResVReg, ResType, I, CL::rsqrt, GL::InverseSqrt);
4955 case Intrinsic::spv_sign:
4956 return selectSign(ResVReg, ResType, I);
4957 case Intrinsic::spv_smoothstep:
4958 return selectExtInst(ResVReg, ResType, I, CL::smoothstep, GL::SmoothStep);
4959 case Intrinsic::spv_firstbituhigh: // There is no CL equivalent of FindUMsb
4960 return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/false);
4961 case Intrinsic::spv_firstbitshigh: // There is no CL equivalent of FindSMsb
4962 return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/true);
4963 case Intrinsic::spv_firstbitlow: // There is no CL equivlent of FindILsb
4964 return selectFirstBitLow(ResVReg, ResType, I);
4965 case Intrinsic::spv_all_memory_barrier:
4966 return selectBarrierInst(I, SPIRV::Scope::Device,
4967 SPIRV::MemorySemantics::UniformMemory |
4968 SPIRV::MemorySemantics::ImageMemory |
4969 SPIRV::MemorySemantics::WorkgroupMemory,
4970 /*WithGroupSync*/ false);
4971 case Intrinsic::spv_all_memory_barrier_with_group_sync:
4972 return selectBarrierInst(I, SPIRV::Scope::Device,
4973 SPIRV::MemorySemantics::UniformMemory |
4974 SPIRV::MemorySemantics::ImageMemory |
4975 SPIRV::MemorySemantics::WorkgroupMemory,
4976 /*WithGroupSync*/ true);
4977 case Intrinsic::spv_device_memory_barrier:
4978 return selectBarrierInst(I, SPIRV::Scope::Device,
4979 SPIRV::MemorySemantics::UniformMemory |
4980 SPIRV::MemorySemantics::ImageMemory,
4981 /*WithGroupSync*/ false);
4982 case Intrinsic::spv_device_memory_barrier_with_group_sync:
4983 return selectBarrierInst(I, SPIRV::Scope::Device,
4984 SPIRV::MemorySemantics::UniformMemory |
4985 SPIRV::MemorySemantics::ImageMemory,
4986 /*WithGroupSync*/ true);
4987 case Intrinsic::spv_group_memory_barrier:
4988 return selectBarrierInst(I, SPIRV::Scope::Workgroup,
4989 SPIRV::MemorySemantics::WorkgroupMemory,
4990 /*WithGroupSync*/ false);
4991 case Intrinsic::spv_group_memory_barrier_with_group_sync:
4992 return selectBarrierInst(I, SPIRV::Scope::Workgroup,
4993 SPIRV::MemorySemantics::WorkgroupMemory,
4994 /*WithGroupSync*/ true);
4995 case Intrinsic::spv_generic_cast_to_ptr_explicit: {
4996 Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 1).getReg();
4997 SPIRV::StorageClass::StorageClass ResSC =
4998 GR.getPointerStorageClass(ResType);
4999 if (!isGenericCastablePtr(ResSC))
5000 report_fatal_error("The target storage class is not castable from the "
5001 "Generic storage class");
5002 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpGenericCastToPtrExplicit))
5003 .addDef(ResVReg)
5004 .addUse(GR.getSPIRVTypeID(ResType))
5005 .addUse(PtrReg)
5006 .addImm(ResSC)
5007 .constrainAllUses(TII, TRI, RBI);
5008 return true;
5009 }
5010 case Intrinsic::spv_lifetime_start:
5011 case Intrinsic::spv_lifetime_end: {
5012 unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
5013 : SPIRV::OpLifetimeStop;
5014 int64_t Size = I.getOperand(I.getNumExplicitDefs() + 1).getImm();
5015 Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 2).getReg();
5016 if (Size == -1)
5017 Size = 0;
5018 BuildMI(BB, I, I.getDebugLoc(), TII.get(Op))
5019 .addUse(PtrReg)
5020 .addImm(Size)
5021 .constrainAllUses(TII, TRI, RBI);
5022 return true;
5023 }
5024 case Intrinsic::spv_saturate:
5025 return selectSaturate(ResVReg, ResType, I);
5026 case Intrinsic::spv_nclamp:
5027 return selectExtInst(ResVReg, ResType, I, CL::fclamp, GL::NClamp);
5028 case Intrinsic::spv_uclamp:
5029 return selectExtInst(ResVReg, ResType, I, CL::u_clamp, GL::UClamp);
5030 case Intrinsic::spv_sclamp:
5031 return selectExtInst(ResVReg, ResType, I, CL::s_clamp, GL::SClamp);
5032 case Intrinsic::spv_subgroup_prefix_bit_count:
5033 return selectWavePrefixBitCount(ResVReg, ResType, I);
5034 case Intrinsic::spv_wave_active_countbits:
5035 return selectWaveActiveCountBits(ResVReg, ResType, I);
5036 case Intrinsic::spv_wave_all_equal:
5037 return selectWaveActiveAllEqual(ResVReg, ResType, I);
5038 case Intrinsic::spv_wave_all:
5039 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAll);
5040 case Intrinsic::spv_wave_any:
5041 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAny);
5042 case Intrinsic::spv_subgroup_ballot:
5043 return selectWaveOpInst(ResVReg, ResType, I,
5044 SPIRV::OpGroupNonUniformBallot);
5045 case Intrinsic::spv_wave_is_first_lane:
5046 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformElect);
5047 case Intrinsic::spv_wave_reduce_or:
5048 return selectWaveReduceOp(ResVReg, ResType, I,
5049 SPIRV::OpGroupNonUniformBitwiseOr);
5050 case Intrinsic::spv_wave_reduce_xor:
5051 return selectWaveReduceOp(ResVReg, ResType, I,
5052 SPIRV::OpGroupNonUniformBitwiseXor);
5053 case Intrinsic::spv_wave_reduce_and:
5054 return selectWaveReduceOp(ResVReg, ResType, I,
5055 SPIRV::OpGroupNonUniformBitwiseAnd);
5056 case Intrinsic::spv_wave_reduce_umax:
5057 return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ true);
5058 case Intrinsic::spv_wave_reduce_max:
5059 return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ false);
5060 case Intrinsic::spv_wave_reduce_umin:
5061 return selectWaveReduceMin(ResVReg, ResType, I, /*IsUnsigned*/ true);
5062 case Intrinsic::spv_wave_reduce_min:
5063 return selectWaveReduceMin(ResVReg, ResType, I, /*IsUnsigned*/ false);
5064 case Intrinsic::spv_wave_reduce_sum:
5065 return selectWaveReduceSum(ResVReg, ResType, I);
5066 case Intrinsic::spv_wave_product:
5067 return selectWaveReduceProduct(ResVReg, ResType, I);
5068 case Intrinsic::spv_wave_readlane:
5069 return selectWaveOpInst(ResVReg, ResType, I,
5070 SPIRV::OpGroupNonUniformShuffle);
5071 case Intrinsic::spv_wave_prefix_sum:
5072 return selectWaveExclusiveScanSum(ResVReg, ResType, I);
5073 case Intrinsic::spv_wave_prefix_product:
5074 return selectWaveExclusiveScanProduct(ResVReg, ResType, I);
5075 case Intrinsic::spv_quad_read_across_x: {
5076 return selectQuadSwap(ResVReg, ResType, I, /*Direction*/ 0);
5077 }
5078 case Intrinsic::spv_quad_read_across_y: {
5079 return selectQuadSwap(ResVReg, ResType, I, /*Direction*/ 1);
5080 }
5081 case Intrinsic::spv_step:
5082 return selectExtInst(ResVReg, ResType, I, CL::step, GL::Step);
5083 case Intrinsic::spv_radians:
5084 return selectExtInst(ResVReg, ResType, I, CL::radians, GL::Radians);
5085 // Discard intrinsics which we do not expect to actually represent code after
5086 // lowering or intrinsics which are not implemented but should not crash when
5087 // found in a customer's LLVM IR input.
5088 case Intrinsic::instrprof_increment:
5089 case Intrinsic::instrprof_increment_step:
5090 case Intrinsic::instrprof_value_profile:
5091 break;
5092 // Discard internal intrinsics.
5093 case Intrinsic::spv_value_md:
5094 break;
5095 case Intrinsic::spv_resource_handlefrombinding: {
5096 return selectHandleFromBinding(ResVReg, ResType, I);
5097 }
5098 case Intrinsic::spv_resource_counterhandlefrombinding:
5099 return selectCounterHandleFromBinding(ResVReg, ResType, I);
5100 case Intrinsic::spv_resource_updatecounter:
5101 return selectUpdateCounter(ResVReg, ResType, I);
5102 case Intrinsic::spv_resource_store_typedbuffer: {
5103 return selectImageWriteIntrinsic(I);
5104 }
5105 case Intrinsic::spv_resource_load_typedbuffer: {
5106 return selectReadImageIntrinsic(ResVReg, ResType, I);
5107 }
5108 case Intrinsic::spv_resource_load_level: {
5109 return selectLoadLevelIntrinsic(ResVReg, ResType, I);
5110 }
5111 case Intrinsic::spv_resource_getdimensions_x:
5112 case Intrinsic::spv_resource_getdimensions_xy:
5113 case Intrinsic::spv_resource_getdimensions_xyz: {
5114 return selectGetDimensionsIntrinsic(ResVReg, ResType, I);
5115 }
5116 case Intrinsic::spv_resource_getdimensions_levels_x:
5117 case Intrinsic::spv_resource_getdimensions_levels_xy:
5118 case Intrinsic::spv_resource_getdimensions_levels_xyz: {
5119 return selectGetDimensionsLevelsIntrinsic(ResVReg, ResType, I);
5120 }
5121 case Intrinsic::spv_resource_getdimensions_ms_xy:
5122 case Intrinsic::spv_resource_getdimensions_ms_xyz: {
5123 return selectGetDimensionsMSIntrinsic(ResVReg, ResType, I);
5124 }
5125 case Intrinsic::spv_resource_calculate_lod:
5126 case Intrinsic::spv_resource_calculate_lod_unclamped:
5127 return selectCalculateLodIntrinsic(ResVReg, ResType, I);
5128 case Intrinsic::spv_resource_sample:
5129 case Intrinsic::spv_resource_sample_clamp:
5130 return selectSampleBasicIntrinsic(ResVReg, ResType, I);
5131 case Intrinsic::spv_resource_samplebias:
5132 case Intrinsic::spv_resource_samplebias_clamp:
5133 return selectSampleBiasIntrinsic(ResVReg, ResType, I);
5134 case Intrinsic::spv_resource_samplegrad:
5135 case Intrinsic::spv_resource_samplegrad_clamp:
5136 return selectSampleGradIntrinsic(ResVReg, ResType, I);
5137 case Intrinsic::spv_resource_samplelevel:
5138 return selectSampleLevelIntrinsic(ResVReg, ResType, I);
5139 case Intrinsic::spv_resource_samplecmp:
5140 case Intrinsic::spv_resource_samplecmp_clamp:
5141 return selectSampleCmpIntrinsic(ResVReg, ResType, I);
5142 case Intrinsic::spv_resource_samplecmplevelzero:
5143 return selectSampleCmpLevelZeroIntrinsic(ResVReg, ResType, I);
5144 case Intrinsic::spv_resource_gather:
5145 case Intrinsic::spv_resource_gather_cmp:
5146 return selectGatherIntrinsic(ResVReg, ResType, I);
5147 case Intrinsic::spv_resource_getbasepointer:
5148 case Intrinsic::spv_resource_getpointer: {
5149 return selectResourceGetPointer(ResVReg, ResType, I);
5150 }
5151 case Intrinsic::spv_pushconstant_getpointer: {
5152 return selectPushConstantGetPointer(ResVReg, ResType, I);
5153 }
5154 case Intrinsic::spv_discard: {
5155 return selectDiscard(ResVReg, ResType, I);
5156 }
5157 case Intrinsic::spv_resource_nonuniformindex: {
5158 return selectResourceNonUniformIndex(ResVReg, ResType, I);
5159 }
5160 case Intrinsic::spv_unpackhalf2x16: {
5161 return selectExtInst(ResVReg, ResType, I, GL::UnpackHalf2x16);
5162 }
5163 case Intrinsic::spv_packhalf2x16: {
5164 return selectExtInst(ResVReg, ResType, I, GL::PackHalf2x16);
5165 }
5166 case Intrinsic::spv_ddx:
5167 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdx);
5168 case Intrinsic::spv_ddy:
5169 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdy);
5170 case Intrinsic::spv_ddx_coarse:
5171 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxCoarse);
5172 case Intrinsic::spv_ddy_coarse:
5173 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
5174 case Intrinsic::spv_ddx_fine:
5175 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxFine);
5176 case Intrinsic::spv_ddy_fine:
5177 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyFine);
5178 case Intrinsic::spv_fwidth:
5179 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpFwidth);
5180 case Intrinsic::spv_masked_gather:
5181 if (STI.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter))
5182 return selectMaskedGather(ResVReg, ResType, I);
5183 return diagnoseUnsupported(
5184 I, "llvm.masked.gather requires SPV_INTEL_masked_gather_scatter");
5185 case Intrinsic::spv_masked_scatter:
5186 if (STI.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter))
5187 return selectMaskedScatter(I);
5188 return diagnoseUnsupported(
5189 I, "llvm.masked.scatter requires SPV_INTEL_masked_gather_scatter");
5190 case Intrinsic::returnaddress:
5191 case Intrinsic::frameaddress: {
5192 // SPIR-V does not have a stack or return address. Lower to null.
5193 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
5194 .addDef(ResVReg)
5195 .addUse(GR.getSPIRVTypeID(ResType));
5196 MIB.constrainAllUses(TII, TRI, RBI);
5197 return true;
5198 }
5199 default: {
5200 std::string DiagMsg;
5201 raw_string_ostream OS(DiagMsg);
5202 I.print(OS);
5203 DiagMsg = "Intrinsic selection not implemented: " + DiagMsg;
5204 report_fatal_error(DiagMsg.c_str(), false);
5205 }
5206 }
5207 return true;
5208}
5209
5210bool SPIRVInstructionSelector::selectHandleFromBinding(Register &ResVReg,
5211 SPIRVTypeInst ResType,
5212 MachineInstr &I) const {
5213 // The images need to be loaded in the same basic block as their use. We defer
5214 // loading the image to the intrinsic that uses it.
5215 if (ResType->getOpcode() == SPIRV::OpTypeImage)
5216 return true;
5217
5218 return loadHandleBeforePosition(ResVReg, GR.getSPIRVTypeForVReg(ResVReg),
5219 *cast<GIntrinsic>(&I), I);
5220}
5221
5222bool SPIRVInstructionSelector::selectCounterHandleFromBinding(
5223 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5224 auto &Intr = cast<GIntrinsic>(I);
5225 assert(Intr.getIntrinsicID() ==
5226 Intrinsic::spv_resource_counterhandlefrombinding);
5227
5228 // Extract information from the intrinsic call.
5229 Register MainHandleReg = Intr.getOperand(2).getReg();
5230 auto *MainHandleDef = cast<GIntrinsic>(getVRegDef(*MRI, MainHandleReg));
5231 assert(MainHandleDef->getIntrinsicID() ==
5232 Intrinsic::spv_resource_handlefrombinding);
5233
5234 uint32_t Set = getIConstVal(Intr.getOperand(4).getReg(), MRI);
5235 uint32_t Binding = getIConstVal(Intr.getOperand(3).getReg(), MRI);
5236 uint32_t ArraySize = getIConstVal(MainHandleDef->getOperand(4).getReg(), MRI);
5237 Register IndexReg = MainHandleDef->getOperand(5).getReg();
5238 std::string CounterName =
5239 getStringValueFromReg(MainHandleDef->getOperand(6).getReg(), *MRI) +
5240 ".counter";
5241
5242 // Create the counter variable.
5243 MachineIRBuilder MIRBuilder(I);
5244 Register CounterVarReg =
5245 buildPointerToResource(SPIRVTypeInst(GR.getPointeeType(ResType)),
5246 GR.getPointerStorageClass(ResType), Set, Binding,
5247 ArraySize, IndexReg, CounterName, MIRBuilder);
5248
5249 return BuildCOPY(ResVReg, CounterVarReg, I);
5250}
5251
5252bool SPIRVInstructionSelector::selectUpdateCounter(Register &ResVReg,
5253 SPIRVTypeInst ResType,
5254 MachineInstr &I) const {
5255 auto &Intr = cast<GIntrinsic>(I);
5256 assert(Intr.getIntrinsicID() == Intrinsic::spv_resource_updatecounter);
5257
5258 Register CounterHandleReg = Intr.getOperand(2).getReg();
5259 Register IncrReg = Intr.getOperand(3).getReg();
5260
5261 // The counter handle is a pointer to the counter variable (which is a struct
5262 // containing an i32). We need to get a pointer to that i32 member to do the
5263 // atomic operation.
5264#ifndef NDEBUG
5265 SPIRVTypeInst CounterVarType = GR.getSPIRVTypeForVReg(CounterHandleReg);
5266 SPIRVTypeInst CounterVarPointeeType = GR.getPointeeType(CounterVarType);
5267 assert(CounterVarPointeeType &&
5268 CounterVarPointeeType->getOpcode() == SPIRV::OpTypeStruct &&
5269 "Counter variable must be a struct");
5270 assert(GR.getPointerStorageClass(CounterVarType) ==
5271 SPIRV::StorageClass::StorageBuffer &&
5272 "Counter variable must be in the storage buffer storage class");
5273 assert(CounterVarPointeeType->getNumOperands() == 2 &&
5274 "Counter variable must have exactly 1 member in the struct");
5275 const SPIRVTypeInst MemberType =
5276 GR.getSPIRVTypeForVReg(CounterVarPointeeType->getOperand(1).getReg());
5277 assert(MemberType->getOpcode() == SPIRV::OpTypeInt &&
5278 "Counter variable struct must have a single i32 member");
5279#endif
5280
5281 // The struct has a single i32 member.
5282 MachineIRBuilder MIRBuilder(I);
5283 const Type *LLVMIntType =
5284 Type::getInt32Ty(I.getMF()->getFunction().getContext());
5285
5286 SPIRVTypeInst IntPtrType = GR.getOrCreateSPIRVPointerType(
5287 LLVMIntType, MIRBuilder, SPIRV::StorageClass::StorageBuffer);
5288
5289 Register Zero = buildI32Constant(0, I);
5290
5291 Register PtrToCounter =
5292 MRI->createVirtualRegister(GR.getRegClass(IntPtrType));
5293 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain))
5294 .addDef(PtrToCounter)
5295 .addUse(GR.getSPIRVTypeID(IntPtrType))
5296 .addUse(CounterHandleReg)
5297 .addUse(Zero)
5298 .constrainAllUses(TII, TRI, RBI);
5299
5300 // For UAV/SSBO counters, the scope is Device. The counter variable is not
5301 // used as a flag. So the memory semantics can be None.
5302 Register Scope = buildI32Constant(SPIRV::Scope::Device, I);
5303 Register Semantics = buildI32Constant(SPIRV::MemorySemantics::None, I);
5304
5305 int64_t IncrVal = getIConstValSext(IncrReg, MRI);
5306 Register Incr = buildI32Constant(static_cast<uint32_t>(IncrVal), I);
5307
5308 Register AtomicRes = MRI->createVirtualRegister(GR.getRegClass(ResType));
5309 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAtomicIAdd))
5310 .addDef(AtomicRes)
5311 .addUse(GR.getSPIRVTypeID(ResType))
5312 .addUse(PtrToCounter)
5313 .addUse(Scope)
5314 .addUse(Semantics)
5315 .addUse(Incr)
5316 .constrainAllUses(TII, TRI, RBI);
5317 if (IncrVal >= 0) {
5318 return BuildCOPY(ResVReg, AtomicRes, I);
5319 }
5320
5321 // In HLSL, IncrementCounter returns the value *before* the increment, while
5322 // DecrementCounter returns the value *after* the decrement. Both are lowered
5323 // to the same atomic intrinsic which returns the value *before* the
5324 // operation. So for decrements (negative IncrVal), we must subtract the
5325 // increment value from the result to get the post-decrement value.
5326 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
5327 .addDef(ResVReg)
5328 .addUse(GR.getSPIRVTypeID(ResType))
5329 .addUse(AtomicRes)
5330 .addUse(Incr)
5331 .constrainAllUses(TII, TRI, RBI);
5332 return true;
5333}
5334bool SPIRVInstructionSelector::selectReadImageIntrinsic(Register &ResVReg,
5335 SPIRVTypeInst ResType,
5336 MachineInstr &I) const {
5337
5338 // If the load of the image is in a different basic block, then
5339 // this will generate invalid code. A proper solution is to move
5340 // the OpLoad from selectHandleFromBinding here. However, to do
5341 // that we will need to change the return type of the intrinsic.
5342 // We will do that when we can, but for now trying to move forward with other
5343 // issues.
5344 Register ImageReg = I.getOperand(2).getReg();
5345 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
5346 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
5347 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
5348 *ImageDef, I)) {
5349 return false;
5350 }
5351
5352 Register IdxReg = I.getOperand(3).getReg();
5353 DebugLoc Loc = I.getDebugLoc();
5354 MachineInstr &Pos = I;
5355
5356 return generateImageReadOrFetch(ResVReg, ResType, NewImageReg, IdxReg, Loc,
5357 Pos);
5358}
5359
5360bool SPIRVInstructionSelector::generateSampleImage(
5361 Register ResVReg, SPIRVTypeInst ResType, Register ImageReg,
5362 Register SamplerReg, Register CoordinateReg, const ImageOperands &ImOps,
5363 DebugLoc Loc, MachineInstr &Pos) const {
5364 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
5365 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
5366 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
5367 *ImageDef, Pos)) {
5368 return false;
5369 }
5370
5371 auto *SamplerDef = cast<GIntrinsic>(getVRegDef(*MRI, SamplerReg));
5372 Register NewSamplerReg =
5373 MRI->createVirtualRegister(MRI->getRegClass(SamplerReg));
5374 if (!loadHandleBeforePosition(NewSamplerReg,
5375 GR.getSPIRVTypeForVReg(SamplerReg), *SamplerDef,
5376 Pos)) {
5377 return false;
5378 }
5379
5380 MachineIRBuilder MIRBuilder(Pos);
5381 SPIRVTypeInst SampledImageType = GR.getOrCreateOpTypeSampledImage(
5382 GR.getSPIRVTypeForVReg(ImageReg), MIRBuilder);
5383 Register SampledImageReg =
5384 MRI->createVirtualRegister(GR.getRegClass(SampledImageType));
5385
5386 BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpSampledImage))
5387 .addDef(SampledImageReg)
5388 .addUse(GR.getSPIRVTypeID(SampledImageType))
5389 .addUse(NewImageReg)
5390 .addUse(NewSamplerReg)
5391 .constrainAllUses(TII, TRI, RBI);
5392
5393 bool IsExplicitLod = ImOps.GradX.has_value() || ImOps.GradY.has_value() ||
5394 ImOps.Lod.has_value();
5395 unsigned Opcode = IsExplicitLod ? SPIRV::OpImageSampleExplicitLod
5396 : SPIRV::OpImageSampleImplicitLod;
5397 if (ImOps.Compare)
5398 Opcode = IsExplicitLod ? SPIRV::OpImageSampleDrefExplicitLod
5399 : SPIRV::OpImageSampleDrefImplicitLod;
5400
5401 auto MIB = BuildMI(*Pos.getParent(), Pos, Loc, TII.get(Opcode))
5402 .addDef(ResVReg)
5403 .addUse(GR.getSPIRVTypeID(ResType))
5404 .addUse(SampledImageReg)
5405 .addUse(CoordinateReg);
5406
5407 if (ImOps.Compare)
5408 MIB.addUse(*ImOps.Compare);
5409
5410 uint32_t ImageOperands = 0;
5411 if (ImOps.Bias)
5412 ImageOperands |= SPIRV::ImageOperand::Bias;
5413 if (ImOps.Lod)
5414 ImageOperands |= SPIRV::ImageOperand::Lod;
5415 if (ImOps.GradX && ImOps.GradY)
5416 ImageOperands |= SPIRV::ImageOperand::Grad;
5417 if (ImOps.Offset && !isScalarOrVectorIntConstantZero(*ImOps.Offset)) {
5418 if (isConstReg(MRI, *ImOps.Offset))
5419 ImageOperands |= SPIRV::ImageOperand::ConstOffset;
5420 else {
5421 Pos.emitGenericError(
5422 "Non-constant offsets are not supported in sample instructions.");
5423 }
5424 }
5425 if (ImOps.MinLod)
5426 ImageOperands |= SPIRV::ImageOperand::MinLod;
5427
5428 if (ImageOperands != 0) {
5429 MIB.addImm(ImageOperands);
5430 if (ImageOperands & SPIRV::ImageOperand::Bias)
5431 MIB.addUse(*ImOps.Bias);
5432 if (ImageOperands & SPIRV::ImageOperand::Lod)
5433 MIB.addUse(*ImOps.Lod);
5434 if (ImageOperands & SPIRV::ImageOperand::Grad) {
5435 MIB.addUse(*ImOps.GradX);
5436 MIB.addUse(*ImOps.GradY);
5437 }
5438 if (ImageOperands &
5439 (SPIRV::ImageOperand::ConstOffset | SPIRV::ImageOperand::Offset))
5440 MIB.addUse(*ImOps.Offset);
5441 if (ImageOperands & SPIRV::ImageOperand::MinLod)
5442 MIB.addUse(*ImOps.MinLod);
5443 }
5444
5445 MIB.constrainAllUses(TII, TRI, RBI);
5446 return true;
5447}
5448
5449bool SPIRVInstructionSelector::selectImageQuerySize(
5450 Register ImageReg, Register &ResVReg, MachineInstr &I,
5451 std::optional<Register> LodReg) const {
5452 unsigned Opcode =
5453 LodReg ? SPIRV::OpImageQuerySizeLod : SPIRV::OpImageQuerySize;
5454 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(ImageReg);
5455 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
5456 "ImageReg is not an image type.");
5457
5458 auto Dim = static_cast<SPIRV::Dim::Dim>(ImageType->getOperand(2).getImm());
5459 bool IsArray = ImageType->getOperand(4).getImm() != 0;
5460 unsigned NumComponents = 0;
5461 switch (Dim) {
5462 case SPIRV::Dim::DIM_1D:
5463 case SPIRV::Dim::DIM_Buffer:
5464 NumComponents = IsArray ? 2 : 1;
5465 break;
5466 case SPIRV::Dim::DIM_2D:
5467 case SPIRV::Dim::DIM_Cube:
5468 case SPIRV::Dim::DIM_Rect:
5469 NumComponents = IsArray ? 3 : 2;
5470 break;
5471 case SPIRV::Dim::DIM_3D:
5472 NumComponents = 3;
5473 break;
5474 default:
5475 I.emitGenericError("Unsupported image dimension for OpImageQuerySize.");
5476 return false;
5477 }
5478
5479 SPIRVTypeInst I32Ty = GR.getOrCreateSPIRVIntegerType(32, I, TII);
5480 SPIRVTypeInst ResType =
5481 NumComponents == 1
5482 ? I32Ty
5483 : GR.getOrCreateSPIRVVectorType(I32Ty, NumComponents, I, TII);
5484
5485 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
5486 .addDef(ResVReg)
5487 .addUse(GR.getSPIRVTypeID(ResType))
5488 .addUse(ImageReg);
5489 if (LodReg)
5490 MIB.addUse(*LodReg);
5491 MIB.constrainAllUses(TII, TRI, RBI);
5492 return true;
5493}
5494
5495bool SPIRVInstructionSelector::selectGetDimensionsIntrinsic(
5496 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5497 Register ImageReg = I.getOperand(2).getReg();
5498 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
5499 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
5500 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
5501 *ImageDef, I)) {
5502 return false;
5503 }
5504 return selectImageQuerySize(NewImageReg, ResVReg, I);
5505}
5506
5507bool SPIRVInstructionSelector::selectGetDimensionsLevelsIntrinsic(
5508 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5509 Register ImageReg = I.getOperand(2).getReg();
5510 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
5511 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
5512 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
5513 *ImageDef, I)) {
5514 return false;
5515 }
5516
5517 Register SizeReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
5518 Register LodReg = I.getOperand(3).getReg();
5519
5520 assert(GR.getSPIRVTypeForVReg(NewImageReg)->getOperand(6).getImm() == 1 &&
5521 "OpImageQuerySizeLod and OpImageQueryLevels require a sampled image");
5522
5523 if (!selectImageQuerySize(NewImageReg, SizeReg, I, LodReg)) {
5524 return false;
5525 }
5526
5527 SPIRVTypeInst I32Ty = GR.getOrCreateSPIRVIntegerType(32, I, TII);
5528 Register LevelsReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
5529 BuildMI(*I.getParent(), I, I.getDebugLoc(),
5530 TII.get(SPIRV::OpImageQueryLevels))
5531 .addDef(LevelsReg)
5532 .addUse(GR.getSPIRVTypeID(I32Ty))
5533 .addUse(NewImageReg)
5534 .constrainAllUses(TII, TRI, RBI);
5535
5536 BuildMI(*I.getParent(), I, I.getDebugLoc(),
5537 TII.get(SPIRV::OpCompositeConstruct))
5538 .addDef(ResVReg)
5539 .addUse(GR.getSPIRVTypeID(ResType))
5540 .addUse(SizeReg)
5541 .addUse(LevelsReg)
5542 .constrainAllUses(TII, TRI, RBI);
5543
5544 return true;
5545}
5546
5547bool SPIRVInstructionSelector::selectGetDimensionsMSIntrinsic(
5548 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5549 Register ImageReg = I.getOperand(2).getReg();
5550 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
5551 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
5552 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
5553 *ImageDef, I)) {
5554 return false;
5555 }
5556
5557 Register SizeReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
5558
5559 assert(GR.getSPIRVTypeForVReg(NewImageReg)->getOperand(5).getImm() == 1 &&
5560 "OpImageQuerySamples requires a multisampled image");
5561
5562 if (!selectImageQuerySize(NewImageReg, SizeReg, I)) {
5563 return false;
5564 }
5565
5566 Register SamplesReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
5567
5568 SPIRVTypeInst I32Ty = GR.getOrCreateSPIRVIntegerType(32, I, TII);
5569 BuildMI(*I.getParent(), I, I.getDebugLoc(),
5570 TII.get(SPIRV::OpImageQuerySamples))
5571 .addDef(SamplesReg)
5572 .addUse(GR.getSPIRVTypeID(I32Ty))
5573 .addUse(NewImageReg)
5574 .constrainAllUses(TII, TRI, RBI);
5575
5576 BuildMI(*I.getParent(), I, I.getDebugLoc(),
5577 TII.get(SPIRV::OpCompositeConstruct))
5578 .addDef(ResVReg)
5579 .addUse(GR.getSPIRVTypeID(ResType))
5580 .addUse(SizeReg)
5581 .addUse(SamplesReg)
5582 .constrainAllUses(TII, TRI, RBI);
5583
5584 return true;
5585}
5586
5587bool SPIRVInstructionSelector::selectCalculateLodIntrinsic(
5588 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5589 Register ImageReg = I.getOperand(2).getReg();
5590 Register SamplerReg = I.getOperand(3).getReg();
5591 Register CoordinateReg = I.getOperand(4).getReg();
5592
5593 auto *ImageDef = dyn_cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
5594 if (!ImageDef)
5595 return false;
5596 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
5597 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
5598 *ImageDef, I)) {
5599 return false;
5600 }
5601
5602 auto *SamplerDef = dyn_cast<GIntrinsic>(getVRegDef(*MRI, SamplerReg));
5603 if (!SamplerDef)
5604 return false;
5605 Register NewSamplerReg =
5606 MRI->createVirtualRegister(MRI->getRegClass(SamplerReg));
5607 if (!loadHandleBeforePosition(
5608 NewSamplerReg, GR.getSPIRVTypeForVReg(SamplerReg), *SamplerDef, I)) {
5609 return false;
5610 }
5611
5612 MachineIRBuilder MIRBuilder(I);
5613 SPIRVTypeInst SampledImageType = GR.getOrCreateOpTypeSampledImage(
5614 GR.getSPIRVTypeForVReg(ImageReg), MIRBuilder);
5615 Register SampledImageReg =
5616 MRI->createVirtualRegister(GR.getRegClass(SampledImageType));
5617
5618 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpSampledImage))
5619 .addDef(SampledImageReg)
5620 .addUse(GR.getSPIRVTypeID(SampledImageType))
5621 .addUse(NewImageReg)
5622 .addUse(NewSamplerReg)
5623 .constrainAllUses(TII, TRI, RBI);
5624
5625 SPIRVTypeInst Vec2Ty = GR.getOrCreateSPIRVVectorType(ResType, 2, I, TII);
5626 Register QueryResultReg = MRI->createVirtualRegister(GR.getRegClass(Vec2Ty));
5627
5628 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpImageQueryLod))
5629 .addDef(QueryResultReg)
5630 .addUse(GR.getSPIRVTypeID(Vec2Ty))
5631 .addUse(SampledImageReg)
5632 .addUse(CoordinateReg)
5633 .constrainAllUses(TII, TRI, RBI);
5634
5635 unsigned ExtractedIndex =
5636 cast<GIntrinsic>(I).getIntrinsicID() ==
5637 Intrinsic::spv_resource_calculate_lod_unclamped
5638 ? 1
5639 : 0;
5640
5641 MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
5642 TII.get(SPIRV::OpCompositeExtract))
5643 .addDef(ResVReg)
5644 .addUse(GR.getSPIRVTypeID(ResType))
5645 .addUse(QueryResultReg)
5646 .addImm(ExtractedIndex);
5647
5648 MIB.constrainAllUses(TII, TRI, RBI);
5649 return true;
5650}
5651
5652bool SPIRVInstructionSelector::selectSampleBasicIntrinsic(
5653 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5654 Register ImageReg = I.getOperand(2).getReg();
5655 Register SamplerReg = I.getOperand(3).getReg();
5656 Register CoordinateReg = I.getOperand(4).getReg();
5657 ImageOperands ImOps;
5658 if (I.getNumOperands() > 5)
5659 ImOps.Offset = I.getOperand(5).getReg();
5660 if (I.getNumOperands() > 6)
5661 ImOps.MinLod = I.getOperand(6).getReg();
5662 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
5663 CoordinateReg, ImOps, I.getDebugLoc(), I);
5664}
5665
5666bool SPIRVInstructionSelector::selectSampleBiasIntrinsic(
5667 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5668 Register ImageReg = I.getOperand(2).getReg();
5669 Register SamplerReg = I.getOperand(3).getReg();
5670 Register CoordinateReg = I.getOperand(4).getReg();
5671 ImageOperands ImOps;
5672 ImOps.Bias = I.getOperand(5).getReg();
5673 if (I.getNumOperands() > 6)
5674 ImOps.Offset = I.getOperand(6).getReg();
5675 if (I.getNumOperands() > 7)
5676 ImOps.MinLod = I.getOperand(7).getReg();
5677 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
5678 CoordinateReg, ImOps, I.getDebugLoc(), I);
5679}
5680
5681bool SPIRVInstructionSelector::selectSampleGradIntrinsic(
5682 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5683 Register ImageReg = I.getOperand(2).getReg();
5684 Register SamplerReg = I.getOperand(3).getReg();
5685 Register CoordinateReg = I.getOperand(4).getReg();
5686 ImageOperands ImOps;
5687 ImOps.GradX = I.getOperand(5).getReg();
5688 ImOps.GradY = I.getOperand(6).getReg();
5689 if (I.getNumOperands() > 7)
5690 ImOps.Offset = I.getOperand(7).getReg();
5691 if (I.getNumOperands() > 8)
5692 ImOps.MinLod = I.getOperand(8).getReg();
5693 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
5694 CoordinateReg, ImOps, I.getDebugLoc(), I);
5695}
5696
5697bool SPIRVInstructionSelector::selectSampleLevelIntrinsic(
5698 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5699 Register ImageReg = I.getOperand(2).getReg();
5700 Register SamplerReg = I.getOperand(3).getReg();
5701 Register CoordinateReg = I.getOperand(4).getReg();
5702 ImageOperands ImOps;
5703 ImOps.Lod = I.getOperand(5).getReg();
5704 if (I.getNumOperands() > 6)
5705 ImOps.Offset = I.getOperand(6).getReg();
5706 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
5707 CoordinateReg, ImOps, I.getDebugLoc(), I);
5708}
5709
5710bool SPIRVInstructionSelector::selectSampleCmpIntrinsic(Register &ResVReg,
5711 SPIRVTypeInst ResType,
5712 MachineInstr &I) const {
5713 Register ImageReg = I.getOperand(2).getReg();
5714 Register SamplerReg = I.getOperand(3).getReg();
5715 Register CoordinateReg = I.getOperand(4).getReg();
5716 ImageOperands ImOps;
5717 ImOps.Compare = I.getOperand(5).getReg();
5718 if (I.getNumOperands() > 6)
5719 ImOps.Offset = I.getOperand(6).getReg();
5720 if (I.getNumOperands() > 7)
5721 ImOps.MinLod = I.getOperand(7).getReg();
5722 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
5723 CoordinateReg, ImOps, I.getDebugLoc(), I);
5724}
5725
5726bool SPIRVInstructionSelector::selectLoadLevelIntrinsic(Register &ResVReg,
5727 SPIRVTypeInst ResType,
5728 MachineInstr &I) const {
5729 Register ImageReg = I.getOperand(2).getReg();
5730 Register CoordinateReg = I.getOperand(3).getReg();
5731 Register LodReg = I.getOperand(4).getReg();
5732
5733 ImageOperands ImOps;
5734 ImOps.Lod = LodReg;
5735 if (I.getNumOperands() > 5)
5736 ImOps.Offset = I.getOperand(5).getReg();
5737
5738 auto *ImageDef = dyn_cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
5739 if (!ImageDef)
5740 return false;
5741
5742 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
5743 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
5744 *ImageDef, I)) {
5745 return false;
5746 }
5747
5748 return generateImageReadOrFetch(ResVReg, ResType, NewImageReg, CoordinateReg,
5749 I.getDebugLoc(), I, &ImOps);
5750}
5751
5752bool SPIRVInstructionSelector::selectSampleCmpLevelZeroIntrinsic(
5753 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5754 Register ImageReg = I.getOperand(2).getReg();
5755 Register SamplerReg = I.getOperand(3).getReg();
5756 Register CoordinateReg = I.getOperand(4).getReg();
5757 ImageOperands ImOps;
5758 ImOps.Compare = I.getOperand(5).getReg();
5759 if (I.getNumOperands() > 6)
5760 ImOps.Offset = I.getOperand(6).getReg();
5761 SPIRVTypeInst FloatTy = GR.getOrCreateSPIRVFloatType(32, I, TII);
5762 ImOps.Lod = GR.getOrCreateConstFP(APFloat(0.0f), I, FloatTy, TII);
5763 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
5764 CoordinateReg, ImOps, I.getDebugLoc(), I);
5765}
5766
5767bool SPIRVInstructionSelector::selectGatherIntrinsic(Register &ResVReg,
5768 SPIRVTypeInst ResType,
5769 MachineInstr &I) const {
5770 Register ImageReg = I.getOperand(2).getReg();
5771 Register SamplerReg = I.getOperand(3).getReg();
5772 Register CoordinateReg = I.getOperand(4).getReg();
5773 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(ImageReg);
5774 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
5775 "ImageReg is not an image type.");
5776
5777 Register ComponentOrCompareReg;
5778 Register OffsetReg;
5779
5780 ComponentOrCompareReg = I.getOperand(5).getReg();
5781 OffsetReg = I.getOperand(6).getReg();
5782 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
5783 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
5784 if (!loadHandleBeforePosition(NewImageReg, ImageType, *ImageDef, I)) {
5785 return false;
5786 }
5787
5788 auto Dim = static_cast<SPIRV::Dim::Dim>(ImageType->getOperand(2).getImm());
5789 if (Dim != SPIRV::Dim::DIM_2D && Dim != SPIRV::Dim::DIM_Cube &&
5790 Dim != SPIRV::Dim::DIM_Rect) {
5791 I.emitGenericError(
5792 "Gather operations are only supported for 2D, Cube, and Rect images.");
5793 return false;
5794 }
5795
5796 auto *SamplerDef = cast<GIntrinsic>(getVRegDef(*MRI, SamplerReg));
5797 Register NewSamplerReg =
5798 MRI->createVirtualRegister(MRI->getRegClass(SamplerReg));
5799 if (!loadHandleBeforePosition(
5800 NewSamplerReg, GR.getSPIRVTypeForVReg(SamplerReg), *SamplerDef, I)) {
5801 return false;
5802 }
5803
5804 MachineIRBuilder MIRBuilder(I);
5805 SPIRVTypeInst SampledImageType =
5806 GR.getOrCreateOpTypeSampledImage(ImageType, MIRBuilder);
5807 Register SampledImageReg =
5808 MRI->createVirtualRegister(GR.getRegClass(SampledImageType));
5809
5810 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpSampledImage))
5811 .addDef(SampledImageReg)
5812 .addUse(GR.getSPIRVTypeID(SampledImageType))
5813 .addUse(NewImageReg)
5814 .addUse(NewSamplerReg)
5815 .constrainAllUses(TII, TRI, RBI);
5816
5817 auto IntrId = cast<GIntrinsic>(I).getIntrinsicID();
5818 bool IsGatherCmp = IntrId == Intrinsic::spv_resource_gather_cmp;
5819 unsigned Opcode =
5820 IsGatherCmp ? SPIRV::OpImageDrefGather : SPIRV::OpImageGather;
5821
5822 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
5823 .addDef(ResVReg)
5824 .addUse(GR.getSPIRVTypeID(ResType))
5825 .addUse(SampledImageReg)
5826 .addUse(CoordinateReg)
5827 .addUse(ComponentOrCompareReg);
5828
5829 uint32_t ImageOperands = 0;
5830 if (OffsetReg && !isScalarOrVectorIntConstantZero(OffsetReg)) {
5831 if (Dim == SPIRV::Dim::DIM_Cube) {
5832 I.emitGenericError(
5833 "Gather operations with offset are not supported for Cube images.");
5834 return false;
5835 }
5836 if (isConstReg(MRI, OffsetReg))
5837 ImageOperands |= SPIRV::ImageOperand::ConstOffset;
5838 else {
5839 ImageOperands |= SPIRV::ImageOperand::Offset;
5840 }
5841 }
5842
5843 if (ImageOperands != 0) {
5844 MIB.addImm(ImageOperands);
5845 if (ImageOperands &
5846 (SPIRV::ImageOperand::ConstOffset | SPIRV::ImageOperand::Offset))
5847 MIB.addUse(OffsetReg);
5848 }
5849
5850 MIB.constrainAllUses(TII, TRI, RBI);
5851 return true;
5852}
5853
5854bool SPIRVInstructionSelector::generateImageReadOrFetch(
5855 Register &ResVReg, SPIRVTypeInst ResType, Register ImageReg,
5856 Register IdxReg, DebugLoc Loc, MachineInstr &Pos,
5857 const ImageOperands *ImOps) const {
5858 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(ImageReg);
5859 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
5860 "ImageReg is not an image type.");
5861
5862 bool IsSignedInteger =
5863 sampledTypeIsSignedInteger(GR.getTypeForSPIRVType(ImageType));
5864 // Check if the "sampled" operand of the image type is 1.
5865 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpImageFetch
5866 auto SampledOp = ImageType->getOperand(6);
5867 bool IsFetch = (SampledOp.getImm() == 1);
5868
5869 auto AddOperands = [&](MachineInstrBuilder &MIB) {
5870 uint32_t ImageOperandsMask = 0;
5871 if (IsSignedInteger)
5872 ImageOperandsMask |= 0x1000; // SignExtend
5873
5874 if (IsFetch && ImOps) {
5875 if (ImOps->Lod)
5876 ImageOperandsMask |= SPIRV::ImageOperand::Lod;
5877 if (ImOps->Offset && !isScalarOrVectorIntConstantZero(*ImOps->Offset)) {
5878 if (isConstReg(MRI, *ImOps->Offset))
5879 ImageOperandsMask |= SPIRV::ImageOperand::ConstOffset;
5880 else
5881 ImageOperandsMask |= SPIRV::ImageOperand::Offset;
5882 }
5883 }
5884
5885 if (ImageOperandsMask != 0) {
5886 MIB.addImm(ImageOperandsMask);
5887 if (IsFetch && ImOps) {
5888 if (ImOps->Lod)
5889 MIB.addUse(*ImOps->Lod);
5890 if (ImOps->Offset &&
5891 (ImageOperandsMask &
5892 (SPIRV::ImageOperand::Offset | SPIRV::ImageOperand::ConstOffset)))
5893 MIB.addUse(*ImOps->Offset);
5894 }
5895 }
5896 };
5897
5898 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
5899 if (ResultSize == 4) {
5900 auto BMI =
5901 BuildMI(*Pos.getParent(), Pos, Loc,
5902 TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
5903 .addDef(ResVReg)
5904 .addUse(GR.getSPIRVTypeID(ResType))
5905 .addUse(ImageReg)
5906 .addUse(IdxReg);
5907
5908 AddOperands(BMI);
5909 BMI.constrainAllUses(TII, TRI, RBI);
5910 return true;
5911 }
5912
5913 SPIRVTypeInst ReadType = widenTypeToVec4(ResType, Pos);
5914 Register ReadReg = MRI->createVirtualRegister(GR.getRegClass(ReadType));
5915 auto BMI =
5916 BuildMI(*Pos.getParent(), Pos, Loc,
5917 TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
5918 .addDef(ReadReg)
5919 .addUse(GR.getSPIRVTypeID(ReadType))
5920 .addUse(ImageReg)
5921 .addUse(IdxReg);
5922 AddOperands(BMI);
5923 BMI.constrainAllUses(TII, TRI, RBI);
5924
5925 if (ResultSize == 1) {
5926 BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpCompositeExtract))
5927 .addDef(ResVReg)
5928 .addUse(GR.getSPIRVTypeID(ResType))
5929 .addUse(ReadReg)
5930 .addImm(0)
5931 .constrainAllUses(TII, TRI, RBI);
5932 return true;
5933 }
5934 return extractSubvector(ResVReg, ResType, ReadReg, Pos);
5935}
5936
5937bool SPIRVInstructionSelector::selectResourceGetPointer(Register &ResVReg,
5938 SPIRVTypeInst ResType,
5939 MachineInstr &I) const {
5940 Register ResourcePtr = I.getOperand(2).getReg();
5941 SPIRVTypeInst RegType = GR.getSPIRVTypeForVReg(ResourcePtr, I.getMF());
5942 if (RegType->getOpcode() == SPIRV::OpTypeImage) {
5943 // For texel buffers, the index into the image is part of the OpImageRead or
5944 // OpImageWrite instructions. So we will do nothing in this case. This
5945 // intrinsic will be combined with the load or store when selecting the load
5946 // or store.
5947 return true;
5948 }
5949
5950 assert(ResType->getOpcode() == SPIRV::OpTypePointer);
5951 MachineIRBuilder MIRBuilder(I);
5952
5953 Register ZeroReg =
5954 buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I);
5955 auto MIB =
5956 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain))
5957 .addDef(ResVReg)
5958 .addUse(GR.getSPIRVTypeID(ResType))
5959 .addUse(ResourcePtr)
5960 .addUse(ZeroReg);
5961
5962 if (I.getNumExplicitOperands() > 3) {
5963 Register IndexReg = I.getOperand(3).getReg();
5964 MIB.addUse(IndexReg);
5965 }
5966 MIB.constrainAllUses(TII, TRI, RBI);
5967 return true;
5968}
5969
5970bool SPIRVInstructionSelector::selectPushConstantGetPointer(
5971 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5972 MRI->replaceRegWith(ResVReg, I.getOperand(2).getReg());
5973 return true;
5974}
5975
5976bool SPIRVInstructionSelector::selectResourceNonUniformIndex(
5977 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
5978 Register ObjReg = I.getOperand(2).getReg();
5979 if (!BuildCOPY(ResVReg, ObjReg, I))
5980 return false;
5981
5982 buildOpDecorate(ResVReg, I, TII, SPIRV::Decoration::NonUniformEXT, {});
5983 // Check for the registers that use the index marked as non-uniform
5984 // and recursively mark them as non-uniform.
5985 // Per the spec, it's necessary that the final argument used for
5986 // load/store/sample/atomic must be decorated, so we need to propagate the
5987 // decoration through access chains and copies.
5988 // https://docs.vulkan.org/samples/latest/samples/extensions/descriptor_indexing/README.html#_when_to_use_non_uniform_indexing_qualifier
5989 decorateUsesAsNonUniform(ResVReg);
5990 return true;
5991}
5992
5993void SPIRVInstructionSelector::decorateUsesAsNonUniform(
5994 Register &NonUniformReg) const {
5995 llvm::SmallVector<Register> WorkList = {NonUniformReg};
5996 while (WorkList.size() > 0) {
5997 Register CurrentReg = WorkList.back();
5998 WorkList.pop_back();
5999
6000 bool IsDecorated = false;
6001 for (MachineInstr &Use : MRI->use_instructions(CurrentReg)) {
6002 if (Use.getOpcode() == SPIRV::OpDecorate &&
6003 Use.getOperand(1).getImm() == SPIRV::Decoration::NonUniformEXT) {
6004 IsDecorated = true;
6005 continue;
6006 }
6007 // Check if the instruction has the result register and add it to the
6008 // worklist.
6009 if (Use.getOperand(0).isReg() && Use.getOperand(0).isDef()) {
6010 Register ResultReg = Use.getOperand(0).getReg();
6011 if (ResultReg == CurrentReg)
6012 continue;
6013 WorkList.push_back(ResultReg);
6014 }
6015 }
6016
6017 if (!IsDecorated) {
6018 buildOpDecorate(CurrentReg, *MRI->getVRegDef(CurrentReg), TII,
6019 SPIRV::Decoration::NonUniformEXT, {});
6020 }
6021 }
6022}
6023
6024bool SPIRVInstructionSelector::extractSubvector(
6025 Register &ResVReg, SPIRVTypeInst ResType, Register &ReadReg,
6026 MachineInstr &InsertionPoint) const {
6027 SPIRVTypeInst InputType = GR.getResultType(ReadReg);
6028 [[maybe_unused]] uint64_t InputSize =
6029 GR.getScalarOrVectorComponentCount(InputType);
6030 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
6031 assert(InputSize > 1 && "The input must be a vector.");
6032 assert(ResultSize > 1 && "The result must be a vector.");
6033 assert(ResultSize < InputSize &&
6034 "Cannot extract more element than there are in the input.");
6035 SmallVector<Register> ComponentRegisters;
6036 SPIRVTypeInst ScalarType = GR.getScalarOrVectorComponentType(ResType);
6037 const TargetRegisterClass *ScalarRegClass = GR.getRegClass(ScalarType);
6038 for (uint64_t I = 0; I < ResultSize; I++) {
6039 Register ComponentReg = MRI->createVirtualRegister(ScalarRegClass);
6040 BuildMI(*InsertionPoint.getParent(), InsertionPoint,
6041 InsertionPoint.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
6042 .addDef(ComponentReg)
6043 .addUse(ScalarType->getOperand(0).getReg())
6044 .addUse(ReadReg)
6045 .addImm(I)
6046 .constrainAllUses(TII, TRI, RBI);
6047 ComponentRegisters.emplace_back(ComponentReg);
6048 }
6049
6050 MachineInstrBuilder MIB = BuildMI(*InsertionPoint.getParent(), InsertionPoint,
6051 InsertionPoint.getDebugLoc(),
6052 TII.get(SPIRV::OpCompositeConstruct))
6053 .addDef(ResVReg)
6054 .addUse(GR.getSPIRVTypeID(ResType));
6055
6056 for (Register ComponentReg : ComponentRegisters)
6057 MIB.addUse(ComponentReg);
6058 MIB.constrainAllUses(TII, TRI, RBI);
6059 return true;
6060}
6061
6062bool SPIRVInstructionSelector::selectImageWriteIntrinsic(
6063 MachineInstr &I) const {
6064 // If the load of the image is in a different basic block, then
6065 // this will generate invalid code. A proper solution is to move
6066 // the OpLoad from selectHandleFromBinding here. However, to do
6067 // that we will need to change the return type of the intrinsic.
6068 // We will do that when we can, but for now trying to move forward with other
6069 // issues.
6070 Register ImageReg = I.getOperand(1).getReg();
6071 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
6072 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
6073 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
6074 *ImageDef, I)) {
6075 return false;
6076 }
6077
6078 Register CoordinateReg = I.getOperand(2).getReg();
6079 Register DataReg = I.getOperand(3).getReg();
6080 assert(GR.getResultType(DataReg)->getOpcode() == SPIRV::OpTypeVector);
6082 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpImageWrite))
6083 .addUse(NewImageReg)
6084 .addUse(CoordinateReg)
6085 .addUse(DataReg)
6086 .constrainAllUses(TII, TRI, RBI);
6087 return true;
6088}
6089
6090Register SPIRVInstructionSelector::buildPointerToResource(
6091 SPIRVTypeInst SpirvResType, SPIRV::StorageClass::StorageClass SC,
6092 uint32_t Set, uint32_t Binding, uint32_t ArraySize, Register IndexReg,
6093 StringRef Name, MachineIRBuilder MIRBuilder) const {
6094 const Type *ResType = GR.getTypeForSPIRVType(SpirvResType);
6095 if (ArraySize == 1) {
6096 SPIRVTypeInst PtrType =
6097 GR.getOrCreateSPIRVPointerType(ResType, MIRBuilder, SC);
6098 assert(GR.getPointeeType(PtrType) == SpirvResType &&
6099 "SpirvResType did not have an explicit layout.");
6100 return GR.getOrCreateGlobalVariableWithBinding(PtrType, Set, Binding, Name,
6101 MIRBuilder);
6102 }
6103
6104 const Type *VarType = ArrayType::get(const_cast<Type *>(ResType), ArraySize);
6105 SPIRVTypeInst VarPointerType =
6106 GR.getOrCreateSPIRVPointerType(VarType, MIRBuilder, SC);
6108 VarPointerType, Set, Binding, Name, MIRBuilder);
6109
6110 SPIRVTypeInst ResPointerType =
6111 GR.getOrCreateSPIRVPointerType(ResType, MIRBuilder, SC);
6112 Register AcReg = MRI->createVirtualRegister(GR.getRegClass(ResPointerType));
6113
6114 MIRBuilder.buildInstr(SPIRV::OpAccessChain)
6115 .addDef(AcReg)
6116 .addUse(GR.getSPIRVTypeID(ResPointerType))
6117 .addUse(VarReg)
6118 .addUse(IndexReg);
6119
6120 return AcReg;
6121}
6122
6123bool SPIRVInstructionSelector::selectFirstBitSet16(
6124 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
6125 unsigned ExtendOpcode, unsigned BitSetOpcode) const {
6126 Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
6127 if (!selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()},
6128 ExtendOpcode))
6129 return false;
6130
6131 return selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode);
6132}
6133
6134bool SPIRVInstructionSelector::selectFirstBitSet32(
6135 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
6136 unsigned BitSetOpcode) const {
6137 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
6138 .addDef(ResVReg)
6139 .addUse(GR.getSPIRVTypeID(ResType))
6140 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
6141 .addImm(BitSetOpcode)
6142 .addUse(SrcReg)
6143 .constrainAllUses(TII, TRI, RBI);
6144 return true;
6145}
6146
6147bool SPIRVInstructionSelector::selectFirstBitSet64(
6148 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
6149 unsigned BitSetOpcode, bool SwapPrimarySide) const {
6150 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType);
6151 SPIRVTypeInst BaseType = GR.retrieveScalarOrVectorIntType(ResType);
6152 bool ZeroAsNull = !STI.isShader();
6153 Register ConstIntZero =
6154 GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull);
6155 Register ConstIntOne =
6156 GR.getOrCreateConstInt(1, I, BaseType, TII, ZeroAsNull);
6157
6158 // SPIRV doesn't support vectors with more than 4 components. Since the
6159 // algoritm below converts i64 -> i32x2 and i64x4 -> i32x8 it can only
6160 // operate on vectors with 2 or less components. When largers vectors are
6161 // seen. Split them, recurse, then recombine them.
6162 if (ComponentCount > 2) {
6163 auto Func = [this, SwapPrimarySide](Register ResVReg, SPIRVTypeInst ResType,
6164 MachineInstr &I, Register SrcReg,
6165 unsigned Opcode) -> bool {
6166 return this->selectFirstBitSet64(ResVReg, ResType, I, SrcReg, Opcode,
6167 SwapPrimarySide);
6168 };
6169
6170 return handle64BitOverflow(ResVReg, ResType, I, SrcReg, BitSetOpcode, Func);
6171 }
6172
6173 // 1. Split int64 into 2 pieces using a bitcast
6174 MachineIRBuilder MIRBuilder(I);
6175 SPIRVTypeInst PostCastType = GR.getOrCreateSPIRVVectorType(
6176 BaseType, 2 * ComponentCount, MIRBuilder, false);
6177 Register BitcastReg =
6178 MRI->createVirtualRegister(GR.getRegClass(PostCastType));
6179
6180 if (!selectOpWithSrcs(BitcastReg, PostCastType, I, {SrcReg},
6181 SPIRV::OpBitcast))
6182 return false;
6183
6184 // 2. Find the first set bit from the primary side for all the pieces in #1
6185 Register FBSReg = MRI->createVirtualRegister(GR.getRegClass(PostCastType));
6186 if (!selectFirstBitSet32(FBSReg, PostCastType, I, BitcastReg, BitSetOpcode))
6187 return false;
6188
6189 // 3. Split result vector into high bits and low bits
6190 Register HighReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
6191 Register LowReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
6192
6193 bool IsScalarRes = ResType->getOpcode() != SPIRV::OpTypeVector;
6194 if (IsScalarRes) {
6195 // if scalar do a vector extract
6196 if (!selectOpWithSrcs(HighReg, ResType, I, {FBSReg, ConstIntOne},
6197 SPIRV::OpVectorExtractDynamic))
6198 return false;
6199 if (!selectOpWithSrcs(LowReg, ResType, I, {FBSReg, ConstIntZero},
6200 SPIRV::OpVectorExtractDynamic))
6201 return false;
6202 } else {
6203 // if vector do a shufflevector
6204 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
6205 TII.get(SPIRV::OpVectorShuffle))
6206 .addDef(HighReg)
6207 .addUse(GR.getSPIRVTypeID(ResType))
6208 .addUse(FBSReg)
6209 // Per the spec, repeat the vector if only one vec is needed
6210 .addUse(FBSReg);
6211
6212 // high bits are stored in even natural indexes. Extract them from FBSReg
6213 for (unsigned J = 1; J < ComponentCount * 2; J += 2) {
6214 MIB.addImm(J);
6215 }
6216
6217 MIB.constrainAllUses(TII, TRI, RBI);
6218
6219 MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
6220 TII.get(SPIRV::OpVectorShuffle))
6221 .addDef(LowReg)
6222 .addUse(GR.getSPIRVTypeID(ResType))
6223 .addUse(FBSReg)
6224 // Per the spec, repeat the vector if only one vec is needed
6225 .addUse(FBSReg);
6226
6227 // low bits are stored in odd natural indices. Extract them from FBSReg
6228 for (unsigned J = 0; J < ComponentCount * 2; J += 2) {
6229 MIB.addImm(J);
6230 }
6231 MIB.constrainAllUses(TII, TRI, RBI);
6232 }
6233
6234 // 4. Check the result. When primary bits == -1 use secondary, otherwise use
6235 // primary
6236 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
6237 Register NegOneReg;
6238 Register Reg0;
6239 Register Reg32;
6240 unsigned SelectOp;
6241 unsigned AddOp;
6242
6243 if (IsScalarRes) {
6244 NegOneReg =
6245 GR.getOrCreateConstInt((unsigned)-1, I, ResType, TII, ZeroAsNull);
6246 Reg0 = GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
6247 Reg32 = GR.getOrCreateConstInt(32, I, ResType, TII, ZeroAsNull);
6248 SelectOp = SPIRV::OpSelectSISCond;
6249 AddOp = SPIRV::OpIAddS;
6250 } else {
6251 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, ComponentCount,
6252 MIRBuilder, false);
6253 NegOneReg =
6254 GR.getOrCreateConstVector((unsigned)-1, I, ResType, TII, ZeroAsNull);
6255 Reg0 = GR.getOrCreateConstVector(0, I, ResType, TII, ZeroAsNull);
6256 Reg32 = GR.getOrCreateConstVector(32, I, ResType, TII, ZeroAsNull);
6257 SelectOp = SPIRV::OpSelectVIVCond;
6258 AddOp = SPIRV::OpIAddV;
6259 }
6260
6261 Register PrimaryReg = HighReg;
6262 Register SecondaryReg = LowReg;
6263 Register RegPrimaryOffset = Reg32;
6264 Register RegSecondaryOffset = Reg0;
6265
6266 // By default the emitted opcodes check for the set bit from the MSB side.
6267 // Setting SwapPrimarySide checks the set bit from the LSB side
6268 if (SwapPrimarySide) {
6269 PrimaryReg = LowReg;
6270 SecondaryReg = HighReg;
6271 RegPrimaryOffset = Reg0;
6272 RegSecondaryOffset = Reg32;
6273 }
6274
6275 Register RegSecondaryHasVal =
6276 MRI->createVirtualRegister(GR.getRegClass(BoolType));
6277 if (!selectOpWithSrcs(RegSecondaryHasVal, BoolType, I,
6278 {SecondaryReg, NegOneReg}, SPIRV::OpINotEqual))
6279 return false;
6280
6281 Register RegPrimaryHasVal =
6282 MRI->createVirtualRegister(GR.getRegClass(BoolType));
6283 if (!selectOpWithSrcs(RegPrimaryHasVal, BoolType, I, {PrimaryReg, NegOneReg},
6284 SPIRV::OpINotEqual))
6285 return false;
6286
6287 // Pass 1: seed with secondary (lower-priority fallback)
6288 // ReturnBits = secondaryHasVal ? SecondaryBits : -1
6289 // Add = secondaryHasVal ? SecondaryOffset : 0
6290 Register RegReturnBits = MRI->createVirtualRegister(GR.getRegClass(ResType));
6291 if (!selectOpWithSrcs(RegReturnBits, ResType, I,
6292 {RegSecondaryHasVal, SecondaryReg, NegOneReg},
6293 SelectOp))
6294 return false;
6295
6296 Register RegAdd;
6297 if (SwapPrimarySide) {
6298 RegAdd = MRI->createVirtualRegister(GR.getRegClass(ResType));
6299 if (!selectOpWithSrcs(RegAdd, ResType, I,
6300 {RegSecondaryHasVal, RegSecondaryOffset, Reg0},
6301 SelectOp))
6302 return false;
6303 } else {
6304 RegAdd = Reg0;
6305 }
6306
6307 // Pass 2: override with primary (higher priority) if it has a valid result
6308 // ReturnBits2 = primaryHasVal ? PrimaryBits : ReturnBits
6309 // Add2 = primaryHasVal ? PrimaryOffset : Add
6310 Register RegReturnBits2 = MRI->createVirtualRegister(GR.getRegClass(ResType));
6311 if (!selectOpWithSrcs(RegReturnBits2, ResType, I,
6312 {RegPrimaryHasVal, PrimaryReg, RegReturnBits},
6313 SelectOp))
6314 return false;
6315
6316 Register RegAdd2 = MRI->createVirtualRegister(GR.getRegClass(ResType));
6317 if (!selectOpWithSrcs(RegAdd2, ResType, I,
6318 {RegPrimaryHasVal, RegPrimaryOffset, RegAdd}, SelectOp))
6319 return false;
6320
6321 return selectOpWithSrcs(ResVReg, ResType, I, {RegReturnBits2, RegAdd2},
6322 AddOp);
6323}
6324
6325bool SPIRVInstructionSelector::selectFirstBitHigh(Register ResVReg,
6326 SPIRVTypeInst ResType,
6327 MachineInstr &I,
6328 bool IsSigned) const {
6329 // FindUMsb and FindSMsb intrinsics only support 32 bit integers
6330 Register OpReg = I.getOperand(2).getReg();
6331 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
6332 // zero or sign extend
6333 unsigned ExtendOpcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
6334 unsigned BitSetOpcode = IsSigned ? GL::FindSMsb : GL::FindUMsb;
6335
6336 switch (GR.getScalarOrVectorBitWidth(OpType)) {
6337 case 16:
6338 return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode);
6339 case 32:
6340 return selectFirstBitSet32(ResVReg, ResType, I, OpReg, BitSetOpcode);
6341 case 64:
6342 return selectFirstBitSet64(ResVReg, ResType, I, OpReg, BitSetOpcode,
6343 /*SwapPrimarySide=*/false);
6344 default:
6346 "spv_firstbituhigh and spv_firstbitshigh only support 16,32,64 bits.");
6347 }
6348}
6349
6350bool SPIRVInstructionSelector::selectFirstBitLow(Register ResVReg,
6351 SPIRVTypeInst ResType,
6352 MachineInstr &I) const {
6353 // FindILsb intrinsic only supports 32 bit integers
6354 Register OpReg = I.getOperand(2).getReg();
6355 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
6356 // OpUConvert treats the operand bits as an unsigned i16 and zero extends it
6357 // to an unsigned i32. As this leaves all the least significant bits unchanged
6358 // so the first set bit from the LSB side doesn't change.
6359 unsigned ExtendOpcode = SPIRV::OpUConvert;
6360 unsigned BitSetOpcode = GL::FindILsb;
6361
6362 switch (GR.getScalarOrVectorBitWidth(OpType)) {
6363 case 16:
6364 return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode);
6365 case 32:
6366 return selectFirstBitSet32(ResVReg, ResType, I, OpReg, BitSetOpcode);
6367 case 64:
6368 return selectFirstBitSet64(ResVReg, ResType, I, OpReg, BitSetOpcode,
6369 /*SwapPrimarySide=*/true);
6370 default:
6371 report_fatal_error("spv_firstbitlow only supports 16,32,64 bits.");
6372 }
6373}
6374
6375bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg,
6376 SPIRVTypeInst ResType,
6377 MachineInstr &I) const {
6378 // there was an allocation size parameter to the allocation instruction
6379 // that is not 1
6380 MachineBasicBlock &BB = *I.getParent();
6381 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVariableLengthArrayINTEL))
6382 .addDef(ResVReg)
6383 .addUse(GR.getSPIRVTypeID(ResType))
6384 .addUse(I.getOperand(2).getReg())
6385 .constrainAllUses(TII, TRI, RBI);
6386 if (!STI.isShader()) {
6387 unsigned Alignment = I.getOperand(3).getImm();
6388 buildOpDecorate(ResVReg, I, TII, SPIRV::Decoration::Alignment, {Alignment});
6389 }
6390 return true;
6391}
6392
6393// Returns true iff `Ty` is a concrete SPIR-V type per the SPV_KHR_abort
6394// definition: a numerical scalar (int/float), a (physical) pointer, a vector,
6395// matrix or any aggregate (array/struct) recursively containing only such
6396// types. OpTypeBool, OpTypeVoid, opaque handles and similar abstract
6397// non-concrete types are rejected.
6399 const SPIRVGlobalRegistry &GR) {
6400 SmallVector<SPIRVTypeInst, 4> Worklist{Ty};
6401 while (!Worklist.empty()) {
6402 SPIRVTypeInst T = Worklist.pop_back_val();
6403 switch (T->getOpcode()) {
6404 case SPIRV::OpTypeInt:
6405 case SPIRV::OpTypeFloat:
6406 case SPIRV::OpTypePointer:
6407 break;
6408 case SPIRV::OpTypeVector:
6409 case SPIRV::OpTypeMatrix:
6410 case SPIRV::OpTypeArray: {
6411 Register OperandReg = T->getOperand(1).getReg();
6412 SPIRVTypeInst ElementT = GR.getSPIRVTypeForVReg(OperandReg);
6413 Worklist.push_back(ElementT);
6414 } break;
6415 case SPIRV::OpTypeStruct:
6416 for (unsigned Idx = 1, E = T->getNumOperands(); Idx < E; ++Idx) {
6417 Register OperandReg = T->getOperand(Idx).getReg();
6418 SPIRVTypeInst ElementT = GR.getSPIRVTypeForVReg(OperandReg);
6419 Worklist.push_back(ElementT);
6420 }
6421 break;
6422 default:
6423 return false;
6424 }
6425 }
6426 return true;
6427}
6428
6429bool SPIRVInstructionSelector::selectAbort(MachineInstr &I) const {
6430 assert(I.getNumExplicitOperands() == 2);
6431
6432 Register MsgReg = I.getOperand(1).getReg();
6433 SPIRVTypeInst MsgType = GR.getSPIRVTypeForVReg(MsgReg);
6434 assert(MsgType && "Message argument of llvm.spv.abort has no SPIR-V type");
6435
6436 if (!isConcreteSPIRVType(MsgType, GR))
6437 return diagnoseUnsupported(
6438 I,
6439 "llvm.spv.abort message type must be a concrete SPIR-V type (numerical "
6440 "scalar, pointer, vector, matrix, or aggregate of such types)");
6441
6442 MachineBasicBlock &BB = *I.getParent();
6443 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAbortKHR))
6444 .addUse(GR.getSPIRVTypeID(MsgType))
6445 .addUse(MsgReg)
6446 .constrainAllUses(TII, TRI, RBI);
6447 return true;
6448}
6449
6450bool SPIRVInstructionSelector::selectTrap(MachineInstr &I) const {
6451 // When the SPV_KHR_abort extension is disabled, drop the G_TRAP and
6452 // G_UBSANTRAP silently.
6453 if (!STI.canUseExtension(SPIRV::Extension::SPV_KHR_abort))
6454 return true;
6455
6456 // Use the 32-bit integer constant for the abort "message" argument:
6457 // - G_UBSANTRAP operand is zero-extended to 32 bits.
6458 // - "All ones" constant is used for G_TRAP.
6459 uint32_t MsgVal = ~0u;
6460 if (I.getOpcode() == TargetOpcode::G_UBSANTRAP)
6461 MsgVal = static_cast<uint32_t>(I.getOperand(0).getImm());
6462
6463 SPIRVTypeInst MsgType = GR.getOrCreateSPIRVIntegerType(32, I, TII);
6464 Register MsgReg = buildI32ConstantInEntryBlock(MsgVal, I, MsgType);
6465
6466 MachineBasicBlock &BB = *I.getParent();
6467 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAbortKHR))
6468 .addUse(GR.getSPIRVTypeID(MsgType))
6469 .addUse(MsgReg)
6470 .constrainAllUses(TII, TRI, RBI);
6471 return true;
6472}
6473
6474bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg,
6475 SPIRVTypeInst ResType,
6476 MachineInstr &I) const {
6477 // Change order of instructions if needed: all OpVariable instructions in a
6478 // function must be the first instructions in the first block
6479 auto It = getOpVariableMBBIt(*I.getMF());
6480 BuildMI(*It->getParent(), It, It->getDebugLoc(), TII.get(SPIRV::OpVariable))
6481 .addDef(ResVReg)
6482 .addUse(GR.getSPIRVTypeID(ResType))
6483 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
6484 .constrainAllUses(TII, TRI, RBI);
6485 if (!STI.isShader()) {
6486 unsigned Alignment = I.getOperand(2).getImm();
6487 buildOpDecorate(ResVReg, *It, TII, SPIRV::Decoration::Alignment,
6488 {Alignment});
6489 }
6490 return true;
6491}
6492
6493bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const {
6494 // InstructionSelector walks backwards through the instructions. We can use
6495 // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
6496 // first, so can generate an OpBranchConditional here. If there is no
6497 // G_BRCOND, we just use OpBranch for a regular unconditional branch.
6498 const MachineInstr *PrevI = I.getPrevNode();
6499 MachineBasicBlock &MBB = *I.getParent();
6500 if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) {
6501 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
6502 .addUse(PrevI->getOperand(0).getReg())
6503 .addMBB(PrevI->getOperand(1).getMBB())
6504 .addMBB(I.getOperand(0).getMBB())
6505 .constrainAllUses(TII, TRI, RBI);
6506 return true;
6507 }
6508 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch))
6509 .addMBB(I.getOperand(0).getMBB())
6510 .constrainAllUses(TII, TRI, RBI);
6511 return true;
6512}
6513
6514bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const {
6515 // InstructionSelector walks backwards through the instructions. For an
6516 // explicit conditional branch with no fallthrough, we use both a G_BR and a
6517 // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
6518 // generate the OpBranchConditional in selectBranch above.
6519 //
6520 // If an OpBranchConditional has been generated, we simply return, as the work
6521 // is alread done. If there is no OpBranchConditional, LLVM must be relying on
6522 // implicit fallthrough to the next basic block, so we need to create an
6523 // OpBranchConditional with an explicit "false" argument pointing to the next
6524 // basic block that LLVM would fall through to.
6525 const MachineInstr *NextI = I.getNextNode();
6526 // Check if this has already been successfully selected.
6527 if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional)
6528 return true;
6529 // Must be relying on implicit block fallthrough, so generate an
6530 // OpBranchConditional with the "next" basic block as the "false" target.
6531 MachineBasicBlock &MBB = *I.getParent();
6532 unsigned NextMBBNum = MBB.getNextNode()->getNumber();
6533 MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum);
6534 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
6535 .addUse(I.getOperand(0).getReg())
6536 .addMBB(I.getOperand(1).getMBB())
6537 .addMBB(NextMBB)
6538 .constrainAllUses(TII, TRI, RBI);
6539 return true;
6540}
6541
6542bool SPIRVInstructionSelector::selectPhi(Register ResVReg,
6543 MachineInstr &I) const {
6544 auto MIB =
6545 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::PHI))
6546 .addDef(ResVReg);
6547 const unsigned NumOps = I.getNumOperands();
6548 for (unsigned i = 1; i < NumOps; i += 2) {
6549 MIB.addUse(I.getOperand(i + 0).getReg());
6550 MIB.addMBB(I.getOperand(i + 1).getMBB());
6551 }
6552 MIB.constrainAllUses(TII, TRI, RBI);
6553 return true;
6554}
6555
6556bool SPIRVInstructionSelector::selectGlobalValue(
6557 Register ResVReg, MachineInstr &I, const MachineInstr *Init) const {
6558 // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
6559 MachineIRBuilder MIRBuilder(I);
6560 const GlobalValue *GV = I.getOperand(1).getGlobal();
6562
6563 std::string GlobalIdent;
6564 if (!GV->hasName()) {
6565 unsigned &ID = UnnamedGlobalIDs[GV];
6566 if (ID == 0)
6567 ID = UnnamedGlobalIDs.size();
6568 GlobalIdent = "__unnamed_" + Twine(ID).str();
6569 } else {
6570 GlobalIdent = GV->getName();
6571 }
6572
6573 // Behaviour of functions as operands depends on availability of the
6574 // corresponding extension (SPV_INTEL_function_pointers):
6575 // - If there is an extension to operate with functions as operands:
6576 // We create a proper constant operand and evaluate a correct type for a
6577 // function pointer.
6578 // - Without the required extension:
6579 // We have functions as operands in tests with blocks of instruction e.g. in
6580 // transcoding/global_block.ll. These operands are not used and should be
6581 // substituted by zero constants. Their type is expected to be always
6582 // OpTypePointer Function %uchar.
6583 if (isa<Function>(GV)) {
6584 const Constant *ConstVal = GV;
6585 MachineBasicBlock &BB = *I.getParent();
6586 Register NewReg = GR.find(ConstVal, GR.CurMF);
6587 if (!NewReg.isValid()) {
6588 const Function *GVFun =
6589 STI.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
6590 ? dyn_cast<Function>(GV)
6591 : nullptr;
6592 SPIRVTypeInst ResType = GR.getOrCreateSPIRVPointerType(
6593 GVType, I,
6594 GVFun ? SPIRV::StorageClass::CodeSectionINTEL
6596 if (GVFun) {
6597 // References to a function via function pointers generate virtual
6598 // registers without a definition. We will resolve it later, during
6599 // module analysis stage.
6600 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
6601 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
6602 Register FuncVReg =
6603 MRI->createGenericVirtualRegister(GR.getRegType(ResType));
6604 MRI->setRegClass(FuncVReg, &SPIRV::pIDRegClass);
6605 GR.assignSPIRVTypeToVReg(ResType, FuncVReg, *GR.CurMF);
6606 MachineInstrBuilder MIB1 =
6607 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
6608 .addDef(FuncVReg)
6609 .addUse(ResTypeReg);
6610 MachineInstrBuilder MIB2 =
6611 BuildMI(BB, I, I.getDebugLoc(),
6612 TII.get(SPIRV::OpConstantFunctionPointerINTEL))
6613 .addDef(ResVReg)
6614 .addUse(ResTypeReg)
6615 .addUse(FuncVReg);
6616 GR.add(ConstVal, MIB2);
6617 // mapping the function pointer to the used Function
6618 GR.recordFunctionPointer(&MIB2.getInstr()->getOperand(2), GVFun);
6619 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF);
6620 MIB1.constrainAllUses(TII, TRI, RBI);
6621 MIB2.constrainAllUses(TII, TRI, RBI);
6622 return true;
6623 }
6624 MachineInstrBuilder MIB3 =
6625 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
6626 .addDef(ResVReg)
6627 .addUse(GR.getSPIRVTypeID(ResType));
6628 GR.add(ConstVal, MIB3);
6629 MIB3.constrainAllUses(TII, TRI, RBI);
6630 return true;
6631 }
6632 assert(NewReg != ResVReg);
6633 return BuildCOPY(ResVReg, NewReg, I);
6634 }
6636 assert(GlobalVar->getName() != "llvm.global.annotations");
6637
6638 // Skip empty declaration for GVs with initializers till we get the decl with
6639 // passed initializer.
6640 if (hasInitializer(GlobalVar) && !Init)
6641 return true;
6642
6643 const std::optional<SPIRV::LinkageType::LinkageType> LnkType =
6644 getSpirvLinkageTypeFor(STI, *GV);
6645
6646 if (LnkType && *LnkType == SPIRV::LinkageType::Import)
6647 Init = nullptr;
6648
6649 const unsigned AddrSpace = GV->getAddressSpace();
6650 SPIRV::StorageClass::StorageClass StorageClass =
6651 addressSpaceToStorageClass(AddrSpace, STI);
6652 SPIRVTypeInst ResType =
6655 ResVReg, ResType, GlobalIdent, GV, StorageClass, Init,
6656 GlobalVar->isConstant(), LnkType, MIRBuilder, true);
6657 // TODO: For AMDGCN, we pipe externally_initialized through via
6658 // HostAccessINTEL, with ReadWrite (3) access, which is we then handle during
6659 // reverse translation. We should remove this once SPIR-V gains the ability to
6660 // express the concept.
6661 if (GlobalVar->isExternallyInitialized() &&
6662 STI.getTargetTriple().getVendor() == Triple::AMD) {
6663 constexpr unsigned ReadWriteINTEL = 3u;
6664 buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::HostAccessINTEL,
6665 {ReadWriteINTEL});
6666 MachineInstrBuilder MIB(*MF, --MIRBuilder.getInsertPt());
6667 addStringImm(GV->getName(), MIB);
6668 }
6669 return Reg.isValid();
6670}
6671
6672bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
6673 SPIRVTypeInst ResType,
6674 MachineInstr &I) const {
6675 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
6676 return selectExtInst(ResVReg, ResType, I, CL::log10);
6677 }
6678
6679 // There is no log10 instruction in the GLSL Extended Instruction set, so it
6680 // is implemented as:
6681 // log10(x) = log2(x) * (1 / log2(10))
6682 // = log2(x) * 0.30103
6683
6684 MachineIRBuilder MIRBuilder(I);
6685 MachineBasicBlock &BB = *I.getParent();
6686
6687 // Build log2(x).
6688 Register VarReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
6689 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
6690 .addDef(VarReg)
6691 .addUse(GR.getSPIRVTypeID(ResType))
6692 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
6693 .addImm(GL::Log2)
6694 .add(I.getOperand(1))
6695 .constrainAllUses(TII, TRI, RBI);
6696
6697 // Build 0.30103.
6698 assert(ResType->getOpcode() == SPIRV::OpTypeVector ||
6699 ResType->getOpcode() == SPIRV::OpTypeFloat);
6700 // TODO: Add matrix implementation once supported by the HLSL frontend.
6701 SPIRVTypeInst SpirvScalarType = GR.getScalarOrVectorComponentType(ResType);
6702 // The literal must match the precision of the scalar type, otherwise the
6703 // OpConstant will contain non-zero high-order bits and fail SPIR-V
6704 // validation when the type is narrower than 32 bits (e.g. half).
6705 APFloat ScaleVal(0.30103);
6706 bool LosesInfo;
6707 ScaleVal.convert(
6708 getZeroFP(GR.getTypeForSPIRVType(SpirvScalarType)).getSemantics(),
6709 APFloat::rmNearestTiesToEven, &LosesInfo);
6710 Register ScaleReg = GR.buildConstantFP(ScaleVal, MIRBuilder, SpirvScalarType);
6711
6712 // Multiply log2(x) by 0.30103 to get log10(x) result.
6713 auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector
6714 ? SPIRV::OpVectorTimesScalar
6715 : SPIRV::OpFMulS;
6716 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
6717 .addDef(ResVReg)
6718 .addUse(GR.getSPIRVTypeID(ResType))
6719 .addUse(VarReg)
6720 .addUse(ScaleReg)
6721 .constrainAllUses(TII, TRI, RBI);
6722 return true;
6723}
6724
6725bool SPIRVInstructionSelector::selectFpowi(Register ResVReg,
6726 SPIRVTypeInst ResType,
6727 MachineInstr &I) const {
6728 // On OpenCL targets, pown(gentype x, intn n) maps directly.
6729 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std))
6730 return selectExtInst(ResVReg, ResType, I, CL::pown);
6731
6732 // On GLSL (Vulkan) targets, there is no integer-exponent power instruction.
6733 // Lower as: Pow(base, OpConvertSToF(exp)).
6734 if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
6735 Register BaseReg = I.getOperand(1).getReg();
6736 Register ExpReg = I.getOperand(2).getReg();
6737 Register FloatExpReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
6738 if (!selectOpWithSrcs(FloatExpReg, ResType, I, {ExpReg},
6739 SPIRV::OpConvertSToF))
6740 return false;
6741 return selectExtInst(ResVReg, ResType, I, GL::Pow,
6742 /*setMIFlags=*/true, /*useMISrc=*/false,
6743 {BaseReg, FloatExpReg});
6744 }
6745 return false;
6746}
6747
6748bool SPIRVInstructionSelector::selectModf(Register ResVReg,
6749 SPIRVTypeInst ResType,
6750 MachineInstr &I) const {
6751 // llvm.modf has a single arg --the number to be decomposed-- and returns a
6752 // struct { restype, restype }, while OpenCLLIB::modf has two args --the
6753 // number to be decomposed and a pointer--, returns the fractional part and
6754 // the integral part is stored in the pointer argument. Therefore, we can't
6755 // use directly the OpenCLLIB::modf intrinsic. However, we can do some
6756 // scaffolding to make it work. The idea is to create an alloca instruction
6757 // to get a ptr, pass this ptr to OpenCL::modf, and then load the value
6758 // from this ptr to place it in the struct. llvm.modf returns the fractional
6759 // part as the first element of the result, and the integral part as the
6760 // second element of the result.
6761
6762 // At this point, the return type is not a struct anymore, but rather two
6763 // independent elements of SPIRVResType. We can get each independent element
6764 // from I.getDefs() or I.getOperands().
6765 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
6766 MachineIRBuilder MIRBuilder(I);
6767 // Get pointer type for alloca variable.
6768 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
6769 ResType, MIRBuilder, SPIRV::StorageClass::Function);
6770 // Create new register for the pointer type of alloca variable.
6771 Register PtrTyReg =
6772 MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
6773 MIRBuilder.getMRI()->setType(
6774 PtrTyReg,
6775 LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Function),
6776 GR.getPointerSize()));
6777
6778 // Assign SPIR-V type of the pointer type of the alloca variable to the
6779 // new register.
6780 GR.assignSPIRVTypeToVReg(PtrType, PtrTyReg, MIRBuilder.getMF());
6782 MachineBasicBlock &EntryBB = I.getMF()->front();
6783 auto AllocaMIB =
6784 BuildMI(EntryBB, VarPos, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
6785 .addDef(PtrTyReg)
6786 .addUse(GR.getSPIRVTypeID(PtrType))
6787 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function));
6788 Register Variable = AllocaMIB->getOperand(0).getReg();
6789
6790 MachineBasicBlock &BB = *I.getParent();
6791 // Create the OpenCLLIB::modf instruction.
6792 auto MIB =
6793 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
6794 .addDef(ResVReg)
6795 .addUse(GR.getSPIRVTypeID(ResType))
6796 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
6797 .addImm(CL::modf)
6798 .setMIFlags(I.getFlags())
6799 .add(I.getOperand(I.getNumExplicitDefs())) // Floating point value.
6800 .addUse(Variable); // Pointer to integral part.
6801 // Assign the integral part stored in the ptr to the second element of the
6802 // result.
6803 Register IntegralPartReg = I.getOperand(1).getReg();
6804 if (IntegralPartReg.isValid()) {
6805 // Load the value from the pointer to integral part.
6806 auto LoadMIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
6807 .addDef(IntegralPartReg)
6808 .addUse(GR.getSPIRVTypeID(ResType))
6809 .addUse(Variable);
6810 LoadMIB.constrainAllUses(TII, TRI, RBI);
6811 return true;
6812 }
6813
6814 MIB.constrainAllUses(TII, TRI, RBI);
6815 return true;
6816 } else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
6817 assert(false && "GLSL::Modf is deprecated.");
6818 // FIXME: GL::Modf is deprecated, use Modfstruct instead.
6819 return false;
6820 }
6821 return false;
6822}
6823
6824// Generate the instructions to load 3-element vector builtin input
6825// IDs/Indices.
6826// Like: GlobalInvocationId, LocalInvocationId, etc....
6827
6828bool SPIRVInstructionSelector::loadVec3BuiltinInputID(
6829 SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg,
6830 SPIRVTypeInst ResType, MachineInstr &I) const {
6831 MachineIRBuilder MIRBuilder(I);
6832 const SPIRVTypeInst Vec3Ty =
6833 GR.getOrCreateSPIRVVectorType(ResType, 3, MIRBuilder, false);
6834 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
6835 Vec3Ty, MIRBuilder, SPIRV::StorageClass::Input);
6836
6837 // Create new register for the input ID builtin variable.
6838 Register NewRegister =
6839 MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
6840 MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 64));
6841 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
6842
6843 // Build global variable with the necessary decorations for the input ID
6844 // builtin variable.
6846 NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr,
6847 SPIRV::StorageClass::Input, nullptr, true, std::nullopt, MIRBuilder,
6848 false);
6849
6850 // Create new register for loading value.
6851 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
6852 Register LoadedRegister = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
6853 MIRBuilder.getMRI()->setType(LoadedRegister, LLT::pointer(0, 64));
6854 GR.assignSPIRVTypeToVReg(Vec3Ty, LoadedRegister, MIRBuilder.getMF());
6855
6856 // Load v3uint value from the global variable.
6857 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
6858 .addDef(LoadedRegister)
6859 .addUse(GR.getSPIRVTypeID(Vec3Ty))
6860 .addUse(Variable);
6861
6862 // Get the input ID index. Expecting operand is a constant immediate value,
6863 // wrapped in a type assignment.
6864 assert(I.getOperand(2).isReg());
6865 const uint32_t ThreadId = foldImm(I.getOperand(2), MRI);
6866
6867 // Extract the input ID from the loaded vector value.
6868 MachineBasicBlock &BB = *I.getParent();
6869 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
6870 .addDef(ResVReg)
6871 .addUse(GR.getSPIRVTypeID(ResType))
6872 .addUse(LoadedRegister)
6873 .addImm(ThreadId);
6874 MIB.constrainAllUses(TII, TRI, RBI);
6875 return true;
6876}
6877
6878// Generate the instructions to load 32-bit integer builtin input IDs/Indices.
6879// Like LocalInvocationIndex
6880bool SPIRVInstructionSelector::loadBuiltinInputID(
6881 SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg,
6882 SPIRVTypeInst ResType, MachineInstr &I) const {
6883 MachineIRBuilder MIRBuilder(I);
6884 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
6885 ResType, MIRBuilder, SPIRV::StorageClass::Input);
6886
6887 // Create new register for the input ID builtin variable.
6888 Register NewRegister =
6889 MIRBuilder.getMRI()->createVirtualRegister(GR.getRegClass(PtrType));
6890 MIRBuilder.getMRI()->setType(
6891 NewRegister,
6892 LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Input),
6893 GR.getPointerSize()));
6894 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
6895
6896 // Build global variable with the necessary decorations for the input ID
6897 // builtin variable.
6899 NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr,
6900 SPIRV::StorageClass::Input, nullptr, true, std::nullopt, MIRBuilder,
6901 false);
6902
6903 // Load uint value from the global variable.
6904 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
6905 .addDef(ResVReg)
6906 .addUse(GR.getSPIRVTypeID(ResType))
6907 .addUse(Variable);
6908
6909 MIB.constrainAllUses(TII, TRI, RBI);
6910 return true;
6911}
6912
6913SPIRVTypeInst SPIRVInstructionSelector::widenTypeToVec4(SPIRVTypeInst Type,
6914 MachineInstr &I) const {
6915 MachineIRBuilder MIRBuilder(I);
6916 if (Type->getOpcode() != SPIRV::OpTypeVector)
6917 return GR.getOrCreateSPIRVVectorType(Type, 4, MIRBuilder, false);
6918
6920 return Type;
6921
6922 SPIRVTypeInst ScalarType = GR.getScalarOrVectorComponentType(Type);
6923 return GR.getOrCreateSPIRVVectorType(ScalarType, 4, MIRBuilder, false);
6924}
6925
6926bool SPIRVInstructionSelector::loadHandleBeforePosition(
6927 Register &HandleReg, SPIRVTypeInst ResType, GIntrinsic &HandleDef,
6928 MachineInstr &Pos) const {
6929
6930 assert(HandleDef.getIntrinsicID() ==
6931 Intrinsic::spv_resource_handlefrombinding);
6932 uint32_t Set = foldImm(HandleDef.getOperand(2), MRI);
6933 uint32_t Binding = foldImm(HandleDef.getOperand(3), MRI);
6934 uint32_t ArraySize = foldImm(HandleDef.getOperand(4), MRI);
6935 Register IndexReg = HandleDef.getOperand(5).getReg();
6936 std::string Name =
6937 getStringValueFromReg(HandleDef.getOperand(6).getReg(), *MRI);
6938
6939 bool IsStructuredBuffer = ResType->getOpcode() == SPIRV::OpTypePointer;
6940 MachineIRBuilder MIRBuilder(HandleDef);
6941 SPIRVTypeInst VarType = ResType;
6942 SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::UniformConstant;
6943
6944 if (IsStructuredBuffer) {
6945 VarType = GR.getPointeeType(ResType);
6946 SC = GR.getPointerStorageClass(ResType);
6947 }
6948
6949 if (ResType->getOpcode() == SPIRV::OpTypeImage && ArraySize == 0)
6950 MIRBuilder.buildInstr(SPIRV::OpCapability)
6951 .addImm(SPIRV::Capability::RuntimeDescriptorArrayEXT);
6952
6953 Register VarReg =
6954 buildPointerToResource(SPIRVTypeInst(VarType), SC, Set, Binding,
6955 ArraySize, IndexReg, Name, MIRBuilder);
6956
6957 // The handle for the buffer is the pointer to the resource. For an image, the
6958 // handle is the image object. So images get an extra load.
6959 uint32_t LoadOpcode =
6960 IsStructuredBuffer ? SPIRV::OpCopyObject : SPIRV::OpLoad;
6961 GR.assignSPIRVTypeToVReg(ResType, HandleReg, *Pos.getMF());
6962 BuildMI(*Pos.getParent(), Pos, HandleDef.getDebugLoc(), TII.get(LoadOpcode))
6963 .addDef(HandleReg)
6964 .addUse(GR.getSPIRVTypeID(ResType))
6965 .addUse(VarReg)
6966 .constrainAllUses(TII, TRI, RBI);
6967 return true;
6968}
6969
6970void SPIRVInstructionSelector::errorIfInstrOutsideShader(
6971 MachineInstr &I) const {
6972 if (!STI.isShader()) {
6973 std::string DiagMsg;
6974 raw_string_ostream OS(DiagMsg);
6975 I.print(OS, true, false, false, false);
6976 DiagMsg += " is only supported in shaders.\n";
6977 report_fatal_error(DiagMsg.c_str(), false);
6978 }
6979}
6980
6981namespace llvm {
6982InstructionSelector *
6984 const SPIRVSubtarget &Subtarget,
6985 const RegisterBankInfo &RBI) {
6986 return new SPIRVInstructionSelector(TM, Subtarget, RBI);
6987}
6988} // 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:853
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:119
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:1687
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:209
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