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