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