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