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