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