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