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