LLVM 23.0.0git
SPIRVInstructionSelector.cpp
Go to the documentation of this file.
1//===- SPIRVInstructionSelector.cpp ------------------------------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the targeting of the InstructionSelector class for
10// SPIRV.
11// TODO: This should be generated by TableGen.
12//
13//===----------------------------------------------------------------------===//
14
17#include "SPIRV.h"
18#include "SPIRVGlobalRegistry.h"
19#include "SPIRVInstrInfo.h"
20#include "SPIRVRegisterInfo.h"
21#include "SPIRVTargetMachine.h"
22#include "SPIRVUtils.h"
23#include "llvm/ADT/APFloat.h"
32#include "llvm/IR/IntrinsicsSPIRV.h"
33#include "llvm/Support/Debug.h"
35
36#define DEBUG_TYPE "spirv-isel"
37
38using namespace llvm;
39namespace CL = SPIRV::OpenCLExtInst;
40namespace GL = SPIRV::GLSLExtInst;
41
43 std::vector<std::pair<SPIRV::InstructionSet::InstructionSet, uint32_t>>;
44
45namespace {
46
47struct ImageOperands {
48 std::optional<Register> Bias;
49 std::optional<Register> Offset;
50 std::optional<Register> MinLod;
51 std::optional<Register> GradX;
52 std::optional<Register> GradY;
53 std::optional<Register> Lod;
54 std::optional<Register> Compare;
55};
56
57llvm::SPIRV::SelectionControl::SelectionControl
58getSelectionOperandForImm(int Imm) {
59 if (Imm == 2)
60 return SPIRV::SelectionControl::Flatten;
61 if (Imm == 1)
62 return SPIRV::SelectionControl::DontFlatten;
63 if (Imm == 0)
64 return SPIRV::SelectionControl::None;
65 llvm_unreachable("Invalid immediate");
66}
67
68#define GET_GLOBALISEL_PREDICATE_BITSET
69#include "SPIRVGenGlobalISel.inc"
70#undef GET_GLOBALISEL_PREDICATE_BITSET
71
72class SPIRVInstructionSelector : public InstructionSelector {
73 const SPIRVSubtarget &STI;
74 const SPIRVInstrInfo &TII;
76 const RegisterBankInfo &RBI;
79 MachineFunction *HasVRegsReset = nullptr;
80
81 /// We need to keep track of the number we give to anonymous global values to
82 /// generate the same name every time when this is needed.
83 mutable DenseMap<const GlobalValue *, unsigned> UnnamedGlobalIDs;
85
86public:
87 SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
88 const SPIRVSubtarget &ST,
89 const RegisterBankInfo &RBI);
90 void setupMF(MachineFunction &MF, GISelValueTracking *VT,
91 CodeGenCoverage *CoverageInfo, ProfileSummaryInfo *PSI,
92 BlockFrequencyInfo *BFI) override;
93 // Common selection code. Instruction-specific selection occurs in spvSelect.
94 bool select(MachineInstr &I) override;
95 static const char *getName() { return DEBUG_TYPE; }
96
97#define GET_GLOBALISEL_PREDICATES_DECL
98#include "SPIRVGenGlobalISel.inc"
99#undef GET_GLOBALISEL_PREDICATES_DECL
100
101#define GET_GLOBALISEL_TEMPORARIES_DECL
102#include "SPIRVGenGlobalISel.inc"
103#undef GET_GLOBALISEL_TEMPORARIES_DECL
104
105private:
106 void resetVRegsType(MachineFunction &MF);
107 void removeDeadInstruction(MachineInstr &MI) const;
108 void removeOpNamesForDeadMI(MachineInstr &MI) const;
109
110 // tblgen-erated 'select' implementation, used as the initial selector for
111 // the patterns that don't require complex C++.
112 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
113
114 // All instruction-specific selection that didn't happen in "select()".
115 // Is basically a large Switch/Case delegating to all other select method.
116 bool spvSelect(Register ResVReg, SPIRVTypeInst ResType,
117 MachineInstr &I) const;
118
119 bool selectFirstBitHigh(Register ResVReg, SPIRVTypeInst ResType,
120 MachineInstr &I, bool IsSigned) const;
121
122 bool selectFirstBitLow(Register ResVReg, SPIRVTypeInst ResType,
123 MachineInstr &I) const;
124
125 bool selectFirstBitSet16(Register ResVReg, SPIRVTypeInst ResType,
126 MachineInstr &I, unsigned ExtendOpcode,
127 unsigned BitSetOpcode) const;
128
129 bool selectFirstBitSet32(Register ResVReg, SPIRVTypeInst ResType,
130 MachineInstr &I, Register SrcReg,
131 unsigned BitSetOpcode) const;
132
133 bool selectFirstBitSet64(Register ResVReg, SPIRVTypeInst ResType,
134 MachineInstr &I, Register SrcReg,
135 unsigned BitSetOpcode, bool SwapPrimarySide) const;
136
137 bool selectFirstBitSet64Overflow(Register ResVReg, SPIRVTypeInst ResType,
138 MachineInstr &I, Register SrcReg,
139 unsigned BitSetOpcode,
140 bool SwapPrimarySide) const;
141
142 bool selectGlobalValue(Register ResVReg, MachineInstr &I,
143 const MachineInstr *Init = nullptr) const;
144
145 bool selectOpWithSrcs(Register ResVReg, SPIRVTypeInst ResType,
146 MachineInstr &I, std::vector<Register> SrcRegs,
147 unsigned Opcode) const;
148
149 bool selectUnOp(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
150 unsigned Opcode) const;
151
152 bool selectBitcast(Register ResVReg, SPIRVTypeInst ResType,
153 MachineInstr &I) const;
154
155 bool selectLoad(Register ResVReg, SPIRVTypeInst ResType,
156 MachineInstr &I) const;
157 bool selectStore(MachineInstr &I) const;
158
159 bool selectStackSave(Register ResVReg, SPIRVTypeInst ResType,
160 MachineInstr &I) const;
161 bool selectStackRestore(MachineInstr &I) const;
162
163 bool selectMemOperation(Register ResVReg, MachineInstr &I) const;
164 Register getOrCreateMemSetGlobal(MachineInstr &I) const;
165 bool selectCopyMemory(MachineInstr &I, Register SrcReg) const;
166 bool selectCopyMemorySized(MachineInstr &I, Register SrcReg) const;
167
168 bool selectAtomicRMW(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
169 unsigned NewOpcode, unsigned NegateOpcode = 0) const;
170
171 bool selectAtomicCmpXchg(Register ResVReg, SPIRVTypeInst ResType,
172 MachineInstr &I) const;
173
174 bool selectFence(MachineInstr &I) const;
175
176 bool selectAddrSpaceCast(Register ResVReg, SPIRVTypeInst ResType,
177 MachineInstr &I) const;
178
179 bool selectAnyOrAll(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
180 unsigned OpType) const;
181
182 bool selectAll(Register ResVReg, SPIRVTypeInst ResType,
183 MachineInstr &I) const;
184
185 bool selectAny(Register ResVReg, SPIRVTypeInst ResType,
186 MachineInstr &I) const;
187
188 bool selectBitreverse(Register ResVReg, SPIRVTypeInst ResType,
189 MachineInstr &I) const;
190
191 bool selectBuildVector(Register ResVReg, SPIRVTypeInst ResType,
192 MachineInstr &I) const;
193 bool selectSplatVector(Register ResVReg, SPIRVTypeInst ResType,
194 MachineInstr &I) const;
195
196 bool selectCmp(Register ResVReg, SPIRVTypeInst ResType,
197 unsigned comparisonOpcode, MachineInstr &I) const;
198 bool selectDiscard(Register ResVReg, SPIRVTypeInst ResType,
199 MachineInstr &I) const;
200
201 bool selectICmp(Register ResVReg, SPIRVTypeInst ResType,
202 MachineInstr &I) const;
203 bool selectFCmp(Register ResVReg, SPIRVTypeInst ResType,
204 MachineInstr &I) const;
205
206 bool selectSign(Register ResVReg, SPIRVTypeInst ResType,
207 MachineInstr &I) const;
208
209 bool selectFloatDot(Register ResVReg, SPIRVTypeInst ResType,
210 MachineInstr &I) const;
211
212 bool selectOverflowArith(Register ResVReg, SPIRVTypeInst ResType,
213 MachineInstr &I, unsigned Opcode) const;
214 bool selectDebugTrap(Register ResVReg, SPIRVTypeInst ResType,
215 MachineInstr &I) const;
216
217 bool selectIntegerDot(Register ResVReg, SPIRVTypeInst ResType,
218 MachineInstr &I, bool Signed) const;
219
220 bool selectIntegerDotExpansion(Register ResVReg, SPIRVTypeInst ResType,
221 MachineInstr &I) const;
222
223 bool selectOpIsInf(Register ResVReg, SPIRVTypeInst ResType,
224 MachineInstr &I) const;
225
226 bool selectOpIsNan(Register ResVReg, SPIRVTypeInst ResType,
227 MachineInstr &I) const;
228
229 template <bool Signed>
230 bool selectDot4AddPacked(Register ResVReg, SPIRVTypeInst ResType,
231 MachineInstr &I) const;
232 template <bool Signed>
233 bool selectDot4AddPackedExpansion(Register ResVReg, SPIRVTypeInst ResType,
234 MachineInstr &I) const;
235
236 bool selectWavePrefixBitCount(Register ResVReg, SPIRVTypeInst ResType,
237 MachineInstr &I) const;
238
239 template <typename PickOpcodeFn>
240 bool selectWaveReduce(Register ResVReg, SPIRVTypeInst ResType,
241 MachineInstr &I, bool IsUnsigned,
242 PickOpcodeFn &&PickOpcode) const;
243
244 bool selectWaveReduceMax(Register ResVReg, SPIRVTypeInst ResType,
245 MachineInstr &I, bool IsUnsigned) const;
246
247 bool selectWaveReduceMin(Register ResVReg, SPIRVTypeInst ResType,
248 MachineInstr &I, bool IsUnsigned) const;
249
250 bool selectWaveReduceSum(Register ResVReg, SPIRVTypeInst ResType,
251 MachineInstr &I) const;
252
253 template <typename PickOpcodeFn>
254 bool selectWaveExclusiveScan(Register ResVReg, SPIRVTypeInst ResType,
255 MachineInstr &I, bool IsUnsigned,
256 PickOpcodeFn &&PickOpcode) const;
257
258 bool selectWaveExclusiveScanSum(Register ResVReg, SPIRVTypeInst ResType,
259 MachineInstr &I) const;
260
261 bool selectWaveExclusiveScanProduct(Register ResVReg, SPIRVTypeInst ResType,
262 MachineInstr &I) const;
263
264 bool selectConst(Register ResVReg, SPIRVTypeInst ResType,
265 MachineInstr &I) const;
266
267 bool selectSelect(Register ResVReg, SPIRVTypeInst ResType,
268 MachineInstr &I) const;
269 bool selectBoolToInt(Register ResVReg, SPIRVTypeInst ResType,
270 Register BooleanVReg, MachineInstr &InsertAt,
271 bool IsSigned) const;
272 bool selectIToF(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
273 bool IsSigned, unsigned Opcode) const;
274 bool selectExt(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
275 bool IsSigned) const;
276
277 bool selectTrunc(Register ResVReg, SPIRVTypeInst ResType,
278 MachineInstr &I) const;
279
280 bool selectSUCmp(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
281 bool IsSigned) const;
282
283 bool selectIntToBool(Register IntReg, Register ResVReg, MachineInstr &I,
284 SPIRVTypeInst intTy, SPIRVTypeInst boolTy) const;
285
286 bool selectOpUndef(Register ResVReg, SPIRVTypeInst ResType,
287 MachineInstr &I) const;
288 bool selectFreeze(Register ResVReg, SPIRVTypeInst ResType,
289 MachineInstr &I) const;
290 bool selectIntrinsic(Register ResVReg, SPIRVTypeInst ResType,
291 MachineInstr &I) const;
292 bool selectExtractVal(Register ResVReg, SPIRVTypeInst ResType,
293 MachineInstr &I) const;
294 bool selectInsertVal(Register ResVReg, SPIRVTypeInst ResType,
295 MachineInstr &I) const;
296 bool selectExtractElt(Register ResVReg, SPIRVTypeInst ResType,
297 MachineInstr &I) const;
298 bool selectInsertElt(Register ResVReg, SPIRVTypeInst ResType,
299 MachineInstr &I) const;
300 bool selectGEP(Register ResVReg, SPIRVTypeInst ResType,
301 MachineInstr &I) const;
302
303 bool selectFrameIndex(Register ResVReg, SPIRVTypeInst ResType,
304 MachineInstr &I) const;
305 bool selectAllocaArray(Register ResVReg, SPIRVTypeInst ResType,
306 MachineInstr &I) const;
307
308 bool selectBranch(MachineInstr &I) const;
309 bool selectBranchCond(MachineInstr &I) const;
310
311 bool selectPhi(Register ResVReg, MachineInstr &I) const;
312
313 bool selectExtInst(Register ResVReg, SPIRVTypeInst RestType, MachineInstr &I,
314 GL::GLSLExtInst GLInst, bool setMIFlags = true,
315 bool useMISrc = true,
316 ArrayRef<Register> SrcRegs = {}) const;
317 bool selectExtInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
318 CL::OpenCLExtInst CLInst, bool setMIFlags = true,
319 bool useMISrc = true,
320 ArrayRef<Register> SrcRegs = {}) const;
321 bool selectExtInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
322 CL::OpenCLExtInst CLInst, GL::GLSLExtInst GLInst,
323 bool setMIFlags = true, bool useMISrc = true,
324 ArrayRef<Register> SrcRegs = {}) const;
325 bool selectExtInst(Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
326 const ExtInstList &ExtInsts, bool setMIFlags = true,
327 bool useMISrc = true,
328 ArrayRef<Register> SrcRegs = {}) const;
329
330 bool selectLog10(Register ResVReg, SPIRVTypeInst ResType,
331 MachineInstr &I) const;
332
333 bool selectSaturate(Register ResVReg, SPIRVTypeInst ResType,
334 MachineInstr &I) const;
335
336 bool selectWaveOpInst(Register ResVReg, SPIRVTypeInst ResType,
337 MachineInstr &I, unsigned Opcode) const;
338
339 bool selectWaveActiveCountBits(Register ResVReg, SPIRVTypeInst ResType,
340 MachineInstr &I) const;
341
342 bool selectWaveActiveAllEqual(Register ResVReg, SPIRVTypeInst ResType,
343 MachineInstr &I) const;
344
345 bool selectUnmergeValues(MachineInstr &I) const;
346
347 bool selectHandleFromBinding(Register &ResVReg, SPIRVTypeInst ResType,
348 MachineInstr &I) const;
349
350 bool selectCounterHandleFromBinding(Register &ResVReg, SPIRVTypeInst ResType,
351 MachineInstr &I) const;
352
353 bool selectReadImageIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
354 MachineInstr &I) const;
355 bool selectSampleBasicIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
356 MachineInstr &I) const;
357 bool selectSampleBiasIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
358 MachineInstr &I) const;
359 bool selectSampleGradIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
360 MachineInstr &I) const;
361 bool selectSampleLevelIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
362 MachineInstr &I) const;
363 bool selectSampleCmpIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
364 MachineInstr &I) const;
365 bool selectSampleCmpLevelZeroIntrinsic(Register &ResVReg,
366 SPIRVTypeInst ResType,
367 MachineInstr &I) const;
368 bool selectGatherIntrinsic(Register &ResVReg, SPIRVTypeInst ResType,
369 MachineInstr &I) const;
370 bool selectImageWriteIntrinsic(MachineInstr &I) const;
371 bool selectResourceGetPointer(Register &ResVReg, SPIRVTypeInst ResType,
372 MachineInstr &I) const;
373 bool selectPushConstantGetPointer(Register &ResVReg, SPIRVTypeInst ResType,
374 MachineInstr &I) const;
375 bool selectResourceNonUniformIndex(Register &ResVReg, SPIRVTypeInst ResType,
376 MachineInstr &I) const;
377 bool selectModf(Register ResVReg, SPIRVTypeInst ResType,
378 MachineInstr &I) const;
379 bool selectUpdateCounter(Register &ResVReg, SPIRVTypeInst ResType,
380 MachineInstr &I) const;
381 bool selectFrexp(Register ResVReg, SPIRVTypeInst ResType,
382 MachineInstr &I) const;
383 bool selectSincos(Register ResVReg, SPIRVTypeInst ResType,
384 MachineInstr &I) const;
385 bool selectExp10(Register ResVReg, SPIRVTypeInst ResType,
386 MachineInstr &I) const;
387 bool selectDerivativeInst(Register ResVReg, SPIRVTypeInst ResType,
388 MachineInstr &I, const unsigned DPdOpCode) const;
389 // Utilities
390 Register buildI32Constant(uint32_t Val, MachineInstr &I,
391 SPIRVTypeInst ResType = nullptr) const;
392
393 Register buildZerosVal(SPIRVTypeInst ResType, MachineInstr &I) const;
394 bool isScalarOrVectorIntConstantZero(Register Reg) const;
395 Register buildZerosValF(SPIRVTypeInst ResType, MachineInstr &I) const;
396 Register buildOnesVal(bool AllOnes, SPIRVTypeInst ResType,
397 MachineInstr &I) const;
398 Register buildOnesValF(SPIRVTypeInst ResType, MachineInstr &I) const;
399
400 bool wrapIntoSpecConstantOp(MachineInstr &I,
401 SmallVector<Register> &CompositeArgs) const;
402
403 Register getUcharPtrTypeReg(MachineInstr &I,
404 SPIRV::StorageClass::StorageClass SC) const;
405 MachineInstrBuilder buildSpecConstantOp(MachineInstr &I, Register Dest,
406 Register Src, Register DestType,
407 uint32_t Opcode) const;
408 MachineInstrBuilder buildConstGenericPtr(MachineInstr &I, Register SrcPtr,
409 SPIRVTypeInst SrcPtrTy) const;
410 Register buildPointerToResource(SPIRVTypeInst ResType,
411 SPIRV::StorageClass::StorageClass SC,
412 uint32_t Set, uint32_t Binding,
413 uint32_t ArraySize, Register IndexReg,
414 StringRef Name,
415 MachineIRBuilder MIRBuilder) const;
416 SPIRVTypeInst widenTypeToVec4(SPIRVTypeInst Type, MachineInstr &I) const;
417 bool extractSubvector(Register &ResVReg, SPIRVTypeInst ResType,
418 Register &ReadReg, MachineInstr &InsertionPoint) const;
419 bool generateImageReadOrFetch(Register &ResVReg, SPIRVTypeInst ResType,
420 Register ImageReg, Register IdxReg,
421 DebugLoc Loc, MachineInstr &Pos) const;
422 bool generateSampleImage(Register ResVReg, SPIRVTypeInst ResType,
423 Register ImageReg, Register SamplerReg,
424 Register CoordinateReg, const ImageOperands &ImOps,
425 DebugLoc Loc, MachineInstr &I) const;
426 bool BuildCOPY(Register DestReg, Register SrcReg, MachineInstr &I) const;
427 bool loadVec3BuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue,
428 Register ResVReg, SPIRVTypeInst ResType,
429 MachineInstr &I) const;
430 bool loadBuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue,
431 Register ResVReg, SPIRVTypeInst ResType,
432 MachineInstr &I) const;
433 bool loadHandleBeforePosition(Register &HandleReg, SPIRVTypeInst ResType,
434 GIntrinsic &HandleDef, MachineInstr &Pos) const;
435 void decorateUsesAsNonUniform(Register &NonUniformReg) const;
436 void errorIfInstrOutsideShader(MachineInstr &I) const;
437};
438
439bool sampledTypeIsSignedInteger(const llvm::Type *HandleType) {
440 const TargetExtType *TET = cast<TargetExtType>(HandleType);
441 if (TET->getTargetExtName() == "spirv.Image") {
442 return false;
443 }
444 assert(TET->getTargetExtName() == "spirv.SignedImage");
445 return TET->getTypeParameter(0)->isIntegerTy();
446}
447} // end anonymous namespace
448
449#define GET_GLOBALISEL_IMPL
450#include "SPIRVGenGlobalISel.inc"
451#undef GET_GLOBALISEL_IMPL
452
453SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
454 const SPIRVSubtarget &ST,
455 const RegisterBankInfo &RBI)
456 : InstructionSelector(), STI(ST), TII(*ST.getInstrInfo()),
457 TRI(*ST.getRegisterInfo()), RBI(RBI), GR(*ST.getSPIRVGlobalRegistry()),
458 MRI(nullptr),
460#include "SPIRVGenGlobalISel.inc"
463#include "SPIRVGenGlobalISel.inc"
465{
466}
467
468void SPIRVInstructionSelector::setupMF(MachineFunction &MF,
470 CodeGenCoverage *CoverageInfo,
472 BlockFrequencyInfo *BFI) {
473 MRI = &MF.getRegInfo();
474 GR.setCurrentFunc(MF);
475 InstructionSelector::setupMF(MF, VT, CoverageInfo, PSI, BFI);
476}
477
478// Ensure that register classes correspond to pattern matching rules.
479void SPIRVInstructionSelector::resetVRegsType(MachineFunction &MF) {
480 if (HasVRegsReset == &MF)
481 return;
482 HasVRegsReset = &MF;
483
484 MachineRegisterInfo &MRI = MF.getRegInfo();
485 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
486 Register Reg = Register::index2VirtReg(I);
487 LLT RegType = MRI.getType(Reg);
488 if (RegType.isScalar())
489 MRI.setType(Reg, LLT::scalar(64));
490 else if (RegType.isPointer())
491 MRI.setType(Reg, LLT::pointer(0, 64));
492 else if (RegType.isVector())
493 MRI.setType(Reg, LLT::fixed_vector(2, LLT::scalar(64)));
494 }
495 for (const auto &MBB : MF) {
496 for (const auto &MI : MBB) {
497 if (isPreISelGenericOpcode(MI.getOpcode()))
498 GR.erase(&MI);
499 if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)
500 continue;
501
502 Register DstReg = MI.getOperand(0).getReg();
503 LLT DstType = MRI.getType(DstReg);
504 Register SrcReg = MI.getOperand(1).getReg();
505 LLT SrcType = MRI.getType(SrcReg);
506 if (DstType != SrcType)
507 MRI.setType(DstReg, MRI.getType(SrcReg));
508
509 const TargetRegisterClass *DstRC = MRI.getRegClassOrNull(DstReg);
510 const TargetRegisterClass *SrcRC = MRI.getRegClassOrNull(SrcReg);
511 if (DstRC != SrcRC && SrcRC)
512 MRI.setRegClass(DstReg, SrcRC);
513 }
514 }
515}
516
517// Return true if the MachineInstr represents a constant register
519
520 SmallVector<MachineInstr *> Stack = {OpDef};
522
523 while (!Stack.empty()) {
524 MachineInstr *MI = Stack.pop_back_val();
525 MI = passCopy(MI, MRI);
526 if (!Visited.insert(MI).second)
527 continue;
528 switch (MI->getOpcode()) {
529 case TargetOpcode::G_INTRINSIC:
530 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
531 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
532 if (cast<GIntrinsic>(*OpDef).getIntrinsicID() !=
533 Intrinsic::spv_const_composite)
534 return false;
535 continue;
536 case TargetOpcode::G_BUILD_VECTOR:
537 case TargetOpcode::G_SPLAT_VECTOR:
538 for (unsigned i = OpDef->getNumExplicitDefs();
539 i < OpDef->getNumOperands(); i++) {
540 if (!OpDef->getOperand(i).isReg())
541 continue;
542 MachineInstr *OpNestedDef =
543 MRI->getVRegDef(OpDef->getOperand(i).getReg());
544 Stack.push_back(OpNestedDef);
545 }
546 continue;
547 case TargetOpcode::G_CONSTANT:
548 case TargetOpcode::G_FCONSTANT:
549 case TargetOpcode::G_IMPLICIT_DEF:
550 case SPIRV::OpConstantTrue:
551 case SPIRV::OpConstantFalse:
552 case SPIRV::OpConstantI:
553 case SPIRV::OpConstantF:
554 case SPIRV::OpConstantComposite:
555 case SPIRV::OpConstantCompositeContinuedINTEL:
556 case SPIRV::OpConstantSampler:
557 case SPIRV::OpConstantNull:
558 case SPIRV::OpUndef:
559 case SPIRV::OpConstantFunctionPointerINTEL:
560 continue;
561 default:
562 return false;
563 }
564 }
565 return true;
566}
567
568// Return true if the virtual register represents a constant
570 if (MachineInstr *OpDef = MRI->getVRegDef(OpReg))
571 return isConstReg(MRI, OpDef);
572 return false;
573}
574
575// TODO(168736): We should make this either a flag in tabelgen
576// or reduce our dependence on the global registry, so we can remove this
577// function. It can easily be missed when new intrinsics are added.
578
579// Most SPIR-V intrinsics are considered to have side-effects in their tablegen
580// definition because they are referenced in the global registry. This is a list
581// of intrinsics that have no side effects other than their references in the
582// global registry.
584 switch (ID) {
585 // This is not an exhaustive list and may need to be updated.
586 case Intrinsic::spv_all:
587 case Intrinsic::spv_alloca:
588 case Intrinsic::spv_any:
589 case Intrinsic::spv_bitcast:
590 case Intrinsic::spv_const_composite:
591 case Intrinsic::spv_cross:
592 case Intrinsic::spv_degrees:
593 case Intrinsic::spv_distance:
594 case Intrinsic::spv_extractelt:
595 case Intrinsic::spv_extractv:
596 case Intrinsic::spv_faceforward:
597 case Intrinsic::spv_fdot:
598 case Intrinsic::spv_firstbitlow:
599 case Intrinsic::spv_firstbitshigh:
600 case Intrinsic::spv_firstbituhigh:
601 case Intrinsic::spv_frac:
602 case Intrinsic::spv_gep:
603 case Intrinsic::spv_global_offset:
604 case Intrinsic::spv_global_size:
605 case Intrinsic::spv_group_id:
606 case Intrinsic::spv_insertelt:
607 case Intrinsic::spv_insertv:
608 case Intrinsic::spv_isinf:
609 case Intrinsic::spv_isnan:
610 case Intrinsic::spv_lerp:
611 case Intrinsic::spv_length:
612 case Intrinsic::spv_normalize:
613 case Intrinsic::spv_num_subgroups:
614 case Intrinsic::spv_num_workgroups:
615 case Intrinsic::spv_ptrcast:
616 case Intrinsic::spv_radians:
617 case Intrinsic::spv_reflect:
618 case Intrinsic::spv_refract:
619 case Intrinsic::spv_resource_getpointer:
620 case Intrinsic::spv_resource_handlefrombinding:
621 case Intrinsic::spv_resource_handlefromimplicitbinding:
622 case Intrinsic::spv_resource_nonuniformindex:
623 case Intrinsic::spv_resource_sample:
624 case Intrinsic::spv_rsqrt:
625 case Intrinsic::spv_saturate:
626 case Intrinsic::spv_sdot:
627 case Intrinsic::spv_sign:
628 case Intrinsic::spv_smoothstep:
629 case Intrinsic::spv_step:
630 case Intrinsic::spv_subgroup_id:
631 case Intrinsic::spv_subgroup_local_invocation_id:
632 case Intrinsic::spv_subgroup_max_size:
633 case Intrinsic::spv_subgroup_size:
634 case Intrinsic::spv_thread_id:
635 case Intrinsic::spv_thread_id_in_group:
636 case Intrinsic::spv_udot:
637 case Intrinsic::spv_undef:
638 case Intrinsic::spv_value_md:
639 case Intrinsic::spv_workgroup_size:
640 return false;
641 default:
642 return true;
643 }
644}
645
646// TODO(168736): We should make this either a flag in tabelgen
647// or reduce our dependence on the global registry, so we can remove this
648// function. It can easily be missed when new intrinsics are added.
649static bool isOpcodeWithNoSideEffects(unsigned Opcode) {
650 switch (Opcode) {
651 case SPIRV::OpTypeVoid:
652 case SPIRV::OpTypeBool:
653 case SPIRV::OpTypeInt:
654 case SPIRV::OpTypeFloat:
655 case SPIRV::OpTypeVector:
656 case SPIRV::OpTypeMatrix:
657 case SPIRV::OpTypeImage:
658 case SPIRV::OpTypeSampler:
659 case SPIRV::OpTypeSampledImage:
660 case SPIRV::OpTypeArray:
661 case SPIRV::OpTypeRuntimeArray:
662 case SPIRV::OpTypeStruct:
663 case SPIRV::OpTypeOpaque:
664 case SPIRV::OpTypePointer:
665 case SPIRV::OpTypeFunction:
666 case SPIRV::OpTypeEvent:
667 case SPIRV::OpTypeDeviceEvent:
668 case SPIRV::OpTypeReserveId:
669 case SPIRV::OpTypeQueue:
670 case SPIRV::OpTypePipe:
671 case SPIRV::OpTypeForwardPointer:
672 case SPIRV::OpTypePipeStorage:
673 case SPIRV::OpTypeNamedBarrier:
674 case SPIRV::OpTypeAccelerationStructureNV:
675 case SPIRV::OpTypeCooperativeMatrixNV:
676 case SPIRV::OpTypeCooperativeMatrixKHR:
677 return true;
678 default:
679 return false;
680 }
681}
682
684 // If there are no definitions, then assume there is some other
685 // side-effect that makes this instruction live.
686 if (MI.getNumDefs() == 0)
687 return false;
688
689 for (const auto &MO : MI.all_defs()) {
690 Register Reg = MO.getReg();
691 if (Reg.isPhysical()) {
692 LLVM_DEBUG(dbgs() << "Not dead: def of physical register " << Reg);
693 return false;
694 }
695 for (const auto &UseMI : MRI.use_nodbg_instructions(Reg)) {
696 if (UseMI.getOpcode() != SPIRV::OpName) {
697 LLVM_DEBUG(dbgs() << "Not dead: def " << MO << " has use in " << UseMI);
698 return false;
699 }
700 }
701 }
702
703 if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE || MI.isFakeUse() ||
704 MI.isLifetimeMarker()) {
706 dbgs()
707 << "Not dead: Opcode is LOCAL_ESCAPE, fake use, or lifetime marker.\n");
708 return false;
709 }
710 if (MI.isPHI()) {
711 LLVM_DEBUG(dbgs() << "Dead: Phi instruction with no uses.\n");
712 return true;
713 }
714
715 // It is possible that the only side effect is that the instruction is
716 // referenced in the global registry. If that is the only side effect, the
717 // intrinsic is dead.
718 if (MI.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
719 MI.getOpcode() == TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS) {
720 const auto &Intr = cast<GIntrinsic>(MI);
721 if (!intrinsicHasSideEffects(Intr.getIntrinsicID())) {
722 LLVM_DEBUG(dbgs() << "Dead: Intrinsic with no real side effects.\n");
723 return true;
724 }
725 }
726
727 if (MI.mayStore() || MI.isCall() ||
728 (MI.mayLoad() && MI.hasOrderedMemoryRef()) || MI.isPosition() ||
729 MI.isDebugInstr() || MI.isTerminator() || MI.isJumpTableDebugInfo()) {
730 LLVM_DEBUG(dbgs() << "Not dead: instruction has side effects.\n");
731 return false;
732 }
733
734 if (isPreISelGenericOpcode(MI.getOpcode())) {
735 // TODO: Is there a generic way to check if the opcode has side effects?
736 LLVM_DEBUG(dbgs() << "Dead: Generic opcode with no uses.\n");
737 return true;
738 }
739
740 if (isOpcodeWithNoSideEffects(MI.getOpcode())) {
741 LLVM_DEBUG(dbgs() << "Dead: known opcode with no side effects\n");
742 return true;
743 }
744
745 return false;
746}
747
748void SPIRVInstructionSelector::removeOpNamesForDeadMI(MachineInstr &MI) const {
749 // Delete the OpName that uses the result if there is one.
750 for (const auto &MO : MI.all_defs()) {
751 Register Reg = MO.getReg();
752 if (Reg.isPhysical())
753 continue;
754 SmallVector<MachineInstr *, 4> UselessOpNames;
755 for (MachineInstr &UseMI : MRI->use_nodbg_instructions(Reg)) {
756 assert(UseMI.getOpcode() == SPIRV::OpName &&
757 "There is still a use of the dead function.");
758 UselessOpNames.push_back(&UseMI);
759 }
760 for (MachineInstr *OpNameMI : UselessOpNames) {
761 GR.invalidateMachineInstr(OpNameMI);
762 OpNameMI->eraseFromParent();
763 }
764 }
765}
766
767void SPIRVInstructionSelector::removeDeadInstruction(MachineInstr &MI) const {
770 removeOpNamesForDeadMI(MI);
771 MI.eraseFromParent();
772}
773
774bool SPIRVInstructionSelector::select(MachineInstr &I) {
775 resetVRegsType(*I.getParent()->getParent());
776
777 assert(I.getParent() && "Instruction should be in a basic block!");
778 assert(I.getParent()->getParent() && "Instruction should be in a function!");
779
780 LLVM_DEBUG(dbgs() << "Checking if instruction is dead: " << I;);
781 if (isDead(I, *MRI)) {
782 LLVM_DEBUG(dbgs() << "Instruction is dead.\n");
783 removeDeadInstruction(I);
784 return true;
785 }
786
787 Register Opcode = I.getOpcode();
788 // If it's not a GMIR instruction, we've selected it already.
789 if (!isPreISelGenericOpcode(Opcode)) {
790 if (Opcode == SPIRV::ASSIGN_TYPE) { // These pseudos aren't needed any more.
791 Register DstReg = I.getOperand(0).getReg();
792 Register SrcReg = I.getOperand(1).getReg();
793 auto *Def = MRI->getVRegDef(SrcReg);
794 if (isTypeFoldingSupported(Def->getOpcode()) &&
795 Def->getOpcode() != TargetOpcode::G_CONSTANT &&
796 Def->getOpcode() != TargetOpcode::G_FCONSTANT) {
797 bool Res = false;
798 if (Def->getOpcode() == TargetOpcode::G_SELECT) {
799 Register SelectDstReg = Def->getOperand(0).getReg();
800 Res = selectSelect(SelectDstReg, GR.getSPIRVTypeForVReg(SelectDstReg),
801 *Def);
803 Def->removeFromParent();
804 MRI->replaceRegWith(DstReg, SelectDstReg);
806 I.removeFromParent();
807 } else
808 Res = selectImpl(I, *CoverageInfo);
809 LLVM_DEBUG({
810 if (!Res && Def->getOpcode() != TargetOpcode::G_CONSTANT) {
811 dbgs() << "Unexpected pattern in ASSIGN_TYPE.\nInstruction: ";
812 I.print(dbgs());
813 }
814 });
815 assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT);
816 if (Res) {
817 if (!isTriviallyDead(*Def, *MRI) && isDead(*Def, *MRI))
818 DeadMIs.insert(Def);
819 return Res;
820 }
821 }
822 MRI->setRegClass(SrcReg, MRI->getRegClass(DstReg));
823 MRI->replaceRegWith(SrcReg, DstReg);
825 I.eraseFromParent();
826 return true;
827 } else if (I.getNumDefs() == 1) {
828 // Make all vregs 64 bits (for SPIR-V IDs).
829 MRI->setType(I.getOperand(0).getReg(), LLT::scalar(64));
830 }
832 return true;
833 }
834
835 if (DeadMIs.contains(&I)) {
836 // if the instruction has been already made dead by folding it away
837 // erase it
838 LLVM_DEBUG(dbgs() << "Instruction is folded and dead.\n");
839 removeDeadInstruction(I);
840 DeadMIs.erase(&I);
841 return true;
842 }
843
844 if (I.getNumOperands() != I.getNumExplicitOperands()) {
845 LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
846 return false;
847 }
848
849 // Common code for getting return reg+type, and removing selected instr
850 // from parent occurs here. Instr-specific selection happens in spvSelect().
851 bool HasDefs = I.getNumDefs() > 0;
852 Register ResVReg = HasDefs ? I.getOperand(0).getReg() : Register(0);
853 SPIRVTypeInst ResType = HasDefs ? GR.getSPIRVTypeForVReg(ResVReg) : nullptr;
854 assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
855 I.getOpcode() == TargetOpcode::G_IMPLICIT_DEF);
856 if (spvSelect(ResVReg, ResType, I)) {
857 if (HasDefs) // Make all vregs 64 bits (for SPIR-V IDs).
858 for (unsigned i = 0; i < I.getNumDefs(); ++i)
859 MRI->setType(I.getOperand(i).getReg(), LLT::scalar(64));
861 I.eraseFromParent();
862 return true;
863 }
864 return false;
865}
866
867static bool mayApplyGenericSelection(unsigned Opcode) {
868 switch (Opcode) {
869 case TargetOpcode::G_CONSTANT:
870 case TargetOpcode::G_FCONSTANT:
871 return false;
872 case TargetOpcode::G_SADDO:
873 case TargetOpcode::G_SSUBO:
874 return true;
875 }
876 return isTypeFoldingSupported(Opcode);
877}
878
879bool SPIRVInstructionSelector::BuildCOPY(Register DestReg, Register SrcReg,
880 MachineInstr &I) const {
881 const TargetRegisterClass *DstRC = MRI->getRegClassOrNull(DestReg);
882 const TargetRegisterClass *SrcRC = MRI->getRegClassOrNull(SrcReg);
883 if (DstRC != SrcRC && SrcRC)
884 MRI->setRegClass(DestReg, SrcRC);
885 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::COPY))
886 .addDef(DestReg)
887 .addUse(SrcReg)
888 .constrainAllUses(TII, TRI, RBI);
889 return true;
890}
891
892bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
893 SPIRVTypeInst ResType,
894 MachineInstr &I) const {
895 const unsigned Opcode = I.getOpcode();
896 if (mayApplyGenericSelection(Opcode))
897 return selectImpl(I, *CoverageInfo);
898 switch (Opcode) {
899 case TargetOpcode::G_CONSTANT:
900 case TargetOpcode::G_FCONSTANT:
901 return selectConst(ResVReg, ResType, I);
902 case TargetOpcode::G_GLOBAL_VALUE:
903 return selectGlobalValue(ResVReg, I);
904 case TargetOpcode::G_IMPLICIT_DEF:
905 return selectOpUndef(ResVReg, ResType, I);
906 case TargetOpcode::G_FREEZE:
907 return selectFreeze(ResVReg, ResType, I);
908
909 case TargetOpcode::G_INTRINSIC:
910 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
911 case TargetOpcode::G_INTRINSIC_CONVERGENT:
912 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
913 return selectIntrinsic(ResVReg, ResType, I);
914 case TargetOpcode::G_BITREVERSE:
915 return selectBitreverse(ResVReg, ResType, I);
916
917 case TargetOpcode::G_BUILD_VECTOR:
918 return selectBuildVector(ResVReg, ResType, I);
919 case TargetOpcode::G_SPLAT_VECTOR:
920 return selectSplatVector(ResVReg, ResType, I);
921
922 case TargetOpcode::G_SHUFFLE_VECTOR: {
923 MachineBasicBlock &BB = *I.getParent();
924 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle))
925 .addDef(ResVReg)
926 .addUse(GR.getSPIRVTypeID(ResType))
927 .addUse(I.getOperand(1).getReg())
928 .addUse(I.getOperand(2).getReg());
929 for (auto V : I.getOperand(3).getShuffleMask())
930 MIB.addImm(V);
931 MIB.constrainAllUses(TII, TRI, RBI);
932 return true;
933 }
934 case TargetOpcode::G_MEMMOVE:
935 case TargetOpcode::G_MEMCPY:
936 case TargetOpcode::G_MEMSET:
937 return selectMemOperation(ResVReg, I);
938
939 case TargetOpcode::G_ICMP:
940 return selectICmp(ResVReg, ResType, I);
941 case TargetOpcode::G_FCMP:
942 return selectFCmp(ResVReg, ResType, I);
943
944 case TargetOpcode::G_FRAME_INDEX:
945 return selectFrameIndex(ResVReg, ResType, I);
946
947 case TargetOpcode::G_LOAD:
948 return selectLoad(ResVReg, ResType, I);
949 case TargetOpcode::G_STORE:
950 return selectStore(I);
951
952 case TargetOpcode::G_BR:
953 return selectBranch(I);
954 case TargetOpcode::G_BRCOND:
955 return selectBranchCond(I);
956
957 case TargetOpcode::G_PHI:
958 return selectPhi(ResVReg, I);
959
960 case TargetOpcode::G_FPTOSI:
961 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
962 case TargetOpcode::G_FPTOUI:
963 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
964
965 case TargetOpcode::G_FPTOSI_SAT:
966 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
967 case TargetOpcode::G_FPTOUI_SAT:
968 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
969
970 case TargetOpcode::G_SITOFP:
971 return selectIToF(ResVReg, ResType, I, true, SPIRV::OpConvertSToF);
972 case TargetOpcode::G_UITOFP:
973 return selectIToF(ResVReg, ResType, I, false, SPIRV::OpConvertUToF);
974
975 case TargetOpcode::G_CTPOP:
976 return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitCount);
977 case TargetOpcode::G_SMIN:
978 return selectExtInst(ResVReg, ResType, I, CL::s_min, GL::SMin);
979 case TargetOpcode::G_UMIN:
980 return selectExtInst(ResVReg, ResType, I, CL::u_min, GL::UMin);
981
982 case TargetOpcode::G_SMAX:
983 return selectExtInst(ResVReg, ResType, I, CL::s_max, GL::SMax);
984 case TargetOpcode::G_UMAX:
985 return selectExtInst(ResVReg, ResType, I, CL::u_max, GL::UMax);
986
987 case TargetOpcode::G_SCMP:
988 return selectSUCmp(ResVReg, ResType, I, true);
989 case TargetOpcode::G_UCMP:
990 return selectSUCmp(ResVReg, ResType, I, false);
991 case TargetOpcode::G_LROUND:
992 case TargetOpcode::G_LLROUND: {
993 Register regForLround =
994 MRI->createVirtualRegister(MRI->getRegClass(ResVReg), "lround");
995 MRI->setRegClass(regForLround, &SPIRV::iIDRegClass);
996 GR.assignSPIRVTypeToVReg(GR.getSPIRVTypeForVReg(I.getOperand(1).getReg()),
997 regForLround, *(I.getParent()->getParent()));
998 selectExtInst(regForLround, GR.getSPIRVTypeForVReg(regForLround), I,
999 CL::round, GL::Round, /* setMIFlags */ false);
1000 MachineBasicBlock &BB = *I.getParent();
1001 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConvertFToS))
1002 .addDef(ResVReg)
1003 .addUse(GR.getSPIRVTypeID(ResType))
1004 .addUse(regForLround);
1005 MIB.constrainAllUses(TII, TRI, RBI);
1006 return true;
1007 }
1008 case TargetOpcode::G_STRICT_FMA:
1009 case TargetOpcode::G_FMA: {
1010 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_fma)) {
1011 MachineBasicBlock &BB = *I.getParent();
1012 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpFmaKHR))
1013 .addDef(ResVReg)
1014 .addUse(GR.getSPIRVTypeID(ResType))
1015 .addUse(I.getOperand(1).getReg())
1016 .addUse(I.getOperand(2).getReg())
1017 .addUse(I.getOperand(3).getReg())
1018 .setMIFlags(I.getFlags());
1019 MIB.constrainAllUses(TII, TRI, RBI);
1020 return true;
1021 }
1022 return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
1023 }
1024
1025 case TargetOpcode::G_STRICT_FLDEXP:
1026 return selectExtInst(ResVReg, ResType, I, CL::ldexp);
1027
1028 case TargetOpcode::G_FPOW:
1029 return selectExtInst(ResVReg, ResType, I, CL::pow, GL::Pow);
1030 case TargetOpcode::G_FPOWI:
1031 return selectExtInst(ResVReg, ResType, I, CL::pown);
1032
1033 case TargetOpcode::G_FEXP:
1034 return selectExtInst(ResVReg, ResType, I, CL::exp, GL::Exp);
1035 case TargetOpcode::G_FEXP2:
1036 return selectExtInst(ResVReg, ResType, I, CL::exp2, GL::Exp2);
1037 case TargetOpcode::G_FEXP10:
1038 return selectExp10(ResVReg, ResType, I);
1039
1040 case TargetOpcode::G_FMODF:
1041 return selectModf(ResVReg, ResType, I);
1042 case TargetOpcode::G_FSINCOS:
1043 return selectSincos(ResVReg, ResType, I);
1044
1045 case TargetOpcode::G_FLOG:
1046 return selectExtInst(ResVReg, ResType, I, CL::log, GL::Log);
1047 case TargetOpcode::G_FLOG2:
1048 return selectExtInst(ResVReg, ResType, I, CL::log2, GL::Log2);
1049 case TargetOpcode::G_FLOG10:
1050 return selectLog10(ResVReg, ResType, I);
1051
1052 case TargetOpcode::G_FABS:
1053 return selectExtInst(ResVReg, ResType, I, CL::fabs, GL::FAbs);
1054 case TargetOpcode::G_ABS:
1055 return selectExtInst(ResVReg, ResType, I, CL::s_abs, GL::SAbs);
1056
1057 case TargetOpcode::G_FMINNUM:
1058 case TargetOpcode::G_FMINIMUM:
1059 return selectExtInst(ResVReg, ResType, I, CL::fmin, GL::NMin);
1060 case TargetOpcode::G_FMAXNUM:
1061 case TargetOpcode::G_FMAXIMUM:
1062 return selectExtInst(ResVReg, ResType, I, CL::fmax, GL::NMax);
1063
1064 case TargetOpcode::G_FCOPYSIGN:
1065 return selectExtInst(ResVReg, ResType, I, CL::copysign);
1066
1067 case TargetOpcode::G_FCEIL:
1068 return selectExtInst(ResVReg, ResType, I, CL::ceil, GL::Ceil);
1069 case TargetOpcode::G_FFLOOR:
1070 return selectExtInst(ResVReg, ResType, I, CL::floor, GL::Floor);
1071
1072 case TargetOpcode::G_FCOS:
1073 return selectExtInst(ResVReg, ResType, I, CL::cos, GL::Cos);
1074 case TargetOpcode::G_FSIN:
1075 return selectExtInst(ResVReg, ResType, I, CL::sin, GL::Sin);
1076 case TargetOpcode::G_FTAN:
1077 return selectExtInst(ResVReg, ResType, I, CL::tan, GL::Tan);
1078 case TargetOpcode::G_FACOS:
1079 return selectExtInst(ResVReg, ResType, I, CL::acos, GL::Acos);
1080 case TargetOpcode::G_FASIN:
1081 return selectExtInst(ResVReg, ResType, I, CL::asin, GL::Asin);
1082 case TargetOpcode::G_FATAN:
1083 return selectExtInst(ResVReg, ResType, I, CL::atan, GL::Atan);
1084 case TargetOpcode::G_FATAN2:
1085 return selectExtInst(ResVReg, ResType, I, CL::atan2, GL::Atan2);
1086 case TargetOpcode::G_FCOSH:
1087 return selectExtInst(ResVReg, ResType, I, CL::cosh, GL::Cosh);
1088 case TargetOpcode::G_FSINH:
1089 return selectExtInst(ResVReg, ResType, I, CL::sinh, GL::Sinh);
1090 case TargetOpcode::G_FTANH:
1091 return selectExtInst(ResVReg, ResType, I, CL::tanh, GL::Tanh);
1092
1093 case TargetOpcode::G_STRICT_FSQRT:
1094 case TargetOpcode::G_FSQRT:
1095 return selectExtInst(ResVReg, ResType, I, CL::sqrt, GL::Sqrt);
1096
1097 case TargetOpcode::G_CTTZ:
1098 case TargetOpcode::G_CTTZ_ZERO_UNDEF:
1099 return selectExtInst(ResVReg, ResType, I, CL::ctz);
1100 case TargetOpcode::G_CTLZ:
1101 case TargetOpcode::G_CTLZ_ZERO_UNDEF:
1102 return selectExtInst(ResVReg, ResType, I, CL::clz);
1103
1104 case TargetOpcode::G_INTRINSIC_ROUND:
1105 return selectExtInst(ResVReg, ResType, I, CL::round, GL::Round);
1106 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1107 return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven);
1108 case TargetOpcode::G_INTRINSIC_TRUNC:
1109 return selectExtInst(ResVReg, ResType, I, CL::trunc, GL::Trunc);
1110 case TargetOpcode::G_FRINT:
1111 case TargetOpcode::G_FNEARBYINT:
1112 return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven);
1113
1114 case TargetOpcode::G_SMULH:
1115 return selectExtInst(ResVReg, ResType, I, CL::s_mul_hi);
1116 case TargetOpcode::G_UMULH:
1117 return selectExtInst(ResVReg, ResType, I, CL::u_mul_hi);
1118
1119 case TargetOpcode::G_SADDSAT:
1120 return selectExtInst(ResVReg, ResType, I, CL::s_add_sat);
1121 case TargetOpcode::G_UADDSAT:
1122 return selectExtInst(ResVReg, ResType, I, CL::u_add_sat);
1123 case TargetOpcode::G_SSUBSAT:
1124 return selectExtInst(ResVReg, ResType, I, CL::s_sub_sat);
1125 case TargetOpcode::G_USUBSAT:
1126 return selectExtInst(ResVReg, ResType, I, CL::u_sub_sat);
1127
1128 case TargetOpcode::G_FFREXP:
1129 return selectFrexp(ResVReg, ResType, I);
1130
1131 case TargetOpcode::G_UADDO:
1132 return selectOverflowArith(ResVReg, ResType, I,
1133 ResType->getOpcode() == SPIRV::OpTypeVector
1134 ? SPIRV::OpIAddCarryV
1135 : SPIRV::OpIAddCarryS);
1136 case TargetOpcode::G_USUBO:
1137 return selectOverflowArith(ResVReg, ResType, I,
1138 ResType->getOpcode() == SPIRV::OpTypeVector
1139 ? SPIRV::OpISubBorrowV
1140 : SPIRV::OpISubBorrowS);
1141 case TargetOpcode::G_UMULO:
1142 return selectOverflowArith(ResVReg, ResType, I, SPIRV::OpUMulExtended);
1143 case TargetOpcode::G_SMULO:
1144 return selectOverflowArith(ResVReg, ResType, I, SPIRV::OpSMulExtended);
1145
1146 case TargetOpcode::G_SEXT:
1147 return selectExt(ResVReg, ResType, I, true);
1148 case TargetOpcode::G_ANYEXT:
1149 case TargetOpcode::G_ZEXT:
1150 return selectExt(ResVReg, ResType, I, false);
1151 case TargetOpcode::G_TRUNC:
1152 return selectTrunc(ResVReg, ResType, I);
1153 case TargetOpcode::G_FPTRUNC:
1154 case TargetOpcode::G_FPEXT:
1155 return selectUnOp(ResVReg, ResType, I, SPIRV::OpFConvert);
1156
1157 case TargetOpcode::G_PTRTOINT:
1158 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertPtrToU);
1159 case TargetOpcode::G_INTTOPTR:
1160 return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertUToPtr);
1161 case TargetOpcode::G_BITCAST:
1162 return selectBitcast(ResVReg, ResType, I);
1163 case TargetOpcode::G_ADDRSPACE_CAST:
1164 return selectAddrSpaceCast(ResVReg, ResType, I);
1165 case TargetOpcode::G_PTR_ADD: {
1166 // Currently, we get G_PTR_ADD only applied to global variables.
1167 assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
1168 Register GV = I.getOperand(1).getReg();
1169 MachineRegisterInfo::def_instr_iterator II = MRI->def_instr_begin(GV);
1170 (void)II;
1171 assert(((*II).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
1172 (*II).getOpcode() == TargetOpcode::COPY ||
1173 (*II).getOpcode() == SPIRV::OpVariable) &&
1174 getImm(I.getOperand(2), MRI));
1175 // It may be the initialization of a global variable.
1176 bool IsGVInit = false;
1178 UseIt = MRI->use_instr_begin(I.getOperand(0).getReg()),
1179 UseEnd = MRI->use_instr_end();
1180 UseIt != UseEnd; UseIt = std::next(UseIt)) {
1181 if ((*UseIt).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
1182 (*UseIt).getOpcode() == SPIRV::OpSpecConstantOp ||
1183 (*UseIt).getOpcode() == SPIRV::OpVariable) {
1184 IsGVInit = true;
1185 break;
1186 }
1187 }
1188 MachineBasicBlock &BB = *I.getParent();
1189 if (!IsGVInit) {
1190 SPIRVTypeInst GVType = GR.getSPIRVTypeForVReg(GV);
1191 SPIRVTypeInst GVPointeeType = GR.getPointeeType(GVType);
1192 SPIRVTypeInst ResPointeeType = GR.getPointeeType(ResType);
1193 if (GVPointeeType && ResPointeeType && GVPointeeType != ResPointeeType) {
1194 // Build a new virtual register that is associated with the required
1195 // data type.
1196 Register NewVReg = MRI->createGenericVirtualRegister(MRI->getType(GV));
1197 MRI->setRegClass(NewVReg, MRI->getRegClass(GV));
1198 // Having a correctly typed base we are ready to build the actually
1199 // required GEP. It may not be a constant though, because all Operands
1200 // of OpSpecConstantOp is to originate from other const instructions,
1201 // and only the AccessChain named opcodes accept a global OpVariable
1202 // instruction. We can't use an AccessChain opcode because of the type
1203 // mismatch between result and base types.
1204 if (!GR.isBitcastCompatible(ResType, GVType))
1206 "incompatible result and operand types in a bitcast");
1207 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
1208 MachineInstrBuilder MIB =
1209 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitcast))
1210 .addDef(NewVReg)
1211 .addUse(ResTypeReg)
1212 .addUse(GV);
1213 MIB.constrainAllUses(TII, TRI, RBI);
1214 BuildMI(BB, I, I.getDebugLoc(),
1215 TII.get(STI.isLogicalSPIRV() ? SPIRV::OpInBoundsAccessChain
1216 : SPIRV::OpInBoundsPtrAccessChain))
1217 .addDef(ResVReg)
1218 .addUse(ResTypeReg)
1219 .addUse(NewVReg)
1220 .addUse(I.getOperand(2).getReg())
1221 .constrainAllUses(TII, TRI, RBI);
1222 } else {
1223 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
1224 .addDef(ResVReg)
1225 .addUse(GR.getSPIRVTypeID(ResType))
1226 .addImm(
1227 static_cast<uint32_t>(SPIRV::Opcode::InBoundsPtrAccessChain))
1228 .addUse(GV)
1229 .addUse(I.getOperand(2).getReg())
1230 .constrainAllUses(TII, TRI, RBI);
1231 }
1232 return true;
1233 }
1234 // It's possible to translate G_PTR_ADD to OpSpecConstantOp: either to
1235 // initialize a global variable with a constant expression (e.g., the test
1236 // case opencl/basic/progvar_prog_scope_init.ll), or for another use case
1237 Register Idx = buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I);
1238 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
1239 .addDef(ResVReg)
1240 .addUse(GR.getSPIRVTypeID(ResType))
1241 .addImm(static_cast<uint32_t>(
1242 SPIRV::Opcode::InBoundsPtrAccessChain))
1243 .addUse(GV)
1244 .addUse(Idx)
1245 .addUse(I.getOperand(2).getReg());
1246 MIB.constrainAllUses(TII, TRI, RBI);
1247 return true;
1248 }
1249
1250 case TargetOpcode::G_ATOMICRMW_OR:
1251 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicOr);
1252 case TargetOpcode::G_ATOMICRMW_ADD:
1253 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicIAdd);
1254 case TargetOpcode::G_ATOMICRMW_AND:
1255 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicAnd);
1256 case TargetOpcode::G_ATOMICRMW_MAX:
1257 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMax);
1258 case TargetOpcode::G_ATOMICRMW_MIN:
1259 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMin);
1260 case TargetOpcode::G_ATOMICRMW_SUB:
1261 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicISub);
1262 case TargetOpcode::G_ATOMICRMW_XOR:
1263 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicXor);
1264 case TargetOpcode::G_ATOMICRMW_UMAX:
1265 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMax);
1266 case TargetOpcode::G_ATOMICRMW_UMIN:
1267 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMin);
1268 case TargetOpcode::G_ATOMICRMW_XCHG:
1269 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicExchange);
1270 case TargetOpcode::G_ATOMIC_CMPXCHG:
1271 return selectAtomicCmpXchg(ResVReg, ResType, I);
1272
1273 case TargetOpcode::G_ATOMICRMW_FADD:
1274 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFAddEXT);
1275 case TargetOpcode::G_ATOMICRMW_FSUB:
1276 // Translate G_ATOMICRMW_FSUB to OpAtomicFAddEXT with negative value operand
1277 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFAddEXT,
1278 ResType->getOpcode() == SPIRV::OpTypeVector
1279 ? SPIRV::OpFNegateV
1280 : SPIRV::OpFNegate);
1281 case TargetOpcode::G_ATOMICRMW_FMIN:
1282 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFMinEXT);
1283 case TargetOpcode::G_ATOMICRMW_FMAX:
1284 return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFMaxEXT);
1285
1286 case TargetOpcode::G_FENCE:
1287 return selectFence(I);
1288
1289 case TargetOpcode::G_STACKSAVE:
1290 return selectStackSave(ResVReg, ResType, I);
1291 case TargetOpcode::G_STACKRESTORE:
1292 return selectStackRestore(I);
1293
1294 case TargetOpcode::G_UNMERGE_VALUES:
1295 return selectUnmergeValues(I);
1296
1297 // Discard gen opcodes for intrinsics which we do not expect to actually
1298 // represent code after lowering or intrinsics which are not implemented but
1299 // should not crash when found in a customer's LLVM IR input.
1300 case TargetOpcode::G_TRAP:
1301 case TargetOpcode::G_UBSANTRAP:
1302 case TargetOpcode::DBG_LABEL:
1303 return true;
1304 case TargetOpcode::G_DEBUGTRAP:
1305 return selectDebugTrap(ResVReg, ResType, I);
1306
1307 default:
1308 return false;
1309 }
1310}
1311
1312bool SPIRVInstructionSelector::selectDebugTrap(Register ResVReg,
1313 SPIRVTypeInst ResType,
1314 MachineInstr &I) const {
1315 unsigned Opcode = SPIRV::OpNop;
1316 MachineBasicBlock &BB = *I.getParent();
1317 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
1318 .constrainAllUses(TII, TRI, RBI);
1319 return true;
1320}
1321
1322bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
1323 SPIRVTypeInst ResType,
1324 MachineInstr &I,
1325 GL::GLSLExtInst GLInst,
1326 bool setMIFlags, bool useMISrc,
1327 ArrayRef<Register> SrcRegs) const {
1328 if (!STI.canUseExtInstSet(
1329 SPIRV::InstructionSet::InstructionSet::GLSL_std_450)) {
1330 std::string DiagMsg;
1331 raw_string_ostream OS(DiagMsg);
1332 I.print(OS, true, false, false, false);
1333 DiagMsg += " is only supported with the GLSL extended instruction set.\n";
1334 report_fatal_error(DiagMsg.c_str(), false);
1335 }
1336 return selectExtInst(ResVReg, ResType, I,
1337 {{SPIRV::InstructionSet::GLSL_std_450, GLInst}},
1338 setMIFlags, useMISrc, SrcRegs);
1339}
1340
1341bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
1342 SPIRVTypeInst ResType,
1343 MachineInstr &I,
1344 CL::OpenCLExtInst CLInst,
1345 bool setMIFlags, bool useMISrc,
1346 ArrayRef<Register> SrcRegs) const {
1347 return selectExtInst(ResVReg, ResType, I,
1348 {{SPIRV::InstructionSet::OpenCL_std, CLInst}},
1349 setMIFlags, useMISrc, SrcRegs);
1350}
1351
1352bool SPIRVInstructionSelector::selectExtInst(
1353 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
1354 CL::OpenCLExtInst CLInst, GL::GLSLExtInst GLInst, bool setMIFlags,
1355 bool useMISrc, ArrayRef<Register> SrcRegs) const {
1356 ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst},
1357 {SPIRV::InstructionSet::GLSL_std_450, GLInst}};
1358 return selectExtInst(ResVReg, ResType, I, ExtInsts, setMIFlags, useMISrc,
1359 SrcRegs);
1360}
1361
1362bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
1363 SPIRVTypeInst ResType,
1364 MachineInstr &I,
1365 const ExtInstList &Insts,
1366 bool setMIFlags, bool useMISrc,
1367 ArrayRef<Register> SrcRegs) const {
1368
1369 for (const auto &[InstructionSet, Opcode] : Insts) {
1370 if (!STI.canUseExtInstSet(InstructionSet))
1371 continue;
1372 MachineBasicBlock &BB = *I.getParent();
1373 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1374 .addDef(ResVReg)
1375 .addUse(GR.getSPIRVTypeID(ResType))
1376 .addImm(static_cast<uint32_t>(InstructionSet))
1377 .addImm(Opcode);
1378 if (setMIFlags)
1379 MIB.setMIFlags(I.getFlags());
1380 if (useMISrc) {
1381 const unsigned NumOps = I.getNumOperands();
1382 unsigned Index = 1;
1383 if (Index < NumOps &&
1384 I.getOperand(Index).getType() ==
1385 MachineOperand::MachineOperandType::MO_IntrinsicID)
1386 Index = 2;
1387 for (; Index < NumOps; ++Index)
1388 MIB.add(I.getOperand(Index));
1389 } else {
1390 for (Register SReg : SrcRegs) {
1391 MIB.addUse(SReg);
1392 }
1393 }
1394 MIB.constrainAllUses(TII, TRI, RBI);
1395 return true;
1396 }
1397 return false;
1398}
1399
1400bool SPIRVInstructionSelector::selectFrexp(Register ResVReg,
1401 SPIRVTypeInst ResType,
1402 MachineInstr &I) const {
1403 ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CL::frexp},
1404 {SPIRV::InstructionSet::GLSL_std_450, GL::Frexp}};
1405 for (const auto &Ex : ExtInsts) {
1406 SPIRV::InstructionSet::InstructionSet Set = Ex.first;
1407 uint32_t Opcode = Ex.second;
1408 if (!STI.canUseExtInstSet(Set))
1409 continue;
1410
1411 MachineIRBuilder MIRBuilder(I);
1412 SPIRVTypeInst PointeeTy = GR.getSPIRVTypeForVReg(I.getOperand(1).getReg());
1413 const SPIRVTypeInst PointerType = GR.getOrCreateSPIRVPointerType(
1414 PointeeTy, MIRBuilder, SPIRV::StorageClass::Function);
1415 Register PointerVReg =
1416 createVirtualRegister(PointerType, &GR, MRI, MRI->getMF());
1417
1418 auto It = getOpVariableMBBIt(I);
1419 BuildMI(*It->getParent(), It, It->getDebugLoc(), TII.get(SPIRV::OpVariable))
1420 .addDef(PointerVReg)
1421 .addUse(GR.getSPIRVTypeID(PointerType))
1422 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
1423 .constrainAllUses(TII, TRI, RBI);
1424
1425 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1426 .addDef(ResVReg)
1427 .addUse(GR.getSPIRVTypeID(ResType))
1428 .addImm(static_cast<uint32_t>(Ex.first))
1429 .addImm(Opcode)
1430 .add(I.getOperand(2))
1431 .addUse(PointerVReg)
1432 .constrainAllUses(TII, TRI, RBI);
1433
1434 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
1435 .addDef(I.getOperand(1).getReg())
1436 .addUse(GR.getSPIRVTypeID(PointeeTy))
1437 .addUse(PointerVReg)
1438 .constrainAllUses(TII, TRI, RBI);
1439 return true;
1440 }
1441 return false;
1442}
1443
1444bool SPIRVInstructionSelector::selectSincos(Register ResVReg,
1445 SPIRVTypeInst ResType,
1446 MachineInstr &I) const {
1447 Register CosResVReg = I.getOperand(1).getReg();
1448 unsigned SrcIdx = I.getNumExplicitDefs();
1449 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
1450
1451 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
1452 // OpenCL.std sincos(x, cosval*) -> returns sin(x), writes cos(x) to ptr.
1453 MachineIRBuilder MIRBuilder(I);
1454 const SPIRVTypeInst PointerType = GR.getOrCreateSPIRVPointerType(
1455 ResType, MIRBuilder, SPIRV::StorageClass::Function);
1456 Register PointerVReg =
1457 createVirtualRegister(PointerType, &GR, MRI, MRI->getMF());
1458
1459 auto It = getOpVariableMBBIt(I);
1460 BuildMI(*It->getParent(), It, It->getDebugLoc(), TII.get(SPIRV::OpVariable))
1461 .addDef(PointerVReg)
1462 .addUse(GR.getSPIRVTypeID(PointerType))
1463 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
1464 .constrainAllUses(TII, TRI, RBI);
1465 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1466 .addDef(ResVReg)
1467 .addUse(ResTypeReg)
1468 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
1469 .addImm(CL::sincos)
1470 .add(I.getOperand(SrcIdx))
1471 .addUse(PointerVReg)
1472 .constrainAllUses(TII, TRI, RBI);
1473 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
1474 .addDef(CosResVReg)
1475 .addUse(ResTypeReg)
1476 .addUse(PointerVReg)
1477 .constrainAllUses(TII, TRI, RBI);
1478 return true;
1479 } else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
1480 // GLSL.std.450 has no combined sincos; emit separate Sin and Cos.
1481 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1482 .addDef(ResVReg)
1483 .addUse(ResTypeReg)
1484 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1485 .addImm(GL::Sin)
1486 .add(I.getOperand(SrcIdx))
1487 .constrainAllUses(TII, TRI, RBI);
1488 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1489 .addDef(CosResVReg)
1490 .addUse(ResTypeReg)
1491 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1492 .addImm(GL::Cos)
1493 .add(I.getOperand(SrcIdx))
1494 .constrainAllUses(TII, TRI, RBI);
1495 return true;
1496 }
1497 return false;
1498}
1499
1500bool SPIRVInstructionSelector::selectOpWithSrcs(Register ResVReg,
1501 SPIRVTypeInst ResType,
1502 MachineInstr &I,
1503 std::vector<Register> Srcs,
1504 unsigned Opcode) const {
1505 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
1506 .addDef(ResVReg)
1507 .addUse(GR.getSPIRVTypeID(ResType));
1508 for (Register SReg : Srcs) {
1509 MIB.addUse(SReg);
1510 }
1511 MIB.constrainAllUses(TII, TRI, RBI);
1512 return true;
1513}
1514
1515bool SPIRVInstructionSelector::selectUnOp(Register ResVReg,
1516 SPIRVTypeInst ResType,
1517 MachineInstr &I,
1518 unsigned Opcode) const {
1519 if (STI.isPhysicalSPIRV() && I.getOperand(1).isReg()) {
1520 Register SrcReg = I.getOperand(1).getReg();
1521 bool IsGV = false;
1523 MRI->def_instr_begin(SrcReg);
1524 DefIt != MRI->def_instr_end(); DefIt = std::next(DefIt)) {
1525 unsigned DefOpCode = DefIt->getOpcode();
1526 if (DefOpCode == SPIRV::ASSIGN_TYPE || DefOpCode == TargetOpcode::COPY) {
1527 // We need special handling to look through the type assignment or the
1528 // COPY pseudo-op and see if this is a constant or a global.
1529 if (auto *VRD = getVRegDef(*MRI, DefIt->getOperand(1).getReg()))
1530 DefOpCode = VRD->getOpcode();
1531 }
1532 if (DefOpCode == TargetOpcode::G_GLOBAL_VALUE ||
1533 DefOpCode == TargetOpcode::G_CONSTANT ||
1534 DefOpCode == SPIRV::OpVariable || DefOpCode == SPIRV::OpConstantI) {
1535 IsGV = true;
1536 break;
1537 }
1538 }
1539 if (IsGV) {
1540 uint32_t SpecOpcode = 0;
1541 switch (Opcode) {
1542 case SPIRV::OpConvertPtrToU:
1543 SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertPtrToU);
1544 break;
1545 case SPIRV::OpConvertUToPtr:
1546 SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertUToPtr);
1547 break;
1548 }
1549 if (SpecOpcode) {
1550 BuildMI(*I.getParent(), I, I.getDebugLoc(),
1551 TII.get(SPIRV::OpSpecConstantOp))
1552 .addDef(ResVReg)
1553 .addUse(GR.getSPIRVTypeID(ResType))
1554 .addImm(SpecOpcode)
1555 .addUse(SrcReg)
1556 .constrainAllUses(TII, TRI, RBI);
1557 return true;
1558 }
1559 }
1560 }
1561 return selectOpWithSrcs(ResVReg, ResType, I, {I.getOperand(1).getReg()},
1562 Opcode);
1563}
1564
1565bool SPIRVInstructionSelector::selectBitcast(Register ResVReg,
1566 SPIRVTypeInst ResType,
1567 MachineInstr &I) const {
1568 Register OpReg = I.getOperand(1).getReg();
1569 SPIRVTypeInst OpType =
1570 OpReg.isValid() ? GR.getSPIRVTypeForVReg(OpReg) : nullptr;
1571 if (!GR.isBitcastCompatible(ResType, OpType))
1572 report_fatal_error("incompatible result and operand types in a bitcast");
1573 return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast);
1574}
1575
1578 MachineIRBuilder &MIRBuilder,
1579 SPIRVGlobalRegistry &GR) {
1580 const SPIRVSubtarget *ST =
1581 static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget());
1582 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
1583 if (MemOp->isVolatile())
1584 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
1585 if (MemOp->isNonTemporal())
1586 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
1587 // Aligned memory operand requires the Kernel capability.
1588 if (!ST->isShader() && MemOp->getAlign().value())
1589 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned);
1590
1591 [[maybe_unused]] MachineInstr *AliasList = nullptr;
1592 [[maybe_unused]] MachineInstr *NoAliasList = nullptr;
1593 if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing)) {
1594 if (auto *MD = MemOp->getAAInfo().Scope) {
1595 AliasList = GR.getOrAddMemAliasingINTELInst(MIRBuilder, MD);
1596 if (AliasList)
1597 SpvMemOp |=
1598 static_cast<uint32_t>(SPIRV::MemoryOperand::AliasScopeINTELMask);
1599 }
1600 if (auto *MD = MemOp->getAAInfo().NoAlias) {
1601 NoAliasList = GR.getOrAddMemAliasingINTELInst(MIRBuilder, MD);
1602 if (NoAliasList)
1603 SpvMemOp |=
1604 static_cast<uint32_t>(SPIRV::MemoryOperand::NoAliasINTELMask);
1605 }
1606 }
1607
1608 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) {
1609 MIB.addImm(SpvMemOp);
1610 if (SpvMemOp & static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned))
1611 MIB.addImm(MemOp->getAlign().value());
1612 if (AliasList)
1613 MIB.addUse(AliasList->getOperand(0).getReg());
1614 if (NoAliasList)
1615 MIB.addUse(NoAliasList->getOperand(0).getReg());
1616 }
1617}
1618
1620 uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
1622 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
1624 SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
1625
1626 if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None))
1627 MIB.addImm(SpvMemOp);
1628}
1629
1630bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
1631 SPIRVTypeInst ResType,
1632 MachineInstr &I) const {
1633 unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0;
1634 Register Ptr = I.getOperand(1 + OpOffset).getReg();
1635
1636 auto *PtrDef = getVRegDef(*MRI, Ptr);
1637 auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef);
1638 if (IntPtrDef &&
1639 IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1640 Register HandleReg = IntPtrDef->getOperand(2).getReg();
1641 SPIRVTypeInst HandleType = GR.getSPIRVTypeForVReg(HandleReg);
1642 if (HandleType->getOpcode() == SPIRV::OpTypeImage) {
1643 Register NewHandleReg =
1644 MRI->createVirtualRegister(MRI->getRegClass(HandleReg));
1645 auto *HandleDef = cast<GIntrinsic>(getVRegDef(*MRI, HandleReg));
1646 if (!loadHandleBeforePosition(NewHandleReg, HandleType, *HandleDef, I)) {
1647 return false;
1648 }
1649
1650 Register IdxReg = IntPtrDef->getOperand(3).getReg();
1651 return generateImageReadOrFetch(ResVReg, ResType, NewHandleReg, IdxReg,
1652 I.getDebugLoc(), I);
1653 }
1654 }
1655
1656 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
1657 .addDef(ResVReg)
1658 .addUse(GR.getSPIRVTypeID(ResType))
1659 .addUse(Ptr);
1660 if (!I.getNumMemOperands()) {
1661 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
1662 I.getOpcode() ==
1663 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
1664 addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
1665 } else {
1666 MachineIRBuilder MIRBuilder(I);
1667 addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR);
1668 }
1669 MIB.constrainAllUses(TII, TRI, RBI);
1670 return true;
1671}
1672
1673bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
1674 unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0;
1675 Register StoreVal = I.getOperand(0 + OpOffset).getReg();
1676 Register Ptr = I.getOperand(1 + OpOffset).getReg();
1677
1678 auto *PtrDef = getVRegDef(*MRI, Ptr);
1679 auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef);
1680 if (IntPtrDef &&
1681 IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
1682 Register HandleReg = IntPtrDef->getOperand(2).getReg();
1683 Register NewHandleReg =
1684 MRI->createVirtualRegister(MRI->getRegClass(HandleReg));
1685 auto *HandleDef = cast<GIntrinsic>(getVRegDef(*MRI, HandleReg));
1686 SPIRVTypeInst HandleType = GR.getSPIRVTypeForVReg(HandleReg);
1687 if (!loadHandleBeforePosition(NewHandleReg, HandleType, *HandleDef, I)) {
1688 return false;
1689 }
1690
1691 Register IdxReg = IntPtrDef->getOperand(3).getReg();
1692 if (HandleType->getOpcode() == SPIRV::OpTypeImage) {
1693 auto BMI = BuildMI(*I.getParent(), I, I.getDebugLoc(),
1694 TII.get(SPIRV::OpImageWrite))
1695 .addUse(NewHandleReg)
1696 .addUse(IdxReg)
1697 .addUse(StoreVal);
1698
1699 const llvm::Type *LLVMHandleType = GR.getTypeForSPIRVType(HandleType);
1700 if (sampledTypeIsSignedInteger(LLVMHandleType))
1701 BMI.addImm(0x1000); // SignExtend
1702
1703 BMI.constrainAllUses(TII, TRI, RBI);
1704 return true;
1705 }
1706 }
1707
1708 MachineBasicBlock &BB = *I.getParent();
1709 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpStore))
1710 .addUse(Ptr)
1711 .addUse(StoreVal);
1712 if (!I.getNumMemOperands()) {
1713 assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
1714 I.getOpcode() ==
1715 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
1716 addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
1717 } else {
1718 MachineIRBuilder MIRBuilder(I);
1719 addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR);
1720 }
1721 MIB.constrainAllUses(TII, TRI, RBI);
1722 return true;
1723}
1724
1725bool SPIRVInstructionSelector::selectStackSave(Register ResVReg,
1726 SPIRVTypeInst ResType,
1727 MachineInstr &I) const {
1728 if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array))
1730 "llvm.stacksave intrinsic: this instruction requires the following "
1731 "SPIR-V extension: SPV_INTEL_variable_length_array",
1732 false);
1733 MachineBasicBlock &BB = *I.getParent();
1734 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSaveMemoryINTEL))
1735 .addDef(ResVReg)
1736 .addUse(GR.getSPIRVTypeID(ResType))
1737 .constrainAllUses(TII, TRI, RBI);
1738 return true;
1739}
1740
1741bool SPIRVInstructionSelector::selectStackRestore(MachineInstr &I) const {
1742 if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array))
1744 "llvm.stackrestore intrinsic: this instruction requires the following "
1745 "SPIR-V extension: SPV_INTEL_variable_length_array",
1746 false);
1747 if (!I.getOperand(0).isReg())
1748 return false;
1749 MachineBasicBlock &BB = *I.getParent();
1750 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpRestoreMemoryINTEL))
1751 .addUse(I.getOperand(0).getReg())
1752 .constrainAllUses(TII, TRI, RBI);
1753 return true;
1754}
1755
1757SPIRVInstructionSelector::getOrCreateMemSetGlobal(MachineInstr &I) const {
1758 MachineIRBuilder MIRBuilder(I);
1759 assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
1760
1761 // TODO: check if we have such GV, add init, use buildGlobalVariable.
1762 unsigned Num = getIConstVal(I.getOperand(2).getReg(), MRI);
1763 Function &CurFunction = GR.CurMF->getFunction();
1764 Type *LLVMArrTy =
1765 ArrayType::get(IntegerType::get(CurFunction.getContext(), 8), Num);
1766 GlobalVariable *GV = new GlobalVariable(*CurFunction.getParent(), LLVMArrTy,
1768 Constant::getNullValue(LLVMArrTy));
1769
1770 Type *ValTy = Type::getInt8Ty(I.getMF()->getFunction().getContext());
1771 Type *ArrTy = ArrayType::get(ValTy, Num);
1772 SPIRVTypeInst VarTy = GR.getOrCreateSPIRVPointerType(
1773 ArrTy, MIRBuilder, SPIRV::StorageClass::UniformConstant);
1774
1775 SPIRVTypeInst SpvArrTy = GR.getOrCreateSPIRVType(
1776 ArrTy, MIRBuilder, SPIRV::AccessQualifier::None, false);
1777
1778 unsigned Val = getIConstVal(I.getOperand(1).getReg(), MRI);
1779 Register Const = GR.getOrCreateConstIntArray(Val, Num, I, SpvArrTy, TII);
1780
1781 Register VarReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
1782 auto MIBVar =
1783 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
1784 .addDef(VarReg)
1785 .addUse(GR.getSPIRVTypeID(VarTy))
1786 .addImm(SPIRV::StorageClass::UniformConstant)
1787 .addUse(Const);
1788 MIBVar.constrainAllUses(TII, TRI, RBI);
1789
1790 GR.add(GV, MIBVar);
1791 GR.addGlobalObject(GV, GR.CurMF, VarReg);
1792
1793 buildOpDecorate(VarReg, I, TII, SPIRV::Decoration::Constant, {});
1794 return VarReg;
1795}
1796
1797bool SPIRVInstructionSelector::selectCopyMemory(MachineInstr &I,
1798 Register SrcReg) const {
1799 MachineBasicBlock &BB = *I.getParent();
1800 Register DstReg = I.getOperand(0).getReg();
1801 SPIRVTypeInst DstTy = GR.getSPIRVTypeForVReg(DstReg);
1802 SPIRVTypeInst SrcTy = GR.getSPIRVTypeForVReg(SrcReg);
1803 if (GR.getPointeeType(DstTy) != GR.getPointeeType(SrcTy))
1804 report_fatal_error("OpCopyMemory requires operands to have the same type");
1805 uint64_t CopySize = getIConstVal(I.getOperand(2).getReg(), MRI);
1806 SPIRVTypeInst PointeeTy = GR.getPointeeType(DstTy);
1807 const Type *LLVMPointeeTy = GR.getTypeForSPIRVType(PointeeTy);
1808 if (!LLVMPointeeTy)
1810 "Unable to determine pointee type size for OpCopyMemory");
1811 const DataLayout &DL = I.getMF()->getFunction().getDataLayout();
1812 if (CopySize != DL.getTypeStoreSize(const_cast<Type *>(LLVMPointeeTy)))
1814 "OpCopyMemory requires the size to match the pointee type size");
1815 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemory))
1816 .addUse(DstReg)
1817 .addUse(SrcReg);
1818 if (I.getNumMemOperands()) {
1819 MachineIRBuilder MIRBuilder(I);
1820 addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR);
1821 }
1822 MIB.constrainAllUses(TII, TRI, RBI);
1823 return true;
1824}
1825
1826bool SPIRVInstructionSelector::selectCopyMemorySized(MachineInstr &I,
1827 Register SrcReg) const {
1828 MachineBasicBlock &BB = *I.getParent();
1829 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemorySized))
1830 .addUse(I.getOperand(0).getReg())
1831 .addUse(SrcReg)
1832 .addUse(I.getOperand(2).getReg());
1833 if (I.getNumMemOperands()) {
1834 MachineIRBuilder MIRBuilder(I);
1835 addMemoryOperands(*I.memoperands_begin(), MIB, MIRBuilder, GR);
1836 }
1837 MIB.constrainAllUses(TII, TRI, RBI);
1838 return true;
1839}
1840
1841bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg,
1842 MachineInstr &I) const {
1843 Register SrcReg = I.getOperand(1).getReg();
1844 if (I.getOpcode() == TargetOpcode::G_MEMSET) {
1845 Register VarReg = getOrCreateMemSetGlobal(I);
1846 if (!VarReg.isValid())
1847 return false;
1848 Type *ValTy = Type::getInt8Ty(I.getMF()->getFunction().getContext());
1849 SPIRVTypeInst SourceTy = GR.getOrCreateSPIRVPointerType(
1850 ValTy, I, SPIRV::StorageClass::UniformConstant);
1851 SrcReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
1852 if (!selectOpWithSrcs(SrcReg, SourceTy, I, {VarReg}, SPIRV::OpBitcast))
1853 return false;
1854 }
1855 if (STI.isLogicalSPIRV()) {
1856 if (!selectCopyMemory(I, SrcReg))
1857 return false;
1858 } else {
1859 if (!selectCopyMemorySized(I, SrcReg))
1860 return false;
1861 }
1862 if (ResVReg.isValid() && ResVReg != I.getOperand(0).getReg())
1863 if (!BuildCOPY(ResVReg, I.getOperand(0).getReg(), I))
1864 return false;
1865 return true;
1866}
1867
1868bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg,
1869 SPIRVTypeInst ResType,
1870 MachineInstr &I,
1871 unsigned NewOpcode,
1872 unsigned NegateOpcode) const {
1873 assert(I.hasOneMemOperand());
1874 const MachineMemOperand *MemOp = *I.memoperands_begin();
1875 uint32_t Scope = static_cast<uint32_t>(getMemScope(
1876 GR.CurMF->getFunction().getContext(), MemOp->getSyncScopeID()));
1877 Register ScopeReg = buildI32Constant(Scope, I);
1878
1879 Register Ptr = I.getOperand(1).getReg();
1880 // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll
1881 // auto ScSem =
1882 // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr));
1883 AtomicOrdering AO = MemOp->getSuccessOrdering();
1884 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
1885 Register MemSemReg = buildI32Constant(MemSem /*| ScSem*/, I);
1886
1887 Register ValueReg = I.getOperand(2).getReg();
1888 if (NegateOpcode != 0) {
1889 // Translation with negative value operand is requested
1890 Register TmpReg = createVirtualRegister(ResType, &GR, MRI, MRI->getMF());
1891 if (!selectOpWithSrcs(TmpReg, ResType, I, {ValueReg}, NegateOpcode))
1892 return false;
1893 ValueReg = TmpReg;
1894 }
1895
1896 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode))
1897 .addDef(ResVReg)
1898 .addUse(GR.getSPIRVTypeID(ResType))
1899 .addUse(Ptr)
1900 .addUse(ScopeReg)
1901 .addUse(MemSemReg)
1902 .addUse(ValueReg)
1903 .constrainAllUses(TII, TRI, RBI);
1904 return true;
1905}
1906
1907bool SPIRVInstructionSelector::selectUnmergeValues(MachineInstr &I) const {
1908 unsigned ArgI = I.getNumOperands() - 1;
1909 Register SrcReg =
1910 I.getOperand(ArgI).isReg() ? I.getOperand(ArgI).getReg() : Register(0);
1911 SPIRVTypeInst SrcType =
1912 SrcReg.isValid() ? GR.getSPIRVTypeForVReg(SrcReg) : nullptr;
1913 if (!SrcType || SrcType->getOpcode() != SPIRV::OpTypeVector)
1915 "cannot select G_UNMERGE_VALUES with a non-vector argument");
1916
1917 SPIRVTypeInst ScalarType =
1918 GR.getSPIRVTypeForVReg(SrcType->getOperand(1).getReg());
1919 MachineBasicBlock &BB = *I.getParent();
1920 unsigned CurrentIndex = 0;
1921 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
1922 Register ResVReg = I.getOperand(i).getReg();
1923 SPIRVTypeInst ResType = GR.getSPIRVTypeForVReg(ResVReg);
1924 if (!ResType) {
1925 LLT ResLLT = MRI->getType(ResVReg);
1926 assert(ResLLT.isValid());
1927 if (ResLLT.isVector()) {
1928 ResType = GR.getOrCreateSPIRVVectorType(
1929 ScalarType, ResLLT.getNumElements(), I, TII);
1930 } else {
1931 ResType = ScalarType;
1932 }
1933 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
1934 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF);
1935 }
1936
1937 if (ResType->getOpcode() == SPIRV::OpTypeVector) {
1938 Register UndefReg = GR.getOrCreateUndef(I, SrcType, TII);
1939 auto MIB =
1940 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle))
1941 .addDef(ResVReg)
1942 .addUse(GR.getSPIRVTypeID(ResType))
1943 .addUse(SrcReg)
1944 .addUse(UndefReg);
1945 unsigned NumElements = GR.getScalarOrVectorComponentCount(ResType);
1946 for (unsigned j = 0; j < NumElements; ++j) {
1947 MIB.addImm(CurrentIndex + j);
1948 }
1949 CurrentIndex += NumElements;
1950 MIB.constrainAllUses(TII, TRI, RBI);
1951 } else {
1952 auto MIB =
1953 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
1954 .addDef(ResVReg)
1955 .addUse(GR.getSPIRVTypeID(ResType))
1956 .addUse(SrcReg)
1957 .addImm(CurrentIndex);
1958 CurrentIndex++;
1959 MIB.constrainAllUses(TII, TRI, RBI);
1960 }
1961 }
1962 return true;
1963}
1964
1965bool SPIRVInstructionSelector::selectFence(MachineInstr &I) const {
1966 AtomicOrdering AO = AtomicOrdering(I.getOperand(0).getImm());
1967 uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
1968 Register MemSemReg = buildI32Constant(MemSem, I);
1969 SyncScope::ID Ord = SyncScope::ID(I.getOperand(1).getImm());
1970 uint32_t Scope = static_cast<uint32_t>(
1971 getMemScope(GR.CurMF->getFunction().getContext(), Ord));
1972 Register ScopeReg = buildI32Constant(Scope, I);
1973 MachineBasicBlock &BB = *I.getParent();
1974 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMemoryBarrier))
1975 .addUse(ScopeReg)
1976 .addUse(MemSemReg)
1977 .constrainAllUses(TII, TRI, RBI);
1978 return true;
1979}
1980
1981bool SPIRVInstructionSelector::selectOverflowArith(Register ResVReg,
1982 SPIRVTypeInst ResType,
1983 MachineInstr &I,
1984 unsigned Opcode) const {
1985 Type *ResTy = nullptr;
1986 StringRef ResName;
1987 if (!GR.findValueAttrs(&I, ResTy, ResName))
1989 "Not enough info to select the arithmetic with overflow instruction");
1990 if (!ResTy || !ResTy->isStructTy())
1991 report_fatal_error("Expect struct type result for the arithmetic "
1992 "with overflow instruction");
1993 // "Result Type must be from OpTypeStruct. The struct must have two members,
1994 // and the two members must be the same type."
1995 Type *ResElemTy = cast<StructType>(ResTy)->getElementType(0);
1996 ResTy = StructType::get(ResElemTy, ResElemTy);
1997 // Build SPIR-V types and constant(s) if needed.
1998 MachineIRBuilder MIRBuilder(I);
1999 SPIRVTypeInst StructType = GR.getOrCreateSPIRVType(
2000 ResTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false);
2001 assert(I.getNumDefs() > 1 && "Not enought operands");
2002 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
2003 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
2004 if (N > 1)
2005 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, N, I, TII);
2006 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
2007 Register ZeroReg = buildZerosVal(ResType, I);
2008 // A new virtual register to store the result struct.
2009 Register StructVReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
2010 MRI->setRegClass(StructVReg, &SPIRV::IDRegClass);
2011 // Build the result name if needed.
2012 if (ResName.size() > 0)
2013 buildOpName(StructVReg, ResName, MIRBuilder);
2014 // Build the arithmetic with overflow instruction.
2015 MachineBasicBlock &BB = *I.getParent();
2016 auto MIB =
2017 BuildMI(BB, MIRBuilder.getInsertPt(), I.getDebugLoc(), TII.get(Opcode))
2018 .addDef(StructVReg)
2019 .addUse(GR.getSPIRVTypeID(StructType));
2020 for (unsigned i = I.getNumDefs(); i < I.getNumOperands(); ++i)
2021 MIB.addUse(I.getOperand(i).getReg());
2022 MIB.constrainAllUses(TII, TRI, RBI);
2023 // Build instructions to extract fields of the instruction's result.
2024 // A new virtual register to store the higher part of the result struct.
2025 Register HigherVReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
2026 MRI->setRegClass(HigherVReg, &SPIRV::iIDRegClass);
2027 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
2028 auto MIB =
2029 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
2030 .addDef(i == 1 ? HigherVReg : I.getOperand(i).getReg())
2031 .addUse(GR.getSPIRVTypeID(ResType))
2032 .addUse(StructVReg)
2033 .addImm(i);
2034 MIB.constrainAllUses(TII, TRI, RBI);
2035 }
2036 // Build boolean value from the higher part.
2037 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
2038 .addDef(I.getOperand(1).getReg())
2039 .addUse(BoolTypeReg)
2040 .addUse(HigherVReg)
2041 .addUse(ZeroReg)
2042 .constrainAllUses(TII, TRI, RBI);
2043 return true;
2044}
2045
2046bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg,
2047 SPIRVTypeInst ResType,
2048 MachineInstr &I) const {
2049 Register ScopeReg;
2050 Register MemSemEqReg;
2051 Register MemSemNeqReg;
2052 Register Ptr = I.getOperand(2).getReg();
2053 if (!isa<GIntrinsic>(I)) {
2054 assert(I.hasOneMemOperand());
2055 const MachineMemOperand *MemOp = *I.memoperands_begin();
2056 unsigned Scope = static_cast<uint32_t>(getMemScope(
2057 GR.CurMF->getFunction().getContext(), MemOp->getSyncScopeID()));
2058 ScopeReg = buildI32Constant(Scope, I);
2059
2060 unsigned ScSem = static_cast<uint32_t>(
2062 AtomicOrdering AO = MemOp->getSuccessOrdering();
2063 unsigned MemSemEq = static_cast<uint32_t>(getMemSemantics(AO)) | ScSem;
2064 Register MemSemEqReg = buildI32Constant(MemSemEq, I);
2065 AtomicOrdering FO = MemOp->getFailureOrdering();
2066 unsigned MemSemNeq = static_cast<uint32_t>(getMemSemantics(FO)) | ScSem;
2067 if (MemSemEq == MemSemNeq)
2068 MemSemNeqReg = MemSemEqReg;
2069 else {
2070 MemSemNeqReg = buildI32Constant(MemSemEq, I);
2071 }
2072 } else {
2073 ScopeReg = I.getOperand(5).getReg();
2074 MemSemEqReg = I.getOperand(6).getReg();
2075 MemSemNeqReg = I.getOperand(7).getReg();
2076 }
2077
2078 Register Cmp = I.getOperand(3).getReg();
2079 Register Val = I.getOperand(4).getReg();
2080 SPIRVTypeInst SpvValTy = GR.getSPIRVTypeForVReg(Val);
2081 Register ACmpRes = createVirtualRegister(SpvValTy, &GR, MRI, *I.getMF());
2082 const DebugLoc &DL = I.getDebugLoc();
2083 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpAtomicCompareExchange))
2084 .addDef(ACmpRes)
2085 .addUse(GR.getSPIRVTypeID(SpvValTy))
2086 .addUse(Ptr)
2087 .addUse(ScopeReg)
2088 .addUse(MemSemEqReg)
2089 .addUse(MemSemNeqReg)
2090 .addUse(Val)
2091 .addUse(Cmp)
2092 .constrainAllUses(TII, TRI, RBI);
2093 SPIRVTypeInst BoolTy = GR.getOrCreateSPIRVBoolType(I, TII);
2094 Register CmpSuccReg = createVirtualRegister(BoolTy, &GR, MRI, *I.getMF());
2095 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpIEqual))
2096 .addDef(CmpSuccReg)
2097 .addUse(GR.getSPIRVTypeID(BoolTy))
2098 .addUse(ACmpRes)
2099 .addUse(Cmp)
2100 .constrainAllUses(TII, TRI, RBI);
2101 Register TmpReg = createVirtualRegister(ResType, &GR, MRI, *I.getMF());
2102 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
2103 .addDef(TmpReg)
2104 .addUse(GR.getSPIRVTypeID(ResType))
2105 .addUse(ACmpRes)
2106 .addUse(GR.getOrCreateUndef(I, ResType, TII))
2107 .addImm(0)
2108 .constrainAllUses(TII, TRI, RBI);
2109 BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
2110 .addDef(ResVReg)
2111 .addUse(GR.getSPIRVTypeID(ResType))
2112 .addUse(CmpSuccReg)
2113 .addUse(TmpReg)
2114 .addImm(1)
2115 .constrainAllUses(TII, TRI, RBI);
2116 return true;
2117}
2118
2119static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) {
2120 switch (SC) {
2121 case SPIRV::StorageClass::DeviceOnlyINTEL:
2122 case SPIRV::StorageClass::HostOnlyINTEL:
2123 return true;
2124 default:
2125 return false;
2126 }
2127}
2128
2129// Returns true ResVReg is referred only from global vars and OpName's.
2131 bool IsGRef = false;
2132 bool IsAllowedRefs =
2133 llvm::all_of(MRI->use_instructions(ResVReg), [&IsGRef](auto const &It) {
2134 unsigned Opcode = It.getOpcode();
2135 if (Opcode == SPIRV::OpConstantComposite ||
2136 Opcode == SPIRV::OpVariable ||
2137 isSpvIntrinsic(It, Intrinsic::spv_init_global))
2138 return IsGRef = true;
2139 return Opcode == SPIRV::OpName;
2140 });
2141 return IsAllowedRefs && IsGRef;
2142}
2143
2144Register SPIRVInstructionSelector::getUcharPtrTypeReg(
2145 MachineInstr &I, SPIRV::StorageClass::StorageClass SC) const {
2147 Type::getInt8Ty(I.getMF()->getFunction().getContext()), I, SC));
2148}
2149
2150MachineInstrBuilder
2151SPIRVInstructionSelector::buildSpecConstantOp(MachineInstr &I, Register Dest,
2152 Register Src, Register DestType,
2153 uint32_t Opcode) const {
2154 return BuildMI(*I.getParent(), I, I.getDebugLoc(),
2155 TII.get(SPIRV::OpSpecConstantOp))
2156 .addDef(Dest)
2157 .addUse(DestType)
2158 .addImm(Opcode)
2159 .addUse(Src);
2160}
2161
2162MachineInstrBuilder
2163SPIRVInstructionSelector::buildConstGenericPtr(MachineInstr &I, Register SrcPtr,
2164 SPIRVTypeInst SrcPtrTy) const {
2165 SPIRVTypeInst GenericPtrTy =
2166 GR.changePointerStorageClass(SrcPtrTy, SPIRV::StorageClass::Generic, I);
2167 Register Tmp = MRI->createVirtualRegister(&SPIRV::pIDRegClass);
2169 SPIRV::StorageClass::Generic),
2170 GR.getPointerSize()));
2171 MachineFunction *MF = I.getParent()->getParent();
2172 GR.assignSPIRVTypeToVReg(GenericPtrTy, Tmp, *MF);
2173 MachineInstrBuilder MIB = buildSpecConstantOp(
2174 I, Tmp, SrcPtr, GR.getSPIRVTypeID(GenericPtrTy),
2175 static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric));
2176 GR.add(MIB.getInstr(), MIB);
2177 return MIB;
2178}
2179
2180// In SPIR-V address space casting can only happen to and from the Generic
2181// storage class. We can also only cast Workgroup, CrossWorkgroup, or Function
2182// pointers to and from Generic pointers. As such, we can convert e.g. from
2183// Workgroup to Function by going via a Generic pointer as an intermediary. All
2184// other combinations can only be done by a bitcast, and are probably not safe.
2185bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
2186 SPIRVTypeInst ResType,
2187 MachineInstr &I) const {
2188 MachineBasicBlock &BB = *I.getParent();
2189 const DebugLoc &DL = I.getDebugLoc();
2190
2191 Register SrcPtr = I.getOperand(1).getReg();
2192 SPIRVTypeInst SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
2193
2194 // don't generate a cast for a null that may be represented by OpTypeInt
2195 if (SrcPtrTy->getOpcode() != SPIRV::OpTypePointer ||
2196 ResType->getOpcode() != SPIRV::OpTypePointer)
2197 return BuildCOPY(ResVReg, SrcPtr, I);
2198
2199 SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtrTy);
2200 SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResType);
2201
2202 if (isASCastInGVar(MRI, ResVReg)) {
2203 // AddrSpaceCast uses within OpVariable and OpConstantComposite instructions
2204 // are expressed by OpSpecConstantOp with an Opcode.
2205 // TODO: maybe insert a check whether the Kernel capability was declared and
2206 // so PtrCastToGeneric/GenericCastToPtr are available.
2207 unsigned SpecOpcode =
2208 DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC)
2209 ? static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric)
2210 : (SrcSC == SPIRV::StorageClass::Generic &&
2212 ? static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr)
2213 : 0);
2214 // TODO: OpConstantComposite expects i8*, so we are forced to forget a
2215 // correct value of ResType and use general i8* instead. Maybe this should
2216 // be addressed in the emit-intrinsic step to infer a correct
2217 // OpConstantComposite type.
2218 if (SpecOpcode) {
2219 buildSpecConstantOp(I, ResVReg, SrcPtr, getUcharPtrTypeReg(I, DstSC),
2220 SpecOpcode)
2221 .constrainAllUses(TII, TRI, RBI);
2222 } else if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
2223 MachineInstrBuilder MIB = buildConstGenericPtr(I, SrcPtr, SrcPtrTy);
2224 MIB.constrainAllUses(TII, TRI, RBI);
2225 buildSpecConstantOp(
2226 I, ResVReg, MIB->getOperand(0).getReg(), getUcharPtrTypeReg(I, DstSC),
2227 static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr))
2228 .constrainAllUses(TII, TRI, RBI);
2229 }
2230 return true;
2231 }
2232
2233 // don't generate a cast between identical storage classes
2234 if (SrcSC == DstSC)
2235 return BuildCOPY(ResVReg, SrcPtr, I);
2236
2237 if ((SrcSC == SPIRV::StorageClass::Function &&
2238 DstSC == SPIRV::StorageClass::Private) ||
2239 (DstSC == SPIRV::StorageClass::Function &&
2240 SrcSC == SPIRV::StorageClass::Private))
2241 return BuildCOPY(ResVReg, SrcPtr, I);
2242
2243 // Casting from an eligible pointer to Generic.
2244 if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC))
2245 return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
2246 // Casting from Generic to an eligible pointer.
2247 if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC))
2248 return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
2249 // Casting between 2 eligible pointers using Generic as an intermediary.
2250 if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
2251 SPIRVTypeInst GenericPtrTy =
2252 GR.changePointerStorageClass(SrcPtrTy, SPIRV::StorageClass::Generic, I);
2253 Register Tmp = createVirtualRegister(GenericPtrTy, &GR, MRI, MRI->getMF());
2254 BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric))
2255 .addDef(Tmp)
2256 .addUse(GR.getSPIRVTypeID(GenericPtrTy))
2257 .addUse(SrcPtr)
2258 .constrainAllUses(TII, TRI, RBI);
2259 BuildMI(BB, I, DL, TII.get(SPIRV::OpGenericCastToPtr))
2260 .addDef(ResVReg)
2261 .addUse(GR.getSPIRVTypeID(ResType))
2262 .addUse(Tmp)
2263 .constrainAllUses(TII, TRI, RBI);
2264 return true;
2265 }
2266
2267 // Check if instructions from the SPV_INTEL_usm_storage_classes extension may
2268 // be applied
2269 if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::CrossWorkgroup)
2270 return selectUnOp(ResVReg, ResType, I,
2271 SPIRV::OpPtrCastToCrossWorkgroupINTEL);
2272 if (SrcSC == SPIRV::StorageClass::CrossWorkgroup && isUSMStorageClass(DstSC))
2273 return selectUnOp(ResVReg, ResType, I,
2274 SPIRV::OpCrossWorkgroupCastToPtrINTEL);
2275 if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::Generic)
2276 return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
2277 if (SrcSC == SPIRV::StorageClass::Generic && isUSMStorageClass(DstSC))
2278 return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
2279
2280 // Bitcast for pointers requires that the address spaces must match
2281 return false;
2282}
2283
2284static unsigned getFCmpOpcode(unsigned PredNum) {
2285 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
2286 switch (Pred) {
2287 case CmpInst::FCMP_OEQ:
2288 return SPIRV::OpFOrdEqual;
2289 case CmpInst::FCMP_OGE:
2290 return SPIRV::OpFOrdGreaterThanEqual;
2291 case CmpInst::FCMP_OGT:
2292 return SPIRV::OpFOrdGreaterThan;
2293 case CmpInst::FCMP_OLE:
2294 return SPIRV::OpFOrdLessThanEqual;
2295 case CmpInst::FCMP_OLT:
2296 return SPIRV::OpFOrdLessThan;
2297 case CmpInst::FCMP_ONE:
2298 return SPIRV::OpFOrdNotEqual;
2299 case CmpInst::FCMP_ORD:
2300 return SPIRV::OpOrdered;
2301 case CmpInst::FCMP_UEQ:
2302 return SPIRV::OpFUnordEqual;
2303 case CmpInst::FCMP_UGE:
2304 return SPIRV::OpFUnordGreaterThanEqual;
2305 case CmpInst::FCMP_UGT:
2306 return SPIRV::OpFUnordGreaterThan;
2307 case CmpInst::FCMP_ULE:
2308 return SPIRV::OpFUnordLessThanEqual;
2309 case CmpInst::FCMP_ULT:
2310 return SPIRV::OpFUnordLessThan;
2311 case CmpInst::FCMP_UNE:
2312 return SPIRV::OpFUnordNotEqual;
2313 case CmpInst::FCMP_UNO:
2314 return SPIRV::OpUnordered;
2315 default:
2316 llvm_unreachable("Unknown predicate type for FCmp");
2317 }
2318}
2319
2320static unsigned getICmpOpcode(unsigned PredNum) {
2321 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
2322 switch (Pred) {
2323 case CmpInst::ICMP_EQ:
2324 return SPIRV::OpIEqual;
2325 case CmpInst::ICMP_NE:
2326 return SPIRV::OpINotEqual;
2327 case CmpInst::ICMP_SGE:
2328 return SPIRV::OpSGreaterThanEqual;
2329 case CmpInst::ICMP_SGT:
2330 return SPIRV::OpSGreaterThan;
2331 case CmpInst::ICMP_SLE:
2332 return SPIRV::OpSLessThanEqual;
2333 case CmpInst::ICMP_SLT:
2334 return SPIRV::OpSLessThan;
2335 case CmpInst::ICMP_UGE:
2336 return SPIRV::OpUGreaterThanEqual;
2337 case CmpInst::ICMP_UGT:
2338 return SPIRV::OpUGreaterThan;
2339 case CmpInst::ICMP_ULE:
2340 return SPIRV::OpULessThanEqual;
2341 case CmpInst::ICMP_ULT:
2342 return SPIRV::OpULessThan;
2343 default:
2344 llvm_unreachable("Unknown predicate type for ICmp");
2345 }
2346}
2347
2348static unsigned getPtrCmpOpcode(unsigned Pred) {
2349 switch (static_cast<CmpInst::Predicate>(Pred)) {
2350 case CmpInst::ICMP_EQ:
2351 return SPIRV::OpPtrEqual;
2352 case CmpInst::ICMP_NE:
2353 return SPIRV::OpPtrNotEqual;
2354 default:
2355 llvm_unreachable("Unknown predicate type for pointer comparison");
2356 }
2357}
2358
2359// Return the logical operation, or abort if none exists.
2360static unsigned getBoolCmpOpcode(unsigned PredNum) {
2361 auto Pred = static_cast<CmpInst::Predicate>(PredNum);
2362 switch (Pred) {
2363 case CmpInst::ICMP_EQ:
2364 return SPIRV::OpLogicalEqual;
2365 case CmpInst::ICMP_NE:
2366 return SPIRV::OpLogicalNotEqual;
2367 default:
2368 llvm_unreachable("Unknown predicate type for Bool comparison");
2369 }
2370}
2371
2372static APFloat getZeroFP(const Type *LLVMFloatTy) {
2373 if (!LLVMFloatTy)
2375 switch (LLVMFloatTy->getScalarType()->getTypeID()) {
2376 case Type::HalfTyID:
2378 default:
2379 case Type::FloatTyID:
2381 case Type::DoubleTyID:
2383 }
2384}
2385
2386static APFloat getOneFP(const Type *LLVMFloatTy) {
2387 if (!LLVMFloatTy)
2389 switch (LLVMFloatTy->getScalarType()->getTypeID()) {
2390 case Type::HalfTyID:
2392 default:
2393 case Type::FloatTyID:
2395 case Type::DoubleTyID:
2397 }
2398}
2399
2400bool SPIRVInstructionSelector::selectAnyOrAll(Register ResVReg,
2401 SPIRVTypeInst ResType,
2402 MachineInstr &I,
2403 unsigned OpAnyOrAll) const {
2404 assert(I.getNumOperands() == 3);
2405 assert(I.getOperand(2).isReg());
2406 MachineBasicBlock &BB = *I.getParent();
2407 Register InputRegister = I.getOperand(2).getReg();
2408 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
2409
2410 if (!InputType)
2411 report_fatal_error("Input Type could not be determined.");
2412
2413 bool IsBoolTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeBool);
2414 bool IsVectorTy = InputType->getOpcode() == SPIRV::OpTypeVector;
2415 if (IsBoolTy && !IsVectorTy) {
2416 assert(ResVReg == I.getOperand(0).getReg());
2417 return BuildCOPY(ResVReg, InputRegister, I);
2418 }
2419
2420 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
2421 unsigned SpirvNotEqualId =
2422 IsFloatTy ? SPIRV::OpFOrdNotEqual : SPIRV::OpINotEqual;
2423 SPIRVTypeInst SpvBoolScalarTy = GR.getOrCreateSPIRVBoolType(I, TII);
2424 SPIRVTypeInst SpvBoolTy = SpvBoolScalarTy;
2425 Register NotEqualReg = ResVReg;
2426
2427 if (IsVectorTy) {
2428 NotEqualReg =
2429 IsBoolTy ? InputRegister
2430 : createVirtualRegister(SpvBoolTy, &GR, MRI, MRI->getMF());
2431 const unsigned NumElts = InputType->getOperand(2).getImm();
2432 SpvBoolTy = GR.getOrCreateSPIRVVectorType(SpvBoolTy, NumElts, I, TII);
2433 }
2434
2435 if (!IsBoolTy) {
2436 Register ConstZeroReg =
2437 IsFloatTy ? buildZerosValF(InputType, I) : buildZerosVal(InputType, I);
2438
2439 BuildMI(BB, I, I.getDebugLoc(), TII.get(SpirvNotEqualId))
2440 .addDef(NotEqualReg)
2441 .addUse(GR.getSPIRVTypeID(SpvBoolTy))
2442 .addUse(InputRegister)
2443 .addUse(ConstZeroReg)
2444 .constrainAllUses(TII, TRI, RBI);
2445 }
2446
2447 if (IsVectorTy)
2448 BuildMI(BB, I, I.getDebugLoc(), TII.get(OpAnyOrAll))
2449 .addDef(ResVReg)
2450 .addUse(GR.getSPIRVTypeID(SpvBoolScalarTy))
2451 .addUse(NotEqualReg)
2452 .constrainAllUses(TII, TRI, RBI);
2453 return true;
2454}
2455
2456bool SPIRVInstructionSelector::selectAll(Register ResVReg,
2457 SPIRVTypeInst ResType,
2458 MachineInstr &I) const {
2459 return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAll);
2460}
2461
2462bool SPIRVInstructionSelector::selectAny(Register ResVReg,
2463 SPIRVTypeInst ResType,
2464 MachineInstr &I) const {
2465 return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAny);
2466}
2467
2468// Select the OpDot instruction for the given float dot
2469bool SPIRVInstructionSelector::selectFloatDot(Register ResVReg,
2470 SPIRVTypeInst ResType,
2471 MachineInstr &I) const {
2472 assert(I.getNumOperands() == 4);
2473 assert(I.getOperand(2).isReg());
2474 assert(I.getOperand(3).isReg());
2475
2476 [[maybe_unused]] SPIRVTypeInst VecType =
2477 GR.getSPIRVTypeForVReg(I.getOperand(2).getReg());
2478
2479 assert(VecType->getOpcode() == SPIRV::OpTypeVector &&
2480 GR.getScalarOrVectorComponentCount(VecType) > 1 &&
2481 "dot product requires a vector of at least 2 components");
2482
2483 [[maybe_unused]] SPIRVTypeInst EltType =
2484 GR.getSPIRVTypeForVReg(VecType->getOperand(1).getReg());
2485
2486 assert(EltType->getOpcode() == SPIRV::OpTypeFloat);
2487
2488 MachineBasicBlock &BB = *I.getParent();
2489 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpDot))
2490 .addDef(ResVReg)
2491 .addUse(GR.getSPIRVTypeID(ResType))
2492 .addUse(I.getOperand(2).getReg())
2493 .addUse(I.getOperand(3).getReg())
2494 .constrainAllUses(TII, TRI, RBI);
2495 return true;
2496}
2497
2498bool SPIRVInstructionSelector::selectIntegerDot(Register ResVReg,
2499 SPIRVTypeInst ResType,
2500 MachineInstr &I,
2501 bool Signed) const {
2502 assert(I.getNumOperands() == 4);
2503 assert(I.getOperand(2).isReg());
2504 assert(I.getOperand(3).isReg());
2505 MachineBasicBlock &BB = *I.getParent();
2506
2507 auto DotOp = Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
2508 BuildMI(BB, I, I.getDebugLoc(), TII.get(DotOp))
2509 .addDef(ResVReg)
2510 .addUse(GR.getSPIRVTypeID(ResType))
2511 .addUse(I.getOperand(2).getReg())
2512 .addUse(I.getOperand(3).getReg())
2513 .constrainAllUses(TII, TRI, RBI);
2514 return true;
2515}
2516
2517// Since pre-1.6 SPIRV has no integer dot implementation,
2518// expand by piecewise multiplying and adding the results
2519bool SPIRVInstructionSelector::selectIntegerDotExpansion(
2520 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
2521 assert(I.getNumOperands() == 4);
2522 assert(I.getOperand(2).isReg());
2523 assert(I.getOperand(3).isReg());
2524 MachineBasicBlock &BB = *I.getParent();
2525
2526 // Multiply the vectors, then sum the results
2527 Register Vec0 = I.getOperand(2).getReg();
2528 Register Vec1 = I.getOperand(3).getReg();
2529 Register TmpVec = MRI->createVirtualRegister(GR.getRegClass(ResType));
2530 SPIRVTypeInst VecType = GR.getSPIRVTypeForVReg(Vec0);
2531
2532 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIMulV))
2533 .addDef(TmpVec)
2534 .addUse(GR.getSPIRVTypeID(VecType))
2535 .addUse(Vec0)
2536 .addUse(Vec1)
2537 .constrainAllUses(TII, TRI, RBI);
2538
2539 assert(VecType->getOpcode() == SPIRV::OpTypeVector &&
2540 GR.getScalarOrVectorComponentCount(VecType) > 1 &&
2541 "dot product requires a vector of at least 2 components");
2542
2543 Register Res = MRI->createVirtualRegister(GR.getRegClass(ResType));
2544 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
2545 .addDef(Res)
2546 .addUse(GR.getSPIRVTypeID(ResType))
2547 .addUse(TmpVec)
2548 .addImm(0)
2549 .constrainAllUses(TII, TRI, RBI);
2550
2551 for (unsigned i = 1; i < GR.getScalarOrVectorComponentCount(VecType); i++) {
2552 Register Elt = MRI->createVirtualRegister(GR.getRegClass(ResType));
2553
2554 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
2555 .addDef(Elt)
2556 .addUse(GR.getSPIRVTypeID(ResType))
2557 .addUse(TmpVec)
2558 .addImm(i)
2559 .constrainAllUses(TII, TRI, RBI);
2560
2561 Register Sum = i < GR.getScalarOrVectorComponentCount(VecType) - 1
2562 ? MRI->createVirtualRegister(GR.getRegClass(ResType))
2563 : ResVReg;
2564
2565 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
2566 .addDef(Sum)
2567 .addUse(GR.getSPIRVTypeID(ResType))
2568 .addUse(Res)
2569 .addUse(Elt)
2570 .constrainAllUses(TII, TRI, RBI);
2571 Res = Sum;
2572 }
2573
2574 return true;
2575}
2576
2577bool SPIRVInstructionSelector::selectOpIsInf(Register ResVReg,
2578 SPIRVTypeInst ResType,
2579 MachineInstr &I) const {
2580 MachineBasicBlock &BB = *I.getParent();
2581 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsInf))
2582 .addDef(ResVReg)
2583 .addUse(GR.getSPIRVTypeID(ResType))
2584 .addUse(I.getOperand(2).getReg())
2585 .constrainAllUses(TII, TRI, RBI);
2586 return true;
2587}
2588
2589bool SPIRVInstructionSelector::selectOpIsNan(Register ResVReg,
2590 SPIRVTypeInst ResType,
2591 MachineInstr &I) const {
2592 MachineBasicBlock &BB = *I.getParent();
2593 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsNan))
2594 .addDef(ResVReg)
2595 .addUse(GR.getSPIRVTypeID(ResType))
2596 .addUse(I.getOperand(2).getReg())
2597 .constrainAllUses(TII, TRI, RBI);
2598 return true;
2599}
2600
2601template <bool Signed>
2602bool SPIRVInstructionSelector::selectDot4AddPacked(Register ResVReg,
2603 SPIRVTypeInst ResType,
2604 MachineInstr &I) const {
2605 assert(I.getNumOperands() == 5);
2606 assert(I.getOperand(2).isReg());
2607 assert(I.getOperand(3).isReg());
2608 assert(I.getOperand(4).isReg());
2609 MachineBasicBlock &BB = *I.getParent();
2610
2611 Register Acc = I.getOperand(2).getReg();
2612 Register X = I.getOperand(3).getReg();
2613 Register Y = I.getOperand(4).getReg();
2614
2615 auto DotOp = Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
2616 Register Dot = MRI->createVirtualRegister(GR.getRegClass(ResType));
2617 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(DotOp))
2618 .addDef(Dot)
2619 .addUse(GR.getSPIRVTypeID(ResType))
2620 .addUse(X)
2621 .addUse(Y);
2622 MIB.addImm(SPIRV::BuiltIn::PackedVectorFormat4x8Bit);
2623 MIB.constrainAllUses(TII, TRI, RBI);
2624
2625 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
2626 .addDef(ResVReg)
2627 .addUse(GR.getSPIRVTypeID(ResType))
2628 .addUse(Dot)
2629 .addUse(Acc)
2630 .constrainAllUses(TII, TRI, RBI);
2631 return true;
2632}
2633
2634// Since pre-1.6 SPIRV has no DotProductInput4x8BitPacked implementation,
2635// extract the elements of the packed inputs, multiply them and add the result
2636// to the accumulator.
2637template <bool Signed>
2638bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
2639 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
2640 assert(I.getNumOperands() == 5);
2641 assert(I.getOperand(2).isReg());
2642 assert(I.getOperand(3).isReg());
2643 assert(I.getOperand(4).isReg());
2644 MachineBasicBlock &BB = *I.getParent();
2645
2646 Register Acc = I.getOperand(2).getReg();
2647 Register X = I.getOperand(3).getReg();
2648 Register Y = I.getOperand(4).getReg();
2649
2650 SPIRVTypeInst EltType = GR.getOrCreateSPIRVIntegerType(8, I, TII);
2651 auto ExtractOp =
2652 Signed ? SPIRV::OpBitFieldSExtract : SPIRV::OpBitFieldUExtract;
2653
2654 bool ZeroAsNull = !STI.isShader();
2655 // Extract the i8 element, multiply and add it to the accumulator
2656 for (unsigned i = 0; i < 4; i++) {
2657 // A[i]
2658 Register AElt = MRI->createVirtualRegister(&SPIRV::IDRegClass);
2659 BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
2660 .addDef(AElt)
2661 .addUse(GR.getSPIRVTypeID(ResType))
2662 .addUse(X)
2663 .addUse(GR.getOrCreateConstInt(i * 8, I, EltType, TII, ZeroAsNull))
2664 .addUse(GR.getOrCreateConstInt(8, I, EltType, TII, ZeroAsNull))
2665 .constrainAllUses(TII, TRI, RBI);
2666
2667 // B[i]
2668 Register BElt = MRI->createVirtualRegister(&SPIRV::IDRegClass);
2669 BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
2670 .addDef(BElt)
2671 .addUse(GR.getSPIRVTypeID(ResType))
2672 .addUse(Y)
2673 .addUse(GR.getOrCreateConstInt(i * 8, I, EltType, TII, ZeroAsNull))
2674 .addUse(GR.getOrCreateConstInt(8, I, EltType, TII, ZeroAsNull))
2675 .constrainAllUses(TII, TRI, RBI);
2676
2677 // A[i] * B[i]
2678 Register Mul = MRI->createVirtualRegister(&SPIRV::IDRegClass);
2679 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIMulS))
2680 .addDef(Mul)
2681 .addUse(GR.getSPIRVTypeID(ResType))
2682 .addUse(AElt)
2683 .addUse(BElt)
2684 .constrainAllUses(TII, TRI, RBI);
2685
2686 // Discard 24 highest-bits so that stored i32 register is i8 equivalent
2687 Register MaskMul = MRI->createVirtualRegister(&SPIRV::IDRegClass);
2688 BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
2689 .addDef(MaskMul)
2690 .addUse(GR.getSPIRVTypeID(ResType))
2691 .addUse(Mul)
2692 .addUse(GR.getOrCreateConstInt(0, I, EltType, TII, ZeroAsNull))
2693 .addUse(GR.getOrCreateConstInt(8, I, EltType, TII, ZeroAsNull))
2694 .constrainAllUses(TII, TRI, RBI);
2695
2696 // Acc = Acc + A[i] * B[i]
2697 Register Sum =
2698 i < 3 ? MRI->createVirtualRegister(&SPIRV::IDRegClass) : ResVReg;
2699 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
2700 .addDef(Sum)
2701 .addUse(GR.getSPIRVTypeID(ResType))
2702 .addUse(Acc)
2703 .addUse(MaskMul)
2704 .constrainAllUses(TII, TRI, RBI);
2705
2706 Acc = Sum;
2707 }
2708
2709 return true;
2710}
2711
2712/// Transform saturate(x) to clamp(x, 0.0f, 1.0f) as SPIRV
2713/// does not have a saturate builtin.
2714bool SPIRVInstructionSelector::selectSaturate(Register ResVReg,
2715 SPIRVTypeInst ResType,
2716 MachineInstr &I) const {
2717 assert(I.getNumOperands() == 3);
2718 assert(I.getOperand(2).isReg());
2719 MachineBasicBlock &BB = *I.getParent();
2720 Register VZero = buildZerosValF(ResType, I);
2721 Register VOne = buildOnesValF(ResType, I);
2722
2723 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
2724 .addDef(ResVReg)
2725 .addUse(GR.getSPIRVTypeID(ResType))
2726 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
2727 .addImm(GL::FClamp)
2728 .addUse(I.getOperand(2).getReg())
2729 .addUse(VZero)
2730 .addUse(VOne)
2731 .constrainAllUses(TII, TRI, RBI);
2732 return true;
2733}
2734
2735bool SPIRVInstructionSelector::selectSign(Register ResVReg,
2736 SPIRVTypeInst ResType,
2737 MachineInstr &I) const {
2738 assert(I.getNumOperands() == 3);
2739 assert(I.getOperand(2).isReg());
2740 MachineBasicBlock &BB = *I.getParent();
2741 Register InputRegister = I.getOperand(2).getReg();
2742 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
2743 auto &DL = I.getDebugLoc();
2744
2745 if (!InputType)
2746 report_fatal_error("Input Type could not be determined.");
2747
2748 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
2749
2750 unsigned SignBitWidth = GR.getScalarOrVectorBitWidth(InputType);
2751 unsigned ResBitWidth = GR.getScalarOrVectorBitWidth(ResType);
2752
2753 bool NeedsConversion = IsFloatTy || SignBitWidth != ResBitWidth;
2754
2755 auto SignOpcode = IsFloatTy ? GL::FSign : GL::SSign;
2756 Register SignReg = NeedsConversion
2757 ? MRI->createVirtualRegister(&SPIRV::IDRegClass)
2758 : ResVReg;
2759
2760 BuildMI(BB, I, DL, TII.get(SPIRV::OpExtInst))
2761 .addDef(SignReg)
2762 .addUse(GR.getSPIRVTypeID(InputType))
2763 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
2764 .addImm(SignOpcode)
2765 .addUse(InputRegister)
2766 .constrainAllUses(TII, TRI, RBI);
2767
2768 if (NeedsConversion) {
2769 auto ConvertOpcode = IsFloatTy ? SPIRV::OpConvertFToS : SPIRV::OpSConvert;
2770 BuildMI(*I.getParent(), I, DL, TII.get(ConvertOpcode))
2771 .addDef(ResVReg)
2772 .addUse(GR.getSPIRVTypeID(ResType))
2773 .addUse(SignReg)
2774 .constrainAllUses(TII, TRI, RBI);
2775 }
2776
2777 return true;
2778}
2779
2780bool SPIRVInstructionSelector::selectWaveOpInst(Register ResVReg,
2781 SPIRVTypeInst ResType,
2782 MachineInstr &I,
2783 unsigned Opcode) const {
2784 MachineBasicBlock &BB = *I.getParent();
2785 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
2786
2787 auto BMI = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
2788 .addDef(ResVReg)
2789 .addUse(GR.getSPIRVTypeID(ResType))
2790 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I,
2791 IntTy, TII, !STI.isShader()));
2792
2793 for (unsigned J = 2; J < I.getNumOperands(); J++) {
2794 BMI.addUse(I.getOperand(J).getReg());
2795 }
2796
2797 BMI.constrainAllUses(TII, TRI, RBI);
2798 return true;
2799}
2800
2801bool SPIRVInstructionSelector::selectWaveActiveCountBits(
2802 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
2803
2804 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
2805 SPIRVTypeInst BallotType = GR.getOrCreateSPIRVVectorType(IntTy, 4, I, TII);
2806 Register BallotReg = MRI->createVirtualRegister(GR.getRegClass(BallotType));
2807 if (!selectWaveOpInst(BallotReg, BallotType, I,
2808 SPIRV::OpGroupNonUniformBallot))
2809 return false;
2810
2811 MachineBasicBlock &BB = *I.getParent();
2812 BuildMI(BB, I, I.getDebugLoc(),
2813 TII.get(SPIRV::OpGroupNonUniformBallotBitCount))
2814 .addDef(ResVReg)
2815 .addUse(GR.getSPIRVTypeID(ResType))
2816 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
2817 !STI.isShader()))
2818 .addImm(SPIRV::GroupOperation::Reduce)
2819 .addUse(BallotReg)
2820 .constrainAllUses(TII, TRI, RBI);
2821
2822 return true;
2823}
2824
2826
2827 if (Type->getOpcode() != SPIRV::OpTypeVector)
2828 return 1;
2829
2830 // Operand(2) is the vector size
2831 return Type->getOperand(2).getImm();
2832}
2833
2834bool SPIRVInstructionSelector::selectWaveActiveAllEqual(Register ResVReg,
2835 SPIRVTypeInst ResType,
2836 MachineInstr &I) const {
2837 MachineBasicBlock &BB = *I.getParent();
2838 const DebugLoc &DL = I.getDebugLoc();
2839
2840 // Input to the intrinsic
2841 Register InputReg = I.getOperand(2).getReg();
2842 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputReg);
2843
2844 // Determine if input is vector
2845 unsigned NumElems = getVectorSizeOrOne(InputType);
2846 bool IsVector = NumElems > 1;
2847
2848 // Determine element types
2849 SPIRVTypeInst ElemInputType = InputType;
2850 SPIRVTypeInst ElemBoolType = ResType;
2851 if (IsVector) {
2852 ElemInputType = GR.getSPIRVTypeForVReg(InputType->getOperand(1).getReg());
2853 ElemBoolType = GR.getSPIRVTypeForVReg(ResType->getOperand(1).getReg());
2854 }
2855
2856 // Subgroup scope constant
2857 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
2858 Register ScopeConst = GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy,
2859 TII, !STI.isShader());
2860
2861 // Scalar case
2862 if (!IsVector) {
2863 return selectWaveOpInst(ResVReg, ElemBoolType, I,
2864 SPIRV::OpGroupNonUniformAllEqual);
2865 }
2866
2867 // Vector case
2868 SmallVector<Register, 4> ElementResults;
2869 ElementResults.reserve(NumElems);
2870
2871 for (unsigned Idx = 0; Idx < NumElems; ++Idx) {
2872 // Extract element
2873 Register ElemInput = InputReg;
2874 Register Extracted =
2875 MRI->createVirtualRegister(GR.getRegClass(ElemInputType));
2876
2877 BuildMI(BB, I, DL, TII.get(SPIRV::OpCompositeExtract))
2878 .addDef(Extracted)
2879 .addUse(GR.getSPIRVTypeID(ElemInputType))
2880 .addUse(InputReg)
2881 .addImm(Idx)
2882 .constrainAllUses(TII, TRI, RBI);
2883
2884 ElemInput = Extracted;
2885
2886 // Emit per-element AllEqual
2887 Register ElemResult =
2888 MRI->createVirtualRegister(GR.getRegClass(ElemBoolType));
2889
2890 BuildMI(BB, I, DL, TII.get(SPIRV::OpGroupNonUniformAllEqual))
2891 .addDef(ElemResult)
2892 .addUse(GR.getSPIRVTypeID(ElemBoolType))
2893 .addUse(ScopeConst)
2894 .addUse(ElemInput)
2895 .constrainAllUses(TII, TRI, RBI);
2896
2897 ElementResults.push_back(ElemResult);
2898 }
2899
2900 // Reconstruct vector<bool>
2901 auto MIB = BuildMI(BB, I, DL, TII.get(SPIRV::OpCompositeConstruct))
2902 .addDef(ResVReg)
2903 .addUse(GR.getSPIRVTypeID(ResType));
2904 for (Register R : ElementResults)
2905 MIB.addUse(R);
2906
2907 MIB.constrainAllUses(TII, TRI, RBI);
2908
2909 return true;
2910}
2911
2912bool SPIRVInstructionSelector::selectWavePrefixBitCount(Register ResVReg,
2913 SPIRVTypeInst ResType,
2914 MachineInstr &I) const {
2915
2916 assert(I.getNumOperands() == 3);
2917
2918 auto Op = I.getOperand(2);
2919 assert(Op.isReg());
2920
2921 MachineBasicBlock &BB = *I.getParent();
2922 DebugLoc DL = I.getDebugLoc();
2923
2924 Register InputRegister = Op.getReg();
2925 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
2926
2927 if (!InputType)
2928 report_fatal_error("Input Type could not be determined.");
2929
2930 if (InputType->getOpcode() != SPIRV::OpTypeBool)
2931 report_fatal_error("WavePrefixBitCount requires boolean input");
2932
2933 // Types
2934 SPIRVTypeInst Int32Ty = GR.getOrCreateSPIRVIntegerType(32, I, TII);
2935
2936 // Ballot result type: vector<uint32>
2937 // Match DXC: %v4uint for Subgroup size
2938 SPIRVTypeInst BallotTy = GR.getOrCreateSPIRVVectorType(Int32Ty, 4, I, TII);
2939
2940 // Create a vreg for the ballot result
2941 Register BallotVReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
2942
2943 // 1. OpGroupNonUniformBallot
2944 BuildMI(BB, I, DL, TII.get(SPIRV::OpGroupNonUniformBallot))
2945 .addDef(BallotVReg)
2946 .addUse(GR.getSPIRVTypeID(BallotTy))
2947 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, Int32Ty, TII))
2948 .addUse(InputRegister)
2949 .constrainAllUses(TII, TRI, RBI);
2950
2951 // 2. OpGroupNonUniformBallotBitCount
2952 BuildMI(BB, I, DL, TII.get(SPIRV::OpGroupNonUniformBallotBitCount))
2953 .addDef(ResVReg)
2954 .addUse(GR.getSPIRVTypeID(ResType))
2955 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, Int32Ty, TII))
2956 .addImm(SPIRV::GroupOperation::ExclusiveScan)
2957 .addUse(BallotVReg)
2958 .constrainAllUses(TII, TRI, RBI);
2959
2960 return true;
2961}
2962
2963bool SPIRVInstructionSelector::selectWaveReduceMax(Register ResVReg,
2964 SPIRVTypeInst ResType,
2965 MachineInstr &I,
2966 bool IsUnsigned) const {
2967 return selectWaveReduce(
2968 ResVReg, ResType, I, IsUnsigned,
2969 [&](Register InputRegister, bool IsUnsigned) {
2970 const bool IsFloatTy =
2971 GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
2972 const auto IntOp = IsUnsigned ? SPIRV::OpGroupNonUniformUMax
2973 : SPIRV::OpGroupNonUniformSMax;
2974 return IsFloatTy ? SPIRV::OpGroupNonUniformFMax : IntOp;
2975 });
2976}
2977
2978bool SPIRVInstructionSelector::selectWaveReduceMin(Register ResVReg,
2979 SPIRVTypeInst ResType,
2980 MachineInstr &I,
2981 bool IsUnsigned) const {
2982 return selectWaveReduce(
2983 ResVReg, ResType, I, IsUnsigned,
2984 [&](Register InputRegister, bool IsUnsigned) {
2985 const bool IsFloatTy =
2986 GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
2987 const auto IntOp = IsUnsigned ? SPIRV::OpGroupNonUniformUMin
2988 : SPIRV::OpGroupNonUniformSMin;
2989 return IsFloatTy ? SPIRV::OpGroupNonUniformFMin : IntOp;
2990 });
2991}
2992
2993bool SPIRVInstructionSelector::selectWaveReduceSum(Register ResVReg,
2994 SPIRVTypeInst ResType,
2995 MachineInstr &I) const {
2996 return selectWaveReduce(ResVReg, ResType, I, /*IsUnsigned*/ false,
2997 [&](Register InputRegister, bool IsUnsigned) {
2998 bool IsFloatTy = GR.isScalarOrVectorOfType(
2999 InputRegister, SPIRV::OpTypeFloat);
3000 return IsFloatTy ? SPIRV::OpGroupNonUniformFAdd
3001 : SPIRV::OpGroupNonUniformIAdd;
3002 });
3003}
3004
3005template <typename PickOpcodeFn>
3006bool SPIRVInstructionSelector::selectWaveReduce(
3007 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, bool IsUnsigned,
3008 PickOpcodeFn &&PickOpcode) const {
3009 assert(I.getNumOperands() == 3);
3010 assert(I.getOperand(2).isReg());
3011 MachineBasicBlock &BB = *I.getParent();
3012 Register InputRegister = I.getOperand(2).getReg();
3013 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
3014
3015 if (!InputType)
3016 report_fatal_error("Input Type could not be determined.");
3017
3018 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3019 const unsigned Opcode = PickOpcode(InputRegister, IsUnsigned);
3020 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3021 .addDef(ResVReg)
3022 .addUse(GR.getSPIRVTypeID(ResType))
3023 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
3024 !STI.isShader()))
3025 .addImm(SPIRV::GroupOperation::Reduce)
3026 .addUse(I.getOperand(2).getReg())
3027 .constrainAllUses(TII, TRI, RBI);
3028 return true;
3029}
3030
3031bool SPIRVInstructionSelector::selectWaveExclusiveScanSum(
3032 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3033 return selectWaveExclusiveScan(ResVReg, ResType, I, /*IsUnsigned*/ false,
3034 [&](Register InputRegister, bool IsUnsigned) {
3035 bool IsFloatTy = GR.isScalarOrVectorOfType(
3036 InputRegister, SPIRV::OpTypeFloat);
3037 return IsFloatTy
3038 ? SPIRV::OpGroupNonUniformFAdd
3039 : SPIRV::OpGroupNonUniformIAdd;
3040 });
3041}
3042
3043bool SPIRVInstructionSelector::selectWaveExclusiveScanProduct(
3044 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
3045 return selectWaveExclusiveScan(ResVReg, ResType, I, /*IsUnsigned*/ false,
3046 [&](Register InputRegister, bool IsUnsigned) {
3047 bool IsFloatTy = GR.isScalarOrVectorOfType(
3048 InputRegister, SPIRV::OpTypeFloat);
3049 return IsFloatTy
3050 ? SPIRV::OpGroupNonUniformFMul
3051 : SPIRV::OpGroupNonUniformIMul;
3052 });
3053}
3054
3055template <typename PickOpcodeFn>
3056bool SPIRVInstructionSelector::selectWaveExclusiveScan(
3057 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, bool IsUnsigned,
3058 PickOpcodeFn &&PickOpcode) const {
3059 assert(I.getNumOperands() == 3);
3060 assert(I.getOperand(2).isReg());
3061 MachineBasicBlock &BB = *I.getParent();
3062 Register InputRegister = I.getOperand(2).getReg();
3063 SPIRVTypeInst InputType = GR.getSPIRVTypeForVReg(InputRegister);
3064
3065 if (!InputType)
3066 report_fatal_error("Input Type could not be determined.");
3067
3068 SPIRVTypeInst IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII);
3069 const unsigned Opcode = PickOpcode(InputRegister, IsUnsigned);
3070 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3071 .addDef(ResVReg)
3072 .addUse(GR.getSPIRVTypeID(ResType))
3073 .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
3074 !STI.isShader()))
3075 .addImm(SPIRV::GroupOperation::ExclusiveScan)
3076 .addUse(I.getOperand(2).getReg())
3077 .constrainAllUses(TII, TRI, RBI);
3078 return true;
3079}
3080
3081bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
3082 SPIRVTypeInst ResType,
3083 MachineInstr &I) const {
3084 MachineBasicBlock &BB = *I.getParent();
3085 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse))
3086 .addDef(ResVReg)
3087 .addUse(GR.getSPIRVTypeID(ResType))
3088 .addUse(I.getOperand(1).getReg())
3089 .constrainAllUses(TII, TRI, RBI);
3090 return true;
3091}
3092
3093bool SPIRVInstructionSelector::selectFreeze(Register ResVReg,
3094 SPIRVTypeInst ResType,
3095 MachineInstr &I) const {
3096 // There is no way to implement `freeze` correctly without support on SPIR-V
3097 // standard side, but we may at least address a simple (static) case when
3098 // undef/poison value presence is obvious. The main benefit of even
3099 // incomplete `freeze` support is preventing of translation from crashing due
3100 // to lack of support on legalization and instruction selection steps.
3101 if (!I.getOperand(0).isReg() || !I.getOperand(1).isReg())
3102 return false;
3103 Register OpReg = I.getOperand(1).getReg();
3104 if (MachineInstr *Def = MRI->getVRegDef(OpReg)) {
3105 if (Def->getOpcode() == TargetOpcode::COPY)
3106 Def = MRI->getVRegDef(Def->getOperand(1).getReg());
3107 Register Reg;
3108 switch (Def->getOpcode()) {
3109 case SPIRV::ASSIGN_TYPE:
3110 if (MachineInstr *AssignToDef =
3111 MRI->getVRegDef(Def->getOperand(1).getReg())) {
3112 if (AssignToDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
3113 Reg = Def->getOperand(2).getReg();
3114 }
3115 break;
3116 case SPIRV::OpUndef:
3117 Reg = Def->getOperand(1).getReg();
3118 break;
3119 }
3120 unsigned DestOpCode;
3121 if (Reg.isValid()) {
3122 DestOpCode = SPIRV::OpConstantNull;
3123 } else {
3124 DestOpCode = TargetOpcode::COPY;
3125 Reg = OpReg;
3126 }
3127 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DestOpCode))
3128 .addDef(I.getOperand(0).getReg())
3129 .addUse(Reg)
3130 .constrainAllUses(TII, TRI, RBI);
3131 return true;
3132 }
3133 return false;
3134}
3135
3136bool SPIRVInstructionSelector::selectBuildVector(Register ResVReg,
3137 SPIRVTypeInst ResType,
3138 MachineInstr &I) const {
3139 unsigned N = 0;
3140 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3141 N = GR.getScalarOrVectorComponentCount(ResType);
3142 else if (ResType->getOpcode() == SPIRV::OpTypeArray)
3143 N = getArrayComponentCount(MRI, ResType);
3144 else
3145 report_fatal_error("Cannot select G_BUILD_VECTOR with a non-vector result");
3146 if (I.getNumExplicitOperands() - I.getNumExplicitDefs() != N)
3147 report_fatal_error("G_BUILD_VECTOR and the result type are inconsistent");
3148
3149 // check if we may construct a constant vector
3150 bool IsConst = true;
3151 for (unsigned i = I.getNumExplicitDefs();
3152 i < I.getNumExplicitOperands() && IsConst; ++i)
3153 if (!isConstReg(MRI, I.getOperand(i).getReg()))
3154 IsConst = false;
3155
3156 if (!IsConst && N < 2)
3158 "There must be at least two constituent operands in a vector");
3159
3160 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
3161 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
3162 TII.get(IsConst ? SPIRV::OpConstantComposite
3163 : SPIRV::OpCompositeConstruct))
3164 .addDef(ResVReg)
3165 .addUse(GR.getSPIRVTypeID(ResType));
3166 for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i)
3167 MIB.addUse(I.getOperand(i).getReg());
3168 MIB.constrainAllUses(TII, TRI, RBI);
3169 return true;
3170}
3171
3172bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg,
3173 SPIRVTypeInst ResType,
3174 MachineInstr &I) const {
3175 unsigned N = 0;
3176 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3177 N = GR.getScalarOrVectorComponentCount(ResType);
3178 else if (ResType->getOpcode() == SPIRV::OpTypeArray)
3179 N = getArrayComponentCount(MRI, ResType);
3180 else
3181 report_fatal_error("Cannot select G_SPLAT_VECTOR with a non-vector result");
3182
3183 unsigned OpIdx = I.getNumExplicitDefs();
3184 if (!I.getOperand(OpIdx).isReg())
3185 report_fatal_error("Unexpected argument in G_SPLAT_VECTOR");
3186
3187 // check if we may construct a constant vector
3188 Register OpReg = I.getOperand(OpIdx).getReg();
3189 bool IsConst = isConstReg(MRI, OpReg);
3190
3191 if (!IsConst && N < 2)
3193 "There must be at least two constituent operands in a vector");
3194
3195 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
3196 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
3197 TII.get(IsConst ? SPIRV::OpConstantComposite
3198 : SPIRV::OpCompositeConstruct))
3199 .addDef(ResVReg)
3200 .addUse(GR.getSPIRVTypeID(ResType));
3201 for (unsigned i = 0; i < N; ++i)
3202 MIB.addUse(OpReg);
3203 MIB.constrainAllUses(TII, TRI, RBI);
3204 return true;
3205}
3206
3207bool SPIRVInstructionSelector::selectDiscard(Register ResVReg,
3208 SPIRVTypeInst ResType,
3209 MachineInstr &I) const {
3210
3211 unsigned Opcode;
3212
3213 if (STI.canUseExtension(
3214 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation) ||
3215 STI.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6))) {
3216 Opcode = SPIRV::OpDemoteToHelperInvocation;
3217 } else {
3218 Opcode = SPIRV::OpKill;
3219 // OpKill must be the last operation of any basic block.
3220 if (MachineInstr *NextI = I.getNextNode()) {
3221 GR.invalidateMachineInstr(NextI);
3222 NextI->eraseFromParent();
3223 }
3224 }
3225
3226 MachineBasicBlock &BB = *I.getParent();
3227 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3228 .constrainAllUses(TII, TRI, RBI);
3229 return true;
3230}
3231
3232bool SPIRVInstructionSelector::selectCmp(Register ResVReg,
3233 SPIRVTypeInst ResType, unsigned CmpOpc,
3234 MachineInstr &I) const {
3235 Register Cmp0 = I.getOperand(2).getReg();
3236 Register Cmp1 = I.getOperand(3).getReg();
3237 assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() ==
3238 GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() &&
3239 "CMP operands should have the same type");
3240 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(CmpOpc))
3241 .addDef(ResVReg)
3242 .addUse(GR.getSPIRVTypeID(ResType))
3243 .addUse(Cmp0)
3244 .addUse(Cmp1)
3245 .setMIFlags(I.getFlags())
3246 .constrainAllUses(TII, TRI, RBI);
3247 return true;
3248}
3249
3250bool SPIRVInstructionSelector::selectICmp(Register ResVReg,
3251 SPIRVTypeInst ResType,
3252 MachineInstr &I) const {
3253 auto Pred = I.getOperand(1).getPredicate();
3254 unsigned CmpOpc;
3255
3256 Register CmpOperand = I.getOperand(2).getReg();
3257 if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer))
3258 CmpOpc = getPtrCmpOpcode(Pred);
3259 else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool))
3260 CmpOpc = getBoolCmpOpcode(Pred);
3261 else
3262 CmpOpc = getICmpOpcode(Pred);
3263 return selectCmp(ResVReg, ResType, CmpOpc, I);
3264}
3265
3267SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I,
3268 SPIRVTypeInst ResType) const {
3269 Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32);
3270 SPIRVTypeInst SpvI32Ty =
3271 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII);
3272 // Find a constant in DT or build a new one.
3273 auto ConstInt = ConstantInt::get(LLVMTy, Val);
3274 Register NewReg = GR.find(ConstInt, GR.CurMF);
3275 if (!NewReg.isValid()) {
3276 NewReg = MRI->createGenericVirtualRegister(LLT::scalar(64));
3277 MachineBasicBlock &BB = *I.getParent();
3278 MachineInstr *MI =
3279 Val == 0
3280 ? BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
3281 .addDef(NewReg)
3282 .addUse(GR.getSPIRVTypeID(SpvI32Ty))
3283 : BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
3284 .addDef(NewReg)
3285 .addUse(GR.getSPIRVTypeID(SpvI32Ty))
3286 .addImm(APInt(32, Val).getZExtValue());
3288 GR.add(ConstInt, MI);
3289 }
3290 return NewReg;
3291}
3292
3293bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
3294 SPIRVTypeInst ResType,
3295 MachineInstr &I) const {
3296 unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate());
3297 return selectCmp(ResVReg, ResType, CmpOp, I);
3298}
3299
3300bool SPIRVInstructionSelector::selectExp10(Register ResVReg,
3301 SPIRVTypeInst ResType,
3302 MachineInstr &I) const {
3303 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
3304 return selectExtInst(ResVReg, ResType, I, CL::exp10);
3305 }
3306
3307 if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
3308 /// There is no exp10 in GLSL. Use exp10(x) = exp2(x * log2(10)) instead
3309 /// log2(10) ~= 3.3219280948874l
3310
3311 if (ResType->getOpcode() != SPIRV::OpTypeVector &&
3312 ResType->getOpcode() != SPIRV::OpTypeFloat)
3313 return false;
3314
3315 MachineIRBuilder MIRBuilder(I);
3316
3317 SPIRVTypeInst SpirvScalarType = ResType->getOpcode() == SPIRV::OpTypeVector
3318 ? SPIRVTypeInst(GR.getSPIRVTypeForVReg(
3319 ResType->getOperand(1).getReg()))
3320 : ResType;
3321
3322 assert(SpirvScalarType->getOperand(1).getImm() == 32 &&
3323 "only float operands supported by GLSL extended math");
3324
3325 Register ConstReg = GR.buildConstantFP(APFloat(3.3219280948874f),
3326 MIRBuilder, SpirvScalarType);
3327 Register ArgReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
3328 auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector
3329 ? SPIRV::OpVectorTimesScalar
3330 : SPIRV::OpFMulS;
3331
3332 if (!selectOpWithSrcs(ArgReg, ResType, I,
3333 {I.getOperand(1).getReg(), ConstReg}, Opcode))
3334 return false;
3335 if (!selectExtInst(ResVReg, ResType, I,
3336 {{SPIRV::InstructionSet::GLSL_std_450, GL::Exp2}}, false,
3337 false, {ArgReg}))
3338 return false;
3339
3340 return true;
3341 }
3342
3343 return false;
3344}
3345
3346Register SPIRVInstructionSelector::buildZerosVal(SPIRVTypeInst ResType,
3347 MachineInstr &I) const {
3348 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
3349 bool ZeroAsNull = !STI.isShader();
3350 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3351 return GR.getOrCreateConstVector(0UL, I, ResType, TII, ZeroAsNull);
3352 return GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
3353}
3354
3355bool SPIRVInstructionSelector::isScalarOrVectorIntConstantZero(
3356 Register Reg) const {
3357 SPIRVTypeInst Type = GR.getSPIRVTypeForVReg(Reg);
3358 if (!Type)
3359 return false;
3360 SPIRVTypeInst CompType = GR.getScalarOrVectorComponentType(Type);
3361 if (!CompType || CompType->getOpcode() != SPIRV::OpTypeInt)
3362 return false;
3363
3364 auto IsZero = [this](Register Reg) {
3365 MachineInstr *Def = getDefInstrMaybeConstant(Reg, MRI);
3366 if (!Def)
3367 return false;
3368
3369 if (Def->getOpcode() == SPIRV::OpConstantNull)
3370 return true;
3371
3372 if (Def->getOpcode() == TargetOpcode::G_CONSTANT ||
3373 Def->getOpcode() == SPIRV::OpConstantI)
3374 return getIConstVal(Reg, MRI) == 0;
3375
3376 return false;
3377 };
3378
3379 if (IsZero(Reg))
3380 return true;
3381
3382 MachineInstr *Def = MRI->getVRegDef(Reg);
3383 if (!Def)
3384 return false;
3385
3386 if (Def->getOpcode() == TargetOpcode::G_BUILD_VECTOR ||
3387 (Def->getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS &&
3388 cast<GIntrinsic>(Def)->getIntrinsicID() ==
3389 Intrinsic::spv_const_composite)) {
3390 unsigned StartOp = Def->getOpcode() == TargetOpcode::G_BUILD_VECTOR ? 1 : 2;
3391 for (unsigned i = StartOp; i < Def->getNumOperands(); ++i) {
3392 if (!IsZero(Def->getOperand(i).getReg()))
3393 return false;
3394 }
3395 return true;
3396 }
3397
3398 return false;
3399}
3400
3401Register SPIRVInstructionSelector::buildZerosValF(SPIRVTypeInst ResType,
3402 MachineInstr &I) const {
3403 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
3404 bool ZeroAsNull = !STI.isShader();
3405 APFloat VZero = getZeroFP(GR.getTypeForSPIRVType(ResType));
3406 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3407 return GR.getOrCreateConstVector(VZero, I, ResType, TII, ZeroAsNull);
3408 return GR.getOrCreateConstFP(VZero, I, ResType, TII, ZeroAsNull);
3409}
3410
3411Register SPIRVInstructionSelector::buildOnesValF(SPIRVTypeInst ResType,
3412 MachineInstr &I) const {
3413 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
3414 bool ZeroAsNull = !STI.isShader();
3415 APFloat VOne = getOneFP(GR.getTypeForSPIRVType(ResType));
3416 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3417 return GR.getOrCreateConstVector(VOne, I, ResType, TII, ZeroAsNull);
3418 return GR.getOrCreateConstFP(VOne, I, ResType, TII, ZeroAsNull);
3419}
3420
3421Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
3422 SPIRVTypeInst ResType,
3423 MachineInstr &I) const {
3424 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
3425 APInt One =
3426 AllOnes ? APInt::getAllOnes(BitWidth) : APInt::getOneBitSet(BitWidth, 0);
3427 if (ResType->getOpcode() == SPIRV::OpTypeVector)
3428 return GR.getOrCreateConstVector(One, I, ResType, TII);
3429 return GR.getOrCreateConstInt(One, I, ResType, TII);
3430}
3431
3432bool SPIRVInstructionSelector::selectSelect(Register ResVReg,
3433 SPIRVTypeInst ResType,
3434 MachineInstr &I) const {
3435 Register SelectFirstArg = I.getOperand(2).getReg();
3436 Register SelectSecondArg = I.getOperand(3).getReg();
3437 assert(ResType == GR.getSPIRVTypeForVReg(SelectFirstArg) &&
3438 ResType == GR.getSPIRVTypeForVReg(SelectSecondArg));
3439
3440 bool IsFloatTy =
3441 GR.isScalarOrVectorOfType(SelectFirstArg, SPIRV::OpTypeFloat);
3442 bool IsPtrTy =
3443 GR.isScalarOrVectorOfType(SelectFirstArg, SPIRV::OpTypePointer);
3444 bool IsVectorTy = GR.getSPIRVTypeForVReg(SelectFirstArg)->getOpcode() ==
3445 SPIRV::OpTypeVector;
3446
3447 bool IsScalarBool =
3448 GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool);
3449 unsigned Opcode;
3450 if (IsVectorTy) {
3451 if (IsFloatTy) {
3452 Opcode = IsScalarBool ? SPIRV::OpSelectVFSCond : SPIRV::OpSelectVFVCond;
3453 } else if (IsPtrTy) {
3454 Opcode = IsScalarBool ? SPIRV::OpSelectVPSCond : SPIRV::OpSelectVPVCond;
3455 } else {
3456 Opcode = IsScalarBool ? SPIRV::OpSelectVISCond : SPIRV::OpSelectVIVCond;
3457 }
3458 } else {
3459 if (IsFloatTy) {
3460 Opcode = IsScalarBool ? SPIRV::OpSelectSFSCond : SPIRV::OpSelectVFVCond;
3461 } else if (IsPtrTy) {
3462 Opcode = IsScalarBool ? SPIRV::OpSelectSPSCond : SPIRV::OpSelectVPVCond;
3463 } else {
3464 Opcode = IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond;
3465 }
3466 }
3467 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
3468 .addDef(ResVReg)
3469 .addUse(GR.getSPIRVTypeID(ResType))
3470 .addUse(I.getOperand(1).getReg())
3471 .addUse(SelectFirstArg)
3472 .addUse(SelectSecondArg)
3473 .constrainAllUses(TII, TRI, RBI);
3474 return true;
3475}
3476
3477// This function is used to extend a bool or a vector of bools into an integer
3478// or vector of integers.
3479bool SPIRVInstructionSelector::selectBoolToInt(Register ResVReg,
3480 SPIRVTypeInst ResType,
3481 Register BooleanVReg,
3482 MachineInstr &InsertAt,
3483 bool IsSigned) const {
3484 // To extend a bool, we need to use OpSelect between constants.
3485 Register ZeroReg = buildZerosVal(ResType, InsertAt);
3486 Register OneReg = buildOnesVal(IsSigned, ResType, InsertAt);
3487 bool IsScalarBool = GR.isScalarOfType(BooleanVReg, SPIRV::OpTypeBool);
3488 unsigned Opcode =
3489 IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond;
3490 BuildMI(*InsertAt.getParent(), InsertAt, InsertAt.getDebugLoc(),
3491 TII.get(Opcode))
3492 .addDef(ResVReg)
3493 .addUse(GR.getSPIRVTypeID(ResType))
3494 .addUse(BooleanVReg)
3495 .addUse(OneReg)
3496 .addUse(ZeroReg)
3497 .constrainAllUses(TII, TRI, RBI);
3498 return true;
3499}
3500
3501bool SPIRVInstructionSelector::selectIToF(Register ResVReg,
3502 SPIRVTypeInst ResType,
3503 MachineInstr &I, bool IsSigned,
3504 unsigned Opcode) const {
3505 Register SrcReg = I.getOperand(1).getReg();
3506 // We can convert bool value directly to float type without OpConvert*ToF,
3507 // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
3508 if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) {
3509 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
3510 SPIRVTypeInst TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII);
3511 if (ResType->getOpcode() == SPIRV::OpTypeVector) {
3512 const unsigned NumElts = ResType->getOperand(2).getImm();
3513 TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII);
3514 }
3515 SrcReg = createVirtualRegister(TmpType, &GR, MRI, MRI->getMF());
3516 selectBoolToInt(SrcReg, TmpType, I.getOperand(1).getReg(), I, false);
3517 }
3518 return selectOpWithSrcs(ResVReg, ResType, I, {SrcReg}, Opcode);
3519}
3520
3521bool SPIRVInstructionSelector::selectExt(Register ResVReg,
3522 SPIRVTypeInst ResType, MachineInstr &I,
3523 bool IsSigned) const {
3524 Register SrcReg = I.getOperand(1).getReg();
3525 if (GR.isScalarOrVectorOfType(SrcReg, SPIRV::OpTypeBool))
3526 return selectBoolToInt(ResVReg, ResType, I.getOperand(1).getReg(), I,
3527 IsSigned);
3528
3529 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(SrcReg);
3530 if (ResType == SrcType)
3531 return BuildCOPY(ResVReg, SrcReg, I);
3532
3533 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
3534 return selectUnOp(ResVReg, ResType, I, Opcode);
3535}
3536
3537bool SPIRVInstructionSelector::selectSUCmp(Register ResVReg,
3538 SPIRVTypeInst ResType,
3539 MachineInstr &I,
3540 bool IsSigned) const {
3541 MachineIRBuilder MIRBuilder(I);
3542 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
3543 MachineBasicBlock &BB = *I.getParent();
3544 // Ensure we have bool.
3545 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
3546 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
3547 if (N > 1)
3548 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, N, I, TII);
3549 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
3550 // Build less-than-equal and less-than.
3551 // TODO: replace with one-liner createVirtualRegister() from
3552 // llvm/lib/Target/SPIRV/SPIRVUtils.cpp when PR #116609 is merged.
3553 Register IsLessEqReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
3554 MRI->setType(IsLessEqReg, LLT::scalar(64));
3555 GR.assignSPIRVTypeToVReg(ResType, IsLessEqReg, MIRBuilder.getMF());
3556 BuildMI(BB, I, I.getDebugLoc(),
3557 TII.get(IsSigned ? SPIRV::OpSLessThanEqual : SPIRV::OpULessThanEqual))
3558 .addDef(IsLessEqReg)
3559 .addUse(BoolTypeReg)
3560 .addUse(I.getOperand(1).getReg())
3561 .addUse(I.getOperand(2).getReg())
3562 .constrainAllUses(TII, TRI, RBI);
3563 Register IsLessReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
3564 MRI->setType(IsLessReg, LLT::scalar(64));
3565 GR.assignSPIRVTypeToVReg(ResType, IsLessReg, MIRBuilder.getMF());
3566 BuildMI(BB, I, I.getDebugLoc(),
3567 TII.get(IsSigned ? SPIRV::OpSLessThan : SPIRV::OpULessThan))
3568 .addDef(IsLessReg)
3569 .addUse(BoolTypeReg)
3570 .addUse(I.getOperand(1).getReg())
3571 .addUse(I.getOperand(2).getReg())
3572 .constrainAllUses(TII, TRI, RBI);
3573 // Build selects.
3574 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
3575 Register NegOneOrZeroReg =
3576 MRI->createVirtualRegister(GR.getRegClass(ResType));
3577 MRI->setType(NegOneOrZeroReg, LLT::scalar(64));
3578 GR.assignSPIRVTypeToVReg(ResType, NegOneOrZeroReg, MIRBuilder.getMF());
3579 unsigned SelectOpcode =
3580 N > 1 ? SPIRV::OpSelectVIVCond : SPIRV::OpSelectSISCond;
3581 BuildMI(BB, I, I.getDebugLoc(), TII.get(SelectOpcode))
3582 .addDef(NegOneOrZeroReg)
3583 .addUse(ResTypeReg)
3584 .addUse(IsLessReg)
3585 .addUse(buildOnesVal(true, ResType, I)) // -1
3586 .addUse(buildZerosVal(ResType, I))
3587 .constrainAllUses(TII, TRI, RBI);
3588 BuildMI(BB, I, I.getDebugLoc(), TII.get(SelectOpcode))
3589 .addDef(ResVReg)
3590 .addUse(ResTypeReg)
3591 .addUse(IsLessEqReg)
3592 .addUse(NegOneOrZeroReg) // -1 or 0
3593 .addUse(buildOnesVal(false, ResType, I))
3594 .constrainAllUses(TII, TRI, RBI);
3595 return true;
3596}
3597
3598bool SPIRVInstructionSelector::selectIntToBool(Register IntReg,
3599 Register ResVReg,
3600 MachineInstr &I,
3601 SPIRVTypeInst IntTy,
3602 SPIRVTypeInst BoolTy) const {
3603 // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
3604 Register BitIntReg = createVirtualRegister(IntTy, &GR, MRI, MRI->getMF());
3605 bool IsVectorTy = IntTy->getOpcode() == SPIRV::OpTypeVector;
3606 unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
3607 Register Zero = buildZerosVal(IntTy, I);
3608 Register One = buildOnesVal(false, IntTy, I);
3609 MachineBasicBlock &BB = *I.getParent();
3610 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
3611 .addDef(BitIntReg)
3612 .addUse(GR.getSPIRVTypeID(IntTy))
3613 .addUse(IntReg)
3614 .addUse(One)
3615 .constrainAllUses(TII, TRI, RBI);
3616 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
3617 .addDef(ResVReg)
3618 .addUse(GR.getSPIRVTypeID(BoolTy))
3619 .addUse(BitIntReg)
3620 .addUse(Zero)
3621 .constrainAllUses(TII, TRI, RBI);
3622 return true;
3623}
3624
3625bool SPIRVInstructionSelector::selectTrunc(Register ResVReg,
3626 SPIRVTypeInst ResType,
3627 MachineInstr &I) const {
3628 Register IntReg = I.getOperand(1).getReg();
3629 const SPIRVTypeInst ArgType = GR.getSPIRVTypeForVReg(IntReg);
3630 if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool))
3631 return selectIntToBool(IntReg, ResVReg, I, ArgType, ResType);
3632 if (ArgType == ResType)
3633 return BuildCOPY(ResVReg, IntReg, I);
3634 bool IsSigned = GR.isScalarOrVectorSigned(ResType);
3635 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
3636 return selectUnOp(ResVReg, ResType, I, Opcode);
3637}
3638
3639bool SPIRVInstructionSelector::selectConst(Register ResVReg,
3640 SPIRVTypeInst ResType,
3641 MachineInstr &I) const {
3642 unsigned Opcode = I.getOpcode();
3643 unsigned TpOpcode = ResType->getOpcode();
3644 Register Reg;
3645 if (TpOpcode == SPIRV::OpTypePointer || TpOpcode == SPIRV::OpTypeEvent) {
3646 assert(Opcode == TargetOpcode::G_CONSTANT &&
3647 I.getOperand(1).getCImm()->isZero());
3648 MachineBasicBlock &DepMBB = I.getMF()->front();
3649 MachineIRBuilder MIRBuilder(DepMBB, DepMBB.getFirstNonPHI());
3650 Reg = GR.getOrCreateConstNullPtr(MIRBuilder, ResType);
3651 } else if (Opcode == TargetOpcode::G_FCONSTANT) {
3652 Reg = GR.getOrCreateConstFP(I.getOperand(1).getFPImm()->getValue(), I,
3653 ResType, TII, !STI.isShader());
3654 } else {
3655 Reg = GR.getOrCreateConstInt(I.getOperand(1).getCImm()->getValue(), I,
3656 ResType, TII, !STI.isShader());
3657 }
3658 return Reg == ResVReg ? true : BuildCOPY(ResVReg, Reg, I);
3659}
3660
3661bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg,
3662 SPIRVTypeInst ResType,
3663 MachineInstr &I) const {
3664 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
3665 .addDef(ResVReg)
3666 .addUse(GR.getSPIRVTypeID(ResType))
3667 .constrainAllUses(TII, TRI, RBI);
3668 return true;
3669}
3670
3671bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg,
3672 SPIRVTypeInst ResType,
3673 MachineInstr &I) const {
3674 MachineBasicBlock &BB = *I.getParent();
3675 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeInsert))
3676 .addDef(ResVReg)
3677 .addUse(GR.getSPIRVTypeID(ResType))
3678 // object to insert
3679 .addUse(I.getOperand(3).getReg())
3680 // composite to insert into
3681 .addUse(I.getOperand(2).getReg());
3682 for (unsigned i = 4; i < I.getNumOperands(); i++)
3683 MIB.addImm(foldImm(I.getOperand(i), MRI));
3684 MIB.constrainAllUses(TII, TRI, RBI);
3685 return true;
3686}
3687
3688bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg,
3689 SPIRVTypeInst ResType,
3690 MachineInstr &I) const {
3691 Type *MaybeResTy = nullptr;
3692 StringRef ResName;
3693 if (GR.findValueAttrs(&I, MaybeResTy, ResName) &&
3694 MaybeResTy != GR.getTypeForSPIRVType(ResType)) {
3695 assert((!MaybeResTy || MaybeResTy->isAggregateType()) &&
3696 "Expected aggregate type for extractv instruction");
3697 ResType = GR.getOrCreateSPIRVType(MaybeResTy, I,
3698 SPIRV::AccessQualifier::ReadWrite, false);
3699 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *I.getMF());
3700 }
3701 MachineBasicBlock &BB = *I.getParent();
3702 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
3703 .addDef(ResVReg)
3704 .addUse(GR.getSPIRVTypeID(ResType))
3705 .addUse(I.getOperand(2).getReg());
3706 for (unsigned i = 3; i < I.getNumOperands(); i++)
3707 MIB.addImm(foldImm(I.getOperand(i), MRI));
3708 MIB.constrainAllUses(TII, TRI, RBI);
3709 return true;
3710}
3711
3712bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg,
3713 SPIRVTypeInst ResType,
3714 MachineInstr &I) const {
3715 if (getImm(I.getOperand(4), MRI))
3716 return selectInsertVal(ResVReg, ResType, I);
3717 MachineBasicBlock &BB = *I.getParent();
3718 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorInsertDynamic))
3719 .addDef(ResVReg)
3720 .addUse(GR.getSPIRVTypeID(ResType))
3721 .addUse(I.getOperand(2).getReg())
3722 .addUse(I.getOperand(3).getReg())
3723 .addUse(I.getOperand(4).getReg())
3724 .constrainAllUses(TII, TRI, RBI);
3725 return true;
3726}
3727
3728bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg,
3729 SPIRVTypeInst ResType,
3730 MachineInstr &I) const {
3731 if (getImm(I.getOperand(3), MRI))
3732 return selectExtractVal(ResVReg, ResType, I);
3733 MachineBasicBlock &BB = *I.getParent();
3734 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorExtractDynamic))
3735 .addDef(ResVReg)
3736 .addUse(GR.getSPIRVTypeID(ResType))
3737 .addUse(I.getOperand(2).getReg())
3738 .addUse(I.getOperand(3).getReg())
3739 .constrainAllUses(TII, TRI, RBI);
3740 return true;
3741}
3742
3743bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
3744 SPIRVTypeInst ResType,
3745 MachineInstr &I) const {
3746 const bool IsGEPInBounds = I.getOperand(2).getImm();
3747
3748 // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator only
3749 // relies on PtrAccessChain, so we'll try not to deviate. For Vulkan however,
3750 // we have to use Op[InBounds]AccessChain.
3751 const unsigned Opcode = STI.isLogicalSPIRV()
3752 ? (IsGEPInBounds ? SPIRV::OpInBoundsAccessChain
3753 : SPIRV::OpAccessChain)
3754 : (IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
3755 : SPIRV::OpPtrAccessChain);
3756
3757 auto Res = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
3758 .addDef(ResVReg)
3759 .addUse(GR.getSPIRVTypeID(ResType))
3760 // Object to get a pointer to.
3761 .addUse(I.getOperand(3).getReg());
3762 assert(
3763 (Opcode == SPIRV::OpPtrAccessChain ||
3764 Opcode == SPIRV::OpInBoundsPtrAccessChain ||
3765 (getImm(I.getOperand(4), MRI) && foldImm(I.getOperand(4), MRI) == 0)) &&
3766 "Cannot translate GEP to OpAccessChain. First index must be 0.");
3767
3768 // Adding indices.
3769 const unsigned StartingIndex =
3770 (Opcode == SPIRV::OpAccessChain || Opcode == SPIRV::OpInBoundsAccessChain)
3771 ? 5
3772 : 4;
3773 for (unsigned i = StartingIndex; i < I.getNumExplicitOperands(); ++i)
3774 Res.addUse(I.getOperand(i).getReg());
3775 Res.constrainAllUses(TII, TRI, RBI);
3776 return true;
3777}
3778
3779// Maybe wrap a value into OpSpecConstantOp
3780bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
3781 MachineInstr &I, SmallVector<Register> &CompositeArgs) const {
3782 unsigned Lim = I.getNumExplicitOperands();
3783 for (unsigned i = I.getNumExplicitDefs() + 1; i < Lim; ++i) {
3784 Register OpReg = I.getOperand(i).getReg();
3785 MachineInstr *OpDefine = MRI->getVRegDef(OpReg);
3786 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
3787 if (!OpDefine || !OpType || isConstReg(MRI, OpDefine) ||
3788 OpDefine->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
3789 OpDefine->getOpcode() == TargetOpcode::G_INTTOPTR ||
3790 GR.isAggregateType(OpType)) {
3791 // The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed
3792 // by selectAddrSpaceCast(), and G_INTTOPTR is processed by selectUnOp()
3793 CompositeArgs.push_back(OpReg);
3794 continue;
3795 }
3796 MachineFunction *MF = I.getMF();
3797 Register WrapReg = GR.find(OpDefine, MF);
3798 if (WrapReg.isValid()) {
3799 CompositeArgs.push_back(WrapReg);
3800 continue;
3801 }
3802 // Create a new register for the wrapper
3803 WrapReg = MRI->createVirtualRegister(GR.getRegClass(OpType));
3804 CompositeArgs.push_back(WrapReg);
3805 // Decorate the wrapper register and generate a new instruction
3806 MRI->setType(WrapReg, LLT::pointer(0, 64));
3807 GR.assignSPIRVTypeToVReg(OpType, WrapReg, *MF);
3808 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
3809 TII.get(SPIRV::OpSpecConstantOp))
3810 .addDef(WrapReg)
3811 .addUse(GR.getSPIRVTypeID(OpType))
3812 .addImm(static_cast<uint32_t>(SPIRV::Opcode::Bitcast))
3813 .addUse(OpReg);
3814 GR.add(OpDefine, MIB);
3815 MIB.constrainAllUses(TII, TRI, RBI);
3816 }
3817 return true;
3818}
3819
3820bool SPIRVInstructionSelector::selectDerivativeInst(
3821 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
3822 const unsigned DPdOpCode) const {
3823 // TODO: This should check specifically for Fragment Execution Model, but STI
3824 // doesn't provide that information yet. See #167562
3825 errorIfInstrOutsideShader(I);
3826
3827 // If the arg/result types are half then we need to wrap the instr in
3828 // conversions to float
3829 // This case occurs because a half arg/result is legal in HLSL but not spirv.
3830 Register SrcReg = I.getOperand(2).getReg();
3831 SPIRVTypeInst SrcType = GR.getSPIRVTypeForVReg(SrcReg);
3832 unsigned BitWidth = std::min(GR.getScalarOrVectorBitWidth(SrcType),
3833 GR.getScalarOrVectorBitWidth(ResType));
3834 if (BitWidth == 32)
3835 return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DPdOpCode))
3836 .addDef(ResVReg)
3837 .addUse(GR.getSPIRVTypeID(ResType))
3838 .addUse(I.getOperand(2).getReg());
3839
3840 MachineIRBuilder MIRBuilder(I);
3841 unsigned componentCount = GR.getScalarOrVectorComponentCount(SrcType);
3842 SPIRVTypeInst F32ConvertTy = GR.getOrCreateSPIRVFloatType(32, I, TII);
3843 if (componentCount != 1)
3844 F32ConvertTy = GR.getOrCreateSPIRVVectorType(F32ConvertTy, componentCount,
3845 MIRBuilder, false);
3846
3847 const TargetRegisterClass *RegClass = GR.getRegClass(SrcType);
3848 Register ConvertToVReg = MRI->createVirtualRegister(RegClass);
3849 Register DpdOpVReg = MRI->createVirtualRegister(RegClass);
3850
3851 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFConvert))
3852 .addDef(ConvertToVReg)
3853 .addUse(GR.getSPIRVTypeID(F32ConvertTy))
3854 .addUse(SrcReg)
3855 .constrainAllUses(TII, TRI, RBI);
3856 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DPdOpCode))
3857 .addDef(DpdOpVReg)
3858 .addUse(GR.getSPIRVTypeID(F32ConvertTy))
3859 .addUse(ConvertToVReg)
3860 .constrainAllUses(TII, TRI, RBI);
3861 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpFConvert))
3862 .addDef(ResVReg)
3863 .addUse(GR.getSPIRVTypeID(ResType))
3864 .addUse(DpdOpVReg)
3865 .constrainAllUses(TII, TRI, RBI);
3866 return true;
3867}
3868
3869bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
3870 SPIRVTypeInst ResType,
3871 MachineInstr &I) const {
3872 MachineBasicBlock &BB = *I.getParent();
3873 Intrinsic::ID IID = cast<GIntrinsic>(I).getIntrinsicID();
3874 switch (IID) {
3875 case Intrinsic::spv_load:
3876 return selectLoad(ResVReg, ResType, I);
3877 case Intrinsic::spv_store:
3878 return selectStore(I);
3879 case Intrinsic::spv_extractv:
3880 return selectExtractVal(ResVReg, ResType, I);
3881 case Intrinsic::spv_insertv:
3882 return selectInsertVal(ResVReg, ResType, I);
3883 case Intrinsic::spv_extractelt:
3884 return selectExtractElt(ResVReg, ResType, I);
3885 case Intrinsic::spv_insertelt:
3886 return selectInsertElt(ResVReg, ResType, I);
3887 case Intrinsic::spv_gep:
3888 return selectGEP(ResVReg, ResType, I);
3889 case Intrinsic::spv_bitcast: {
3890 Register OpReg = I.getOperand(2).getReg();
3891 SPIRVTypeInst OpType =
3892 OpReg.isValid() ? GR.getSPIRVTypeForVReg(OpReg) : nullptr;
3893 if (!GR.isBitcastCompatible(ResType, OpType))
3894 report_fatal_error("incompatible result and operand types in a bitcast");
3895 return selectOpWithSrcs(ResVReg, ResType, I, {OpReg}, SPIRV::OpBitcast);
3896 }
3897 case Intrinsic::spv_unref_global:
3898 case Intrinsic::spv_init_global: {
3899 MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());
3900 MachineInstr *Init = I.getNumExplicitOperands() > 2
3901 ? MRI->getVRegDef(I.getOperand(2).getReg())
3902 : nullptr;
3903 assert(MI);
3904 Register GVarVReg = MI->getOperand(0).getReg();
3905 if (!selectGlobalValue(GVarVReg, *MI, Init))
3906 return false;
3907 // We violate SSA form by inserting OpVariable and still having a gMIR
3908 // instruction %vreg = G_GLOBAL_VALUE @gvar. We need to fix this by erasing
3909 // the duplicated definition.
3910 if (MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
3912 MI->eraseFromParent();
3913 }
3914 return true;
3915 }
3916 case Intrinsic::spv_undef: {
3917 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
3918 .addDef(ResVReg)
3919 .addUse(GR.getSPIRVTypeID(ResType));
3920 MIB.constrainAllUses(TII, TRI, RBI);
3921 return true;
3922 }
3923 case Intrinsic::spv_const_composite: {
3924 // If no values are attached, the composite is null constant.
3925 bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
3926 SmallVector<Register> CompositeArgs;
3927 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
3928
3929 // skip type MD node we already used when generated assign.type for this
3930 if (!IsNull) {
3931 if (!wrapIntoSpecConstantOp(I, CompositeArgs))
3932 return false;
3933 MachineIRBuilder MIR(I);
3934 SmallVector<MachineInstr *, 4> Instructions = createContinuedInstructions(
3935 MIR, SPIRV::OpConstantComposite, 3,
3936 SPIRV::OpConstantCompositeContinuedINTEL, CompositeArgs, ResVReg,
3937 GR.getSPIRVTypeID(ResType));
3938 for (auto *Instr : Instructions) {
3939 Instr->setDebugLoc(I.getDebugLoc());
3941 }
3942 return true;
3943 } else {
3944 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
3945 .addDef(ResVReg)
3946 .addUse(GR.getSPIRVTypeID(ResType));
3947 MIB.constrainAllUses(TII, TRI, RBI);
3948 return true;
3949 }
3950 }
3951 case Intrinsic::spv_assign_name: {
3952 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName));
3953 MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg());
3954 for (unsigned i = I.getNumExplicitDefs() + 2;
3955 i < I.getNumExplicitOperands(); ++i) {
3956 MIB.addImm(I.getOperand(i).getImm());
3957 }
3958 MIB.constrainAllUses(TII, TRI, RBI);
3959 return true;
3960 }
3961 case Intrinsic::spv_switch: {
3962 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch));
3963 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
3964 if (I.getOperand(i).isReg())
3965 MIB.addReg(I.getOperand(i).getReg());
3966 else if (I.getOperand(i).isCImm())
3967 addNumImm(I.getOperand(i).getCImm()->getValue(), MIB);
3968 else if (I.getOperand(i).isMBB())
3969 MIB.addMBB(I.getOperand(i).getMBB());
3970 else
3971 llvm_unreachable("Unexpected OpSwitch operand");
3972 }
3973 MIB.constrainAllUses(TII, TRI, RBI);
3974 return true;
3975 }
3976 case Intrinsic::spv_loop_merge: {
3977 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopMerge));
3978 for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
3979 if (I.getOperand(i).isMBB())
3980 MIB.addMBB(I.getOperand(i).getMBB());
3981 else
3982 MIB.addImm(foldImm(I.getOperand(i), MRI));
3983 }
3984 MIB.constrainAllUses(TII, TRI, RBI);
3985 return true;
3986 }
3987 case Intrinsic::spv_loop_control_intel: {
3988 auto MIB =
3989 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopControlINTEL));
3990 for (unsigned J = 1; J < I.getNumExplicitOperands(); ++J)
3991 MIB.addImm(foldImm(I.getOperand(J), MRI));
3992 MIB.constrainAllUses(TII, TRI, RBI);
3993 return true;
3994 }
3995 case Intrinsic::spv_selection_merge: {
3996 auto MIB =
3997 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSelectionMerge));
3998 assert(I.getOperand(1).isMBB() &&
3999 "operand 1 to spv_selection_merge must be a basic block");
4000 MIB.addMBB(I.getOperand(1).getMBB());
4001 MIB.addImm(getSelectionOperandForImm(I.getOperand(2).getImm()));
4002 MIB.constrainAllUses(TII, TRI, RBI);
4003 return true;
4004 }
4005 case Intrinsic::spv_cmpxchg:
4006 return selectAtomicCmpXchg(ResVReg, ResType, I);
4007 case Intrinsic::spv_unreachable:
4008 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUnreachable))
4009 .constrainAllUses(TII, TRI, RBI);
4010 return true;
4011 case Intrinsic::spv_alloca:
4012 return selectFrameIndex(ResVReg, ResType, I);
4013 case Intrinsic::spv_alloca_array:
4014 return selectAllocaArray(ResVReg, ResType, I);
4015 case Intrinsic::spv_assume:
4016 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
4017 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAssumeTrueKHR))
4018 .addUse(I.getOperand(1).getReg())
4019 .constrainAllUses(TII, TRI, RBI);
4020 return true;
4021 }
4022 break;
4023 case Intrinsic::spv_expect:
4024 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
4025 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExpectKHR))
4026 .addDef(ResVReg)
4027 .addUse(GR.getSPIRVTypeID(ResType))
4028 .addUse(I.getOperand(2).getReg())
4029 .addUse(I.getOperand(3).getReg())
4030 .constrainAllUses(TII, TRI, RBI);
4031 return true;
4032 }
4033 break;
4034 case Intrinsic::arithmetic_fence:
4035 if (STI.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence)) {
4036 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpArithmeticFenceEXT))
4037 .addDef(ResVReg)
4038 .addUse(GR.getSPIRVTypeID(ResType))
4039 .addUse(I.getOperand(2).getReg())
4040 .constrainAllUses(TII, TRI, RBI);
4041 return true;
4042 } else
4043 return BuildCOPY(ResVReg, I.getOperand(2).getReg(), I);
4044 break;
4045 case Intrinsic::spv_thread_id:
4046 // The HLSL SV_DispatchThreadID semantic is lowered to llvm.spv.thread.id
4047 // intrinsic in LLVM IR for SPIR-V backend.
4048 //
4049 // In SPIR-V backend, llvm.spv.thread.id is now correctly translated to a
4050 // `GlobalInvocationId` builtin variable
4051 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalInvocationId, ResVReg,
4052 ResType, I);
4053 case Intrinsic::spv_thread_id_in_group:
4054 // The HLSL SV_GroupThreadId semantic is lowered to
4055 // llvm.spv.thread.id.in.group intrinsic in LLVM IR for SPIR-V backend.
4056 //
4057 // In SPIR-V backend, llvm.spv.thread.id.in.group is now correctly
4058 // translated to a `LocalInvocationId` builtin variable
4059 return loadVec3BuiltinInputID(SPIRV::BuiltIn::LocalInvocationId, ResVReg,
4060 ResType, I);
4061 case Intrinsic::spv_group_id:
4062 // The HLSL SV_GroupId semantic is lowered to
4063 // llvm.spv.group.id intrinsic in LLVM IR for SPIR-V backend.
4064 //
4065 // In SPIR-V backend, llvm.spv.group.id is now translated to a `WorkgroupId`
4066 // builtin variable
4067 return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupId, ResVReg, ResType,
4068 I);
4069 case Intrinsic::spv_flattened_thread_id_in_group:
4070 // The HLSL SV_GroupIndex semantic is lowered to
4071 // llvm.spv.flattened.thread.id.in.group() intrinsic in LLVM IR for SPIR-V
4072 // backend.
4073 //
4074 // In SPIR-V backend, llvm.spv.flattened.thread.id.in.group is translated to
4075 // a `LocalInvocationIndex` builtin variable
4076 return loadBuiltinInputID(SPIRV::BuiltIn::LocalInvocationIndex, ResVReg,
4077 ResType, I);
4078 case Intrinsic::spv_workgroup_size:
4079 return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupSize, ResVReg,
4080 ResType, I);
4081 case Intrinsic::spv_global_size:
4082 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalSize, ResVReg, ResType,
4083 I);
4084 case Intrinsic::spv_global_offset:
4085 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalOffset, ResVReg,
4086 ResType, I);
4087 case Intrinsic::spv_num_workgroups:
4088 return loadVec3BuiltinInputID(SPIRV::BuiltIn::NumWorkgroups, ResVReg,
4089 ResType, I);
4090 case Intrinsic::spv_subgroup_size:
4091 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupSize, ResVReg, ResType,
4092 I);
4093 case Intrinsic::spv_num_subgroups:
4094 return loadBuiltinInputID(SPIRV::BuiltIn::NumSubgroups, ResVReg, ResType,
4095 I);
4096 case Intrinsic::spv_subgroup_id:
4097 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupId, ResVReg, ResType, I);
4098 case Intrinsic::spv_subgroup_local_invocation_id:
4099 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupLocalInvocationId,
4100 ResVReg, ResType, I);
4101 case Intrinsic::spv_subgroup_max_size:
4102 return loadBuiltinInputID(SPIRV::BuiltIn::SubgroupMaxSize, ResVReg, ResType,
4103 I);
4104 case Intrinsic::spv_fdot:
4105 return selectFloatDot(ResVReg, ResType, I);
4106 case Intrinsic::spv_udot:
4107 case Intrinsic::spv_sdot:
4108 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
4109 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
4110 return selectIntegerDot(ResVReg, ResType, I,
4111 /*Signed=*/IID == Intrinsic::spv_sdot);
4112 return selectIntegerDotExpansion(ResVReg, ResType, I);
4113 case Intrinsic::spv_dot4add_i8packed:
4114 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
4115 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
4116 return selectDot4AddPacked<true>(ResVReg, ResType, I);
4117 return selectDot4AddPackedExpansion<true>(ResVReg, ResType, I);
4118 case Intrinsic::spv_dot4add_u8packed:
4119 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
4120 STI.isAtLeastSPIRVVer(VersionTuple(1, 6)))
4121 return selectDot4AddPacked<false>(ResVReg, ResType, I);
4122 return selectDot4AddPackedExpansion<false>(ResVReg, ResType, I);
4123 case Intrinsic::spv_all:
4124 return selectAll(ResVReg, ResType, I);
4125 case Intrinsic::spv_any:
4126 return selectAny(ResVReg, ResType, I);
4127 case Intrinsic::spv_cross:
4128 return selectExtInst(ResVReg, ResType, I, CL::cross, GL::Cross);
4129 case Intrinsic::spv_distance:
4130 return selectExtInst(ResVReg, ResType, I, CL::distance, GL::Distance);
4131 case Intrinsic::spv_lerp:
4132 return selectExtInst(ResVReg, ResType, I, CL::mix, GL::FMix);
4133 case Intrinsic::spv_length:
4134 return selectExtInst(ResVReg, ResType, I, CL::length, GL::Length);
4135 case Intrinsic::spv_degrees:
4136 return selectExtInst(ResVReg, ResType, I, CL::degrees, GL::Degrees);
4137 case Intrinsic::spv_faceforward:
4138 return selectExtInst(ResVReg, ResType, I, GL::FaceForward);
4139 case Intrinsic::spv_frac:
4140 return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
4141 case Intrinsic::spv_isinf:
4142 return selectOpIsInf(ResVReg, ResType, I);
4143 case Intrinsic::spv_isnan:
4144 return selectOpIsNan(ResVReg, ResType, I);
4145 case Intrinsic::spv_normalize:
4146 return selectExtInst(ResVReg, ResType, I, CL::normalize, GL::Normalize);
4147 case Intrinsic::spv_refract:
4148 return selectExtInst(ResVReg, ResType, I, GL::Refract);
4149 case Intrinsic::spv_reflect:
4150 return selectExtInst(ResVReg, ResType, I, GL::Reflect);
4151 case Intrinsic::spv_rsqrt:
4152 return selectExtInst(ResVReg, ResType, I, CL::rsqrt, GL::InverseSqrt);
4153 case Intrinsic::spv_sign:
4154 return selectSign(ResVReg, ResType, I);
4155 case Intrinsic::spv_smoothstep:
4156 return selectExtInst(ResVReg, ResType, I, CL::smoothstep, GL::SmoothStep);
4157 case Intrinsic::spv_firstbituhigh: // There is no CL equivalent of FindUMsb
4158 return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/false);
4159 case Intrinsic::spv_firstbitshigh: // There is no CL equivalent of FindSMsb
4160 return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/true);
4161 case Intrinsic::spv_firstbitlow: // There is no CL equivlent of FindILsb
4162 return selectFirstBitLow(ResVReg, ResType, I);
4163 case Intrinsic::spv_group_memory_barrier_with_group_sync: {
4164 Register MemSemReg =
4165 buildI32Constant(SPIRV::MemorySemantics::SequentiallyConsistent, I);
4166 Register ScopeReg = buildI32Constant(SPIRV::Scope::Workgroup, I);
4167 MachineBasicBlock &BB = *I.getParent();
4168 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpControlBarrier))
4169 .addUse(ScopeReg)
4170 .addUse(ScopeReg)
4171 .addUse(MemSemReg)
4172 .constrainAllUses(TII, TRI, RBI);
4173 return true;
4174 }
4175 case Intrinsic::spv_generic_cast_to_ptr_explicit: {
4176 Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 1).getReg();
4177 SPIRV::StorageClass::StorageClass ResSC =
4178 GR.getPointerStorageClass(ResType);
4179 if (!isGenericCastablePtr(ResSC))
4180 report_fatal_error("The target storage class is not castable from the "
4181 "Generic storage class");
4182 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpGenericCastToPtrExplicit))
4183 .addDef(ResVReg)
4184 .addUse(GR.getSPIRVTypeID(ResType))
4185 .addUse(PtrReg)
4186 .addImm(ResSC)
4187 .constrainAllUses(TII, TRI, RBI);
4188 return true;
4189 }
4190 case Intrinsic::spv_lifetime_start:
4191 case Intrinsic::spv_lifetime_end: {
4192 unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
4193 : SPIRV::OpLifetimeStop;
4194 int64_t Size = I.getOperand(I.getNumExplicitDefs() + 1).getImm();
4195 Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 2).getReg();
4196 if (Size == -1)
4197 Size = 0;
4198 BuildMI(BB, I, I.getDebugLoc(), TII.get(Op))
4199 .addUse(PtrReg)
4200 .addImm(Size)
4201 .constrainAllUses(TII, TRI, RBI);
4202 return true;
4203 }
4204 case Intrinsic::spv_saturate:
4205 return selectSaturate(ResVReg, ResType, I);
4206 case Intrinsic::spv_nclamp:
4207 return selectExtInst(ResVReg, ResType, I, CL::fclamp, GL::NClamp);
4208 case Intrinsic::spv_uclamp:
4209 return selectExtInst(ResVReg, ResType, I, CL::u_clamp, GL::UClamp);
4210 case Intrinsic::spv_sclamp:
4211 return selectExtInst(ResVReg, ResType, I, CL::s_clamp, GL::SClamp);
4212 case Intrinsic::spv_subgroup_prefix_bit_count:
4213 return selectWavePrefixBitCount(ResVReg, ResType, I);
4214 case Intrinsic::spv_wave_active_countbits:
4215 return selectWaveActiveCountBits(ResVReg, ResType, I);
4216 case Intrinsic::spv_wave_all_equal:
4217 return selectWaveActiveAllEqual(ResVReg, ResType, I);
4218 case Intrinsic::spv_wave_all:
4219 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAll);
4220 case Intrinsic::spv_wave_any:
4221 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAny);
4222 case Intrinsic::spv_subgroup_ballot:
4223 return selectWaveOpInst(ResVReg, ResType, I,
4224 SPIRV::OpGroupNonUniformBallot);
4225 case Intrinsic::spv_wave_is_first_lane:
4226 return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformElect);
4227 case Intrinsic::spv_wave_reduce_umax:
4228 return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ true);
4229 case Intrinsic::spv_wave_reduce_max:
4230 return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ false);
4231 case Intrinsic::spv_wave_reduce_umin:
4232 return selectWaveReduceMin(ResVReg, ResType, I, /*IsUnsigned*/ true);
4233 case Intrinsic::spv_wave_reduce_min:
4234 return selectWaveReduceMin(ResVReg, ResType, I, /*IsUnsigned*/ false);
4235 case Intrinsic::spv_wave_reduce_sum:
4236 return selectWaveReduceSum(ResVReg, ResType, I);
4237 case Intrinsic::spv_wave_readlane:
4238 return selectWaveOpInst(ResVReg, ResType, I,
4239 SPIRV::OpGroupNonUniformShuffle);
4240 case Intrinsic::spv_wave_prefix_sum:
4241 return selectWaveExclusiveScanSum(ResVReg, ResType, I);
4242 case Intrinsic::spv_wave_prefix_product:
4243 return selectWaveExclusiveScanProduct(ResVReg, ResType, I);
4244 case Intrinsic::spv_step:
4245 return selectExtInst(ResVReg, ResType, I, CL::step, GL::Step);
4246 case Intrinsic::spv_radians:
4247 return selectExtInst(ResVReg, ResType, I, CL::radians, GL::Radians);
4248 // Discard intrinsics which we do not expect to actually represent code after
4249 // lowering or intrinsics which are not implemented but should not crash when
4250 // found in a customer's LLVM IR input.
4251 case Intrinsic::instrprof_increment:
4252 case Intrinsic::instrprof_increment_step:
4253 case Intrinsic::instrprof_value_profile:
4254 break;
4255 // Discard internal intrinsics.
4256 case Intrinsic::spv_value_md:
4257 break;
4258 case Intrinsic::spv_resource_handlefrombinding: {
4259 return selectHandleFromBinding(ResVReg, ResType, I);
4260 }
4261 case Intrinsic::spv_resource_counterhandlefrombinding:
4262 return selectCounterHandleFromBinding(ResVReg, ResType, I);
4263 case Intrinsic::spv_resource_updatecounter:
4264 return selectUpdateCounter(ResVReg, ResType, I);
4265 case Intrinsic::spv_resource_store_typedbuffer: {
4266 return selectImageWriteIntrinsic(I);
4267 }
4268 case Intrinsic::spv_resource_load_typedbuffer: {
4269 return selectReadImageIntrinsic(ResVReg, ResType, I);
4270 }
4271 case Intrinsic::spv_resource_sample:
4272 case Intrinsic::spv_resource_sample_clamp:
4273 return selectSampleBasicIntrinsic(ResVReg, ResType, I);
4274 case Intrinsic::spv_resource_samplebias:
4275 case Intrinsic::spv_resource_samplebias_clamp:
4276 return selectSampleBiasIntrinsic(ResVReg, ResType, I);
4277 case Intrinsic::spv_resource_samplegrad:
4278 case Intrinsic::spv_resource_samplegrad_clamp:
4279 return selectSampleGradIntrinsic(ResVReg, ResType, I);
4280 case Intrinsic::spv_resource_samplelevel:
4281 return selectSampleLevelIntrinsic(ResVReg, ResType, I);
4282 case Intrinsic::spv_resource_samplecmp:
4283 case Intrinsic::spv_resource_samplecmp_clamp:
4284 return selectSampleCmpIntrinsic(ResVReg, ResType, I);
4285 case Intrinsic::spv_resource_samplecmplevelzero:
4286 return selectSampleCmpLevelZeroIntrinsic(ResVReg, ResType, I);
4287 case Intrinsic::spv_resource_gather:
4288 case Intrinsic::spv_resource_gather_cmp:
4289 return selectGatherIntrinsic(ResVReg, ResType, I);
4290 case Intrinsic::spv_resource_getpointer: {
4291 return selectResourceGetPointer(ResVReg, ResType, I);
4292 }
4293 case Intrinsic::spv_pushconstant_getpointer: {
4294 return selectPushConstantGetPointer(ResVReg, ResType, I);
4295 }
4296 case Intrinsic::spv_discard: {
4297 return selectDiscard(ResVReg, ResType, I);
4298 }
4299 case Intrinsic::spv_resource_nonuniformindex: {
4300 return selectResourceNonUniformIndex(ResVReg, ResType, I);
4301 }
4302 case Intrinsic::spv_unpackhalf2x16: {
4303 return selectExtInst(ResVReg, ResType, I, GL::UnpackHalf2x16);
4304 }
4305 case Intrinsic::spv_packhalf2x16: {
4306 return selectExtInst(ResVReg, ResType, I, GL::PackHalf2x16);
4307 }
4308 case Intrinsic::spv_ddx:
4309 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdx);
4310 case Intrinsic::spv_ddy:
4311 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdy);
4312 case Intrinsic::spv_ddx_coarse:
4313 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxCoarse);
4314 case Intrinsic::spv_ddy_coarse:
4315 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
4316 case Intrinsic::spv_ddx_fine:
4317 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxFine);
4318 case Intrinsic::spv_ddy_fine:
4319 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyFine);
4320 case Intrinsic::spv_fwidth:
4321 return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpFwidth);
4322 default: {
4323 std::string DiagMsg;
4324 raw_string_ostream OS(DiagMsg);
4325 I.print(OS);
4326 DiagMsg = "Intrinsic selection not implemented: " + DiagMsg;
4327 report_fatal_error(DiagMsg.c_str(), false);
4328 }
4329 }
4330 return true;
4331}
4332
4333bool SPIRVInstructionSelector::selectHandleFromBinding(Register &ResVReg,
4334 SPIRVTypeInst ResType,
4335 MachineInstr &I) const {
4336 // The images need to be loaded in the same basic block as their use. We defer
4337 // loading the image to the intrinsic that uses it.
4338 if (ResType->getOpcode() == SPIRV::OpTypeImage)
4339 return true;
4340
4341 return loadHandleBeforePosition(ResVReg, GR.getSPIRVTypeForVReg(ResVReg),
4342 *cast<GIntrinsic>(&I), I);
4343}
4344
4345bool SPIRVInstructionSelector::selectCounterHandleFromBinding(
4346 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4347 auto &Intr = cast<GIntrinsic>(I);
4348 assert(Intr.getIntrinsicID() ==
4349 Intrinsic::spv_resource_counterhandlefrombinding);
4350
4351 // Extract information from the intrinsic call.
4352 Register MainHandleReg = Intr.getOperand(2).getReg();
4353 auto *MainHandleDef = cast<GIntrinsic>(getVRegDef(*MRI, MainHandleReg));
4354 assert(MainHandleDef->getIntrinsicID() ==
4355 Intrinsic::spv_resource_handlefrombinding);
4356
4357 uint32_t Set = getIConstVal(Intr.getOperand(4).getReg(), MRI);
4358 uint32_t Binding = getIConstVal(Intr.getOperand(3).getReg(), MRI);
4359 uint32_t ArraySize = getIConstVal(MainHandleDef->getOperand(4).getReg(), MRI);
4360 Register IndexReg = MainHandleDef->getOperand(5).getReg();
4361 std::string CounterName =
4362 getStringValueFromReg(MainHandleDef->getOperand(6).getReg(), *MRI) +
4363 ".counter";
4364
4365 // Create the counter variable.
4366 MachineIRBuilder MIRBuilder(I);
4367 Register CounterVarReg =
4368 buildPointerToResource(SPIRVTypeInst(GR.getPointeeType(ResType)),
4369 GR.getPointerStorageClass(ResType), Set, Binding,
4370 ArraySize, IndexReg, CounterName, MIRBuilder);
4371
4372 return BuildCOPY(ResVReg, CounterVarReg, I);
4373}
4374
4375bool SPIRVInstructionSelector::selectUpdateCounter(Register &ResVReg,
4376 SPIRVTypeInst ResType,
4377 MachineInstr &I) const {
4378 auto &Intr = cast<GIntrinsic>(I);
4379 assert(Intr.getIntrinsicID() == Intrinsic::spv_resource_updatecounter);
4380
4381 Register CounterHandleReg = Intr.getOperand(2).getReg();
4382 Register IncrReg = Intr.getOperand(3).getReg();
4383
4384 // The counter handle is a pointer to the counter variable (which is a struct
4385 // containing an i32). We need to get a pointer to that i32 member to do the
4386 // atomic operation.
4387#ifndef NDEBUG
4388 SPIRVTypeInst CounterVarType = GR.getSPIRVTypeForVReg(CounterHandleReg);
4389 SPIRVTypeInst CounterVarPointeeType = GR.getPointeeType(CounterVarType);
4390 assert(CounterVarPointeeType &&
4391 CounterVarPointeeType->getOpcode() == SPIRV::OpTypeStruct &&
4392 "Counter variable must be a struct");
4393 assert(GR.getPointerStorageClass(CounterVarType) ==
4394 SPIRV::StorageClass::StorageBuffer &&
4395 "Counter variable must be in the storage buffer storage class");
4396 assert(CounterVarPointeeType->getNumOperands() == 2 &&
4397 "Counter variable must have exactly 1 member in the struct");
4398 const SPIRVTypeInst MemberType =
4399 GR.getSPIRVTypeForVReg(CounterVarPointeeType->getOperand(1).getReg());
4400 assert(MemberType->getOpcode() == SPIRV::OpTypeInt &&
4401 "Counter variable struct must have a single i32 member");
4402#endif
4403
4404 // The struct has a single i32 member.
4405 MachineIRBuilder MIRBuilder(I);
4406 const Type *LLVMIntType =
4407 Type::getInt32Ty(I.getMF()->getFunction().getContext());
4408
4409 SPIRVTypeInst IntPtrType = GR.getOrCreateSPIRVPointerType(
4410 LLVMIntType, MIRBuilder, SPIRV::StorageClass::StorageBuffer);
4411
4412 Register Zero = buildI32Constant(0, I);
4413
4414 Register PtrToCounter =
4415 MRI->createVirtualRegister(GR.getRegClass(IntPtrType));
4416 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain))
4417 .addDef(PtrToCounter)
4418 .addUse(GR.getSPIRVTypeID(IntPtrType))
4419 .addUse(CounterHandleReg)
4420 .addUse(Zero)
4421 .constrainAllUses(TII, TRI, RBI);
4422
4423 // For UAV/SSBO counters, the scope is Device. The counter variable is not
4424 // used as a flag. So the memory semantics can be None.
4425 Register Scope = buildI32Constant(SPIRV::Scope::Device, I);
4426 Register Semantics = buildI32Constant(SPIRV::MemorySemantics::None, I);
4427
4428 int64_t IncrVal = getIConstValSext(IncrReg, MRI);
4429 Register Incr = buildI32Constant(static_cast<uint32_t>(IncrVal), I);
4430
4431 Register AtomicRes = MRI->createVirtualRegister(GR.getRegClass(ResType));
4432 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAtomicIAdd))
4433 .addDef(AtomicRes)
4434 .addUse(GR.getSPIRVTypeID(ResType))
4435 .addUse(PtrToCounter)
4436 .addUse(Scope)
4437 .addUse(Semantics)
4438 .addUse(Incr)
4439 .constrainAllUses(TII, TRI, RBI);
4440 if (IncrVal >= 0) {
4441 return BuildCOPY(ResVReg, AtomicRes, I);
4442 }
4443
4444 // In HLSL, IncrementCounter returns the value *before* the increment, while
4445 // DecrementCounter returns the value *after* the decrement. Both are lowered
4446 // to the same atomic intrinsic which returns the value *before* the
4447 // operation. So for decrements (negative IncrVal), we must subtract the
4448 // increment value from the result to get the post-decrement value.
4449 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
4450 .addDef(ResVReg)
4451 .addUse(GR.getSPIRVTypeID(ResType))
4452 .addUse(AtomicRes)
4453 .addUse(Incr)
4454 .constrainAllUses(TII, TRI, RBI);
4455 return true;
4456}
4457bool SPIRVInstructionSelector::selectReadImageIntrinsic(Register &ResVReg,
4458 SPIRVTypeInst ResType,
4459 MachineInstr &I) const {
4460
4461 // If the load of the image is in a different basic block, then
4462 // this will generate invalid code. A proper solution is to move
4463 // the OpLoad from selectHandleFromBinding here. However, to do
4464 // that we will need to change the return type of the intrinsic.
4465 // We will do that when we can, but for now trying to move forward with other
4466 // issues.
4467 Register ImageReg = I.getOperand(2).getReg();
4468 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
4469 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
4470 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
4471 *ImageDef, I)) {
4472 return false;
4473 }
4474
4475 Register IdxReg = I.getOperand(3).getReg();
4476 DebugLoc Loc = I.getDebugLoc();
4477 MachineInstr &Pos = I;
4478
4479 return generateImageReadOrFetch(ResVReg, ResType, NewImageReg, IdxReg, Loc,
4480 Pos);
4481}
4482
4483bool SPIRVInstructionSelector::generateSampleImage(
4484 Register ResVReg, SPIRVTypeInst ResType, Register ImageReg,
4485 Register SamplerReg, Register CoordinateReg, const ImageOperands &ImOps,
4486 DebugLoc Loc, MachineInstr &Pos) const {
4487 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
4488 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
4489 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
4490 *ImageDef, Pos)) {
4491 return false;
4492 }
4493
4494 auto *SamplerDef = cast<GIntrinsic>(getVRegDef(*MRI, SamplerReg));
4495 Register NewSamplerReg =
4496 MRI->createVirtualRegister(MRI->getRegClass(SamplerReg));
4497 if (!loadHandleBeforePosition(NewSamplerReg,
4498 GR.getSPIRVTypeForVReg(SamplerReg), *SamplerDef,
4499 Pos)) {
4500 return false;
4501 }
4502
4503 MachineIRBuilder MIRBuilder(Pos);
4504 SPIRVTypeInst SampledImageType = GR.getOrCreateOpTypeSampledImage(
4505 GR.getSPIRVTypeForVReg(ImageReg), MIRBuilder);
4506 Register SampledImageReg =
4507 MRI->createVirtualRegister(GR.getRegClass(SampledImageType));
4508
4509 BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpSampledImage))
4510 .addDef(SampledImageReg)
4511 .addUse(GR.getSPIRVTypeID(SampledImageType))
4512 .addUse(NewImageReg)
4513 .addUse(NewSamplerReg)
4514 .constrainAllUses(TII, TRI, RBI);
4515
4516 bool IsExplicitLod = ImOps.GradX.has_value() || ImOps.GradY.has_value() ||
4517 ImOps.Lod.has_value();
4518 unsigned Opcode = IsExplicitLod ? SPIRV::OpImageSampleExplicitLod
4519 : SPIRV::OpImageSampleImplicitLod;
4520 if (ImOps.Compare)
4521 Opcode = IsExplicitLod ? SPIRV::OpImageSampleDrefExplicitLod
4522 : SPIRV::OpImageSampleDrefImplicitLod;
4523
4524 auto MIB = BuildMI(*Pos.getParent(), Pos, Loc, TII.get(Opcode))
4525 .addDef(ResVReg)
4526 .addUse(GR.getSPIRVTypeID(ResType))
4527 .addUse(SampledImageReg)
4528 .addUse(CoordinateReg);
4529
4530 if (ImOps.Compare)
4531 MIB.addUse(*ImOps.Compare);
4532
4533 uint32_t ImageOperands = 0;
4534 if (ImOps.Bias)
4535 ImageOperands |= SPIRV::ImageOperand::Bias;
4536 if (ImOps.Lod)
4537 ImageOperands |= SPIRV::ImageOperand::Lod;
4538 if (ImOps.GradX && ImOps.GradY)
4539 ImageOperands |= SPIRV::ImageOperand::Grad;
4540 if (ImOps.Offset && !isScalarOrVectorIntConstantZero(*ImOps.Offset)) {
4541 if (isConstReg(MRI, *ImOps.Offset))
4542 ImageOperands |= SPIRV::ImageOperand::ConstOffset;
4543 else {
4544 Pos.emitGenericError(
4545 "Non-constant offsets are not supported in sample instructions.");
4546 }
4547 }
4548 if (ImOps.MinLod)
4549 ImageOperands |= SPIRV::ImageOperand::MinLod;
4550
4551 if (ImageOperands != 0) {
4552 MIB.addImm(ImageOperands);
4553 if (ImageOperands & SPIRV::ImageOperand::Bias)
4554 MIB.addUse(*ImOps.Bias);
4555 if (ImageOperands & SPIRV::ImageOperand::Lod)
4556 MIB.addUse(*ImOps.Lod);
4557 if (ImageOperands & SPIRV::ImageOperand::Grad) {
4558 MIB.addUse(*ImOps.GradX);
4559 MIB.addUse(*ImOps.GradY);
4560 }
4561 if (ImageOperands &
4562 (SPIRV::ImageOperand::ConstOffset | SPIRV::ImageOperand::Offset))
4563 MIB.addUse(*ImOps.Offset);
4564 if (ImageOperands & SPIRV::ImageOperand::MinLod)
4565 MIB.addUse(*ImOps.MinLod);
4566 }
4567
4568 MIB.constrainAllUses(TII, TRI, RBI);
4569 return true;
4570}
4571
4572bool SPIRVInstructionSelector::selectSampleBasicIntrinsic(
4573 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4574 Register ImageReg = I.getOperand(2).getReg();
4575 Register SamplerReg = I.getOperand(3).getReg();
4576 Register CoordinateReg = I.getOperand(4).getReg();
4577 ImageOperands ImOps;
4578 if (I.getNumOperands() > 5)
4579 ImOps.Offset = I.getOperand(5).getReg();
4580 if (I.getNumOperands() > 6)
4581 ImOps.MinLod = I.getOperand(6).getReg();
4582 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4583 CoordinateReg, ImOps, I.getDebugLoc(), I);
4584}
4585
4586bool SPIRVInstructionSelector::selectSampleBiasIntrinsic(
4587 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4588 Register ImageReg = I.getOperand(2).getReg();
4589 Register SamplerReg = I.getOperand(3).getReg();
4590 Register CoordinateReg = I.getOperand(4).getReg();
4591 ImageOperands ImOps;
4592 ImOps.Bias = I.getOperand(5).getReg();
4593 if (I.getNumOperands() > 6)
4594 ImOps.Offset = I.getOperand(6).getReg();
4595 if (I.getNumOperands() > 7)
4596 ImOps.MinLod = I.getOperand(7).getReg();
4597 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4598 CoordinateReg, ImOps, I.getDebugLoc(), I);
4599}
4600
4601bool SPIRVInstructionSelector::selectSampleGradIntrinsic(
4602 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4603 Register ImageReg = I.getOperand(2).getReg();
4604 Register SamplerReg = I.getOperand(3).getReg();
4605 Register CoordinateReg = I.getOperand(4).getReg();
4606 ImageOperands ImOps;
4607 ImOps.GradX = I.getOperand(5).getReg();
4608 ImOps.GradY = I.getOperand(6).getReg();
4609 if (I.getNumOperands() > 7)
4610 ImOps.Offset = I.getOperand(7).getReg();
4611 if (I.getNumOperands() > 8)
4612 ImOps.MinLod = I.getOperand(8).getReg();
4613 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4614 CoordinateReg, ImOps, I.getDebugLoc(), I);
4615}
4616
4617bool SPIRVInstructionSelector::selectSampleLevelIntrinsic(
4618 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4619 Register ImageReg = I.getOperand(2).getReg();
4620 Register SamplerReg = I.getOperand(3).getReg();
4621 Register CoordinateReg = I.getOperand(4).getReg();
4622 ImageOperands ImOps;
4623 ImOps.Lod = I.getOperand(5).getReg();
4624 if (I.getNumOperands() > 6)
4625 ImOps.Offset = I.getOperand(6).getReg();
4626 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4627 CoordinateReg, ImOps, I.getDebugLoc(), I);
4628}
4629
4630bool SPIRVInstructionSelector::selectSampleCmpIntrinsic(Register &ResVReg,
4631 SPIRVTypeInst ResType,
4632 MachineInstr &I) const {
4633 Register ImageReg = I.getOperand(2).getReg();
4634 Register SamplerReg = I.getOperand(3).getReg();
4635 Register CoordinateReg = I.getOperand(4).getReg();
4636 ImageOperands ImOps;
4637 ImOps.Compare = I.getOperand(5).getReg();
4638 if (I.getNumOperands() > 6)
4639 ImOps.Offset = I.getOperand(6).getReg();
4640 if (I.getNumOperands() > 7)
4641 ImOps.MinLod = I.getOperand(7).getReg();
4642 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4643 CoordinateReg, ImOps, I.getDebugLoc(), I);
4644}
4645
4646bool SPIRVInstructionSelector::selectSampleCmpLevelZeroIntrinsic(
4647 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4648 Register ImageReg = I.getOperand(2).getReg();
4649 Register SamplerReg = I.getOperand(3).getReg();
4650 Register CoordinateReg = I.getOperand(4).getReg();
4651 ImageOperands ImOps;
4652 ImOps.Compare = I.getOperand(5).getReg();
4653 if (I.getNumOperands() > 6)
4654 ImOps.Offset = I.getOperand(6).getReg();
4655 SPIRVTypeInst FloatTy = GR.getOrCreateSPIRVFloatType(32, I, TII);
4656 ImOps.Lod = GR.getOrCreateConstFP(APFloat(0.0f), I, FloatTy, TII);
4657 return generateSampleImage(ResVReg, ResType, ImageReg, SamplerReg,
4658 CoordinateReg, ImOps, I.getDebugLoc(), I);
4659}
4660
4661bool SPIRVInstructionSelector::selectGatherIntrinsic(Register &ResVReg,
4662 SPIRVTypeInst ResType,
4663 MachineInstr &I) const {
4664 Register ImageReg = I.getOperand(2).getReg();
4665 Register SamplerReg = I.getOperand(3).getReg();
4666 Register CoordinateReg = I.getOperand(4).getReg();
4667 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(ImageReg);
4668 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
4669 "ImageReg is not an image type.");
4670
4671 Register ComponentOrCompareReg;
4672 Register OffsetReg;
4673
4674 ComponentOrCompareReg = I.getOperand(5).getReg();
4675 OffsetReg = I.getOperand(6).getReg();
4676 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
4677 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
4678 if (!loadHandleBeforePosition(NewImageReg, ImageType, *ImageDef, I)) {
4679 return false;
4680 }
4681
4682 auto Dim = static_cast<SPIRV::Dim::Dim>(ImageType->getOperand(2).getImm());
4683 if (Dim != SPIRV::Dim::DIM_2D && Dim != SPIRV::Dim::DIM_Cube &&
4684 Dim != SPIRV::Dim::DIM_Rect) {
4685 I.emitGenericError(
4686 "Gather operations are only supported for 2D, Cube, and Rect images.");
4687 return false;
4688 }
4689
4690 auto *SamplerDef = cast<GIntrinsic>(getVRegDef(*MRI, SamplerReg));
4691 Register NewSamplerReg =
4692 MRI->createVirtualRegister(MRI->getRegClass(SamplerReg));
4693 if (!loadHandleBeforePosition(
4694 NewSamplerReg, GR.getSPIRVTypeForVReg(SamplerReg), *SamplerDef, I)) {
4695 return false;
4696 }
4697
4698 MachineIRBuilder MIRBuilder(I);
4699 SPIRVTypeInst SampledImageType =
4700 GR.getOrCreateOpTypeSampledImage(ImageType, MIRBuilder);
4701 Register SampledImageReg =
4702 MRI->createVirtualRegister(GR.getRegClass(SampledImageType));
4703
4704 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpSampledImage))
4705 .addDef(SampledImageReg)
4706 .addUse(GR.getSPIRVTypeID(SampledImageType))
4707 .addUse(NewImageReg)
4708 .addUse(NewSamplerReg)
4709 .constrainAllUses(TII, TRI, RBI);
4710
4711 auto IntrId = cast<GIntrinsic>(I).getIntrinsicID();
4712 bool IsGatherCmp = IntrId == Intrinsic::spv_resource_gather_cmp;
4713 unsigned Opcode =
4714 IsGatherCmp ? SPIRV::OpImageDrefGather : SPIRV::OpImageGather;
4715
4716 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
4717 .addDef(ResVReg)
4718 .addUse(GR.getSPIRVTypeID(ResType))
4719 .addUse(SampledImageReg)
4720 .addUse(CoordinateReg)
4721 .addUse(ComponentOrCompareReg);
4722
4723 uint32_t ImageOperands = 0;
4724 if (OffsetReg && !isScalarOrVectorIntConstantZero(OffsetReg)) {
4725 if (Dim == SPIRV::Dim::DIM_Cube) {
4726 I.emitGenericError(
4727 "Gather operations with offset are not supported for Cube images.");
4728 return false;
4729 }
4730 if (isConstReg(MRI, OffsetReg))
4731 ImageOperands |= SPIRV::ImageOperand::ConstOffset;
4732 else {
4733 ImageOperands |= SPIRV::ImageOperand::Offset;
4734 }
4735 }
4736
4737 if (ImageOperands != 0) {
4738 MIB.addImm(ImageOperands);
4739 if (ImageOperands &
4740 (SPIRV::ImageOperand::ConstOffset | SPIRV::ImageOperand::Offset))
4741 MIB.addUse(OffsetReg);
4742 }
4743
4744 MIB.constrainAllUses(TII, TRI, RBI);
4745 return true;
4746}
4747
4748bool SPIRVInstructionSelector::generateImageReadOrFetch(
4749 Register &ResVReg, SPIRVTypeInst ResType, Register ImageReg,
4750 Register IdxReg, DebugLoc Loc, MachineInstr &Pos) const {
4751 SPIRVTypeInst ImageType = GR.getSPIRVTypeForVReg(ImageReg);
4752 assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
4753 "ImageReg is not an image type.");
4754
4755 bool IsSignedInteger =
4756 sampledTypeIsSignedInteger(GR.getTypeForSPIRVType(ImageType));
4757 // Check if the "sampled" operand of the image type is 1.
4758 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpImageFetch
4759 auto SampledOp = ImageType->getOperand(6);
4760 bool IsFetch = (SampledOp.getImm() == 1);
4761
4762 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
4763 if (ResultSize == 4) {
4764 auto BMI =
4765 BuildMI(*Pos.getParent(), Pos, Loc,
4766 TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
4767 .addDef(ResVReg)
4768 .addUse(GR.getSPIRVTypeID(ResType))
4769 .addUse(ImageReg)
4770 .addUse(IdxReg);
4771
4772 if (IsSignedInteger)
4773 BMI.addImm(0x1000); // SignExtend
4774 BMI.constrainAllUses(TII, TRI, RBI);
4775 return true;
4776 }
4777
4778 SPIRVTypeInst ReadType = widenTypeToVec4(ResType, Pos);
4779 Register ReadReg = MRI->createVirtualRegister(GR.getRegClass(ReadType));
4780 auto BMI =
4781 BuildMI(*Pos.getParent(), Pos, Loc,
4782 TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
4783 .addDef(ReadReg)
4784 .addUse(GR.getSPIRVTypeID(ReadType))
4785 .addUse(ImageReg)
4786 .addUse(IdxReg);
4787 if (IsSignedInteger)
4788 BMI.addImm(0x1000); // SignExtend
4789 BMI.constrainAllUses(TII, TRI, RBI);
4790
4791 if (ResultSize == 1) {
4792 BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpCompositeExtract))
4793 .addDef(ResVReg)
4794 .addUse(GR.getSPIRVTypeID(ResType))
4795 .addUse(ReadReg)
4796 .addImm(0)
4797 .constrainAllUses(TII, TRI, RBI);
4798 return true;
4799 }
4800 return extractSubvector(ResVReg, ResType, ReadReg, Pos);
4801}
4802
4803bool SPIRVInstructionSelector::selectResourceGetPointer(Register &ResVReg,
4804 SPIRVTypeInst ResType,
4805 MachineInstr &I) const {
4806 Register ResourcePtr = I.getOperand(2).getReg();
4807 SPIRVTypeInst RegType = GR.getSPIRVTypeForVReg(ResourcePtr, I.getMF());
4808 if (RegType->getOpcode() == SPIRV::OpTypeImage) {
4809 // For texel buffers, the index into the image is part of the OpImageRead or
4810 // OpImageWrite instructions. So we will do nothing in this case. This
4811 // intrinsic will be combined with the load or store when selecting the load
4812 // or store.
4813 return true;
4814 }
4815
4816 assert(ResType->getOpcode() == SPIRV::OpTypePointer);
4817 MachineIRBuilder MIRBuilder(I);
4818
4819 Register IndexReg = I.getOperand(3).getReg();
4820 Register ZeroReg =
4821 buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I);
4822 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain))
4823 .addDef(ResVReg)
4824 .addUse(GR.getSPIRVTypeID(ResType))
4825 .addUse(ResourcePtr)
4826 .addUse(ZeroReg)
4827 .addUse(IndexReg)
4828 .constrainAllUses(TII, TRI, RBI);
4829 return true;
4830}
4831
4832bool SPIRVInstructionSelector::selectPushConstantGetPointer(
4833 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4834 MRI->replaceRegWith(ResVReg, I.getOperand(2).getReg());
4835 return true;
4836}
4837
4838bool SPIRVInstructionSelector::selectResourceNonUniformIndex(
4839 Register &ResVReg, SPIRVTypeInst ResType, MachineInstr &I) const {
4840 Register ObjReg = I.getOperand(2).getReg();
4841 if (!BuildCOPY(ResVReg, ObjReg, I))
4842 return false;
4843
4844 buildOpDecorate(ResVReg, I, TII, SPIRV::Decoration::NonUniformEXT, {});
4845 // Check for the registers that use the index marked as non-uniform
4846 // and recursively mark them as non-uniform.
4847 // Per the spec, it's necessary that the final argument used for
4848 // load/store/sample/atomic must be decorated, so we need to propagate the
4849 // decoration through access chains and copies.
4850 // https://docs.vulkan.org/samples/latest/samples/extensions/descriptor_indexing/README.html#_when_to_use_non_uniform_indexing_qualifier
4851 decorateUsesAsNonUniform(ResVReg);
4852 return true;
4853}
4854
4855void SPIRVInstructionSelector::decorateUsesAsNonUniform(
4856 Register &NonUniformReg) const {
4857 llvm::SmallVector<Register> WorkList = {NonUniformReg};
4858 while (WorkList.size() > 0) {
4859 Register CurrentReg = WorkList.back();
4860 WorkList.pop_back();
4861
4862 bool IsDecorated = false;
4863 for (MachineInstr &Use : MRI->use_instructions(CurrentReg)) {
4864 if (Use.getOpcode() == SPIRV::OpDecorate &&
4865 Use.getOperand(1).getImm() == SPIRV::Decoration::NonUniformEXT) {
4866 IsDecorated = true;
4867 continue;
4868 }
4869 // Check if the instruction has the result register and add it to the
4870 // worklist.
4871 if (Use.getOperand(0).isReg() && Use.getOperand(0).isDef()) {
4872 Register ResultReg = Use.getOperand(0).getReg();
4873 if (ResultReg == CurrentReg)
4874 continue;
4875 WorkList.push_back(ResultReg);
4876 }
4877 }
4878
4879 if (!IsDecorated) {
4880 buildOpDecorate(CurrentReg, *MRI->getVRegDef(CurrentReg), TII,
4881 SPIRV::Decoration::NonUniformEXT, {});
4882 }
4883 }
4884}
4885
4886bool SPIRVInstructionSelector::extractSubvector(
4887 Register &ResVReg, SPIRVTypeInst ResType, Register &ReadReg,
4888 MachineInstr &InsertionPoint) const {
4889 SPIRVTypeInst InputType = GR.getResultType(ReadReg);
4890 [[maybe_unused]] uint64_t InputSize =
4891 GR.getScalarOrVectorComponentCount(InputType);
4892 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
4893 assert(InputSize > 1 && "The input must be a vector.");
4894 assert(ResultSize > 1 && "The result must be a vector.");
4895 assert(ResultSize < InputSize &&
4896 "Cannot extract more element than there are in the input.");
4897 SmallVector<Register> ComponentRegisters;
4898 SPIRVTypeInst ScalarType = GR.getScalarOrVectorComponentType(ResType);
4899 const TargetRegisterClass *ScalarRegClass = GR.getRegClass(ScalarType);
4900 for (uint64_t I = 0; I < ResultSize; I++) {
4901 Register ComponentReg = MRI->createVirtualRegister(ScalarRegClass);
4902 BuildMI(*InsertionPoint.getParent(), InsertionPoint,
4903 InsertionPoint.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
4904 .addDef(ComponentReg)
4905 .addUse(ScalarType->getOperand(0).getReg())
4906 .addUse(ReadReg)
4907 .addImm(I)
4908 .constrainAllUses(TII, TRI, RBI);
4909 ComponentRegisters.emplace_back(ComponentReg);
4910 }
4911
4912 MachineInstrBuilder MIB = BuildMI(*InsertionPoint.getParent(), InsertionPoint,
4913 InsertionPoint.getDebugLoc(),
4914 TII.get(SPIRV::OpCompositeConstruct))
4915 .addDef(ResVReg)
4916 .addUse(GR.getSPIRVTypeID(ResType));
4917
4918 for (Register ComponentReg : ComponentRegisters)
4919 MIB.addUse(ComponentReg);
4920 MIB.constrainAllUses(TII, TRI, RBI);
4921 return true;
4922}
4923
4924bool SPIRVInstructionSelector::selectImageWriteIntrinsic(
4925 MachineInstr &I) const {
4926 // If the load of the image is in a different basic block, then
4927 // this will generate invalid code. A proper solution is to move
4928 // the OpLoad from selectHandleFromBinding here. However, to do
4929 // that we will need to change the return type of the intrinsic.
4930 // We will do that when we can, but for now trying to move forward with other
4931 // issues.
4932 Register ImageReg = I.getOperand(1).getReg();
4933 auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg));
4934 Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg));
4935 if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg),
4936 *ImageDef, I)) {
4937 return false;
4938 }
4939
4940 Register CoordinateReg = I.getOperand(2).getReg();
4941 Register DataReg = I.getOperand(3).getReg();
4942 assert(GR.getResultType(DataReg)->getOpcode() == SPIRV::OpTypeVector);
4944 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpImageWrite))
4945 .addUse(NewImageReg)
4946 .addUse(CoordinateReg)
4947 .addUse(DataReg)
4948 .constrainAllUses(TII, TRI, RBI);
4949 return true;
4950}
4951
4952Register SPIRVInstructionSelector::buildPointerToResource(
4953 SPIRVTypeInst SpirvResType, SPIRV::StorageClass::StorageClass SC,
4954 uint32_t Set, uint32_t Binding, uint32_t ArraySize, Register IndexReg,
4955 StringRef Name, MachineIRBuilder MIRBuilder) const {
4956 const Type *ResType = GR.getTypeForSPIRVType(SpirvResType);
4957 if (ArraySize == 1) {
4958 SPIRVTypeInst PtrType =
4959 GR.getOrCreateSPIRVPointerType(ResType, MIRBuilder, SC);
4960 assert(GR.getPointeeType(PtrType) == SpirvResType &&
4961 "SpirvResType did not have an explicit layout.");
4962 return GR.getOrCreateGlobalVariableWithBinding(PtrType, Set, Binding, Name,
4963 MIRBuilder);
4964 }
4965
4966 const Type *VarType = ArrayType::get(const_cast<Type *>(ResType), ArraySize);
4967 SPIRVTypeInst VarPointerType =
4968 GR.getOrCreateSPIRVPointerType(VarType, MIRBuilder, SC);
4970 VarPointerType, Set, Binding, Name, MIRBuilder);
4971
4972 SPIRVTypeInst ResPointerType =
4973 GR.getOrCreateSPIRVPointerType(ResType, MIRBuilder, SC);
4974 Register AcReg = MRI->createVirtualRegister(GR.getRegClass(ResPointerType));
4975
4976 MIRBuilder.buildInstr(SPIRV::OpAccessChain)
4977 .addDef(AcReg)
4978 .addUse(GR.getSPIRVTypeID(ResPointerType))
4979 .addUse(VarReg)
4980 .addUse(IndexReg);
4981
4982 return AcReg;
4983}
4984
4985bool SPIRVInstructionSelector::selectFirstBitSet16(
4986 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I,
4987 unsigned ExtendOpcode, unsigned BitSetOpcode) const {
4988 Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
4989 if (!selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()},
4990 ExtendOpcode))
4991 return false;
4992
4993 return selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode);
4994}
4995
4996bool SPIRVInstructionSelector::selectFirstBitSet32(
4997 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
4998 unsigned BitSetOpcode) const {
4999 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
5000 .addDef(ResVReg)
5001 .addUse(GR.getSPIRVTypeID(ResType))
5002 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
5003 .addImm(BitSetOpcode)
5004 .addUse(SrcReg)
5005 .constrainAllUses(TII, TRI, RBI);
5006 return true;
5007}
5008
5009bool SPIRVInstructionSelector::selectFirstBitSet64Overflow(
5010 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
5011 unsigned BitSetOpcode, bool SwapPrimarySide) const {
5012
5013 // SPIR-V allow vectors of size 2,3,4 only. Calling with a larger vectors
5014 // requires creating a param register and return register with an invalid
5015 // vector size. If that is resolved, then this function can be used for
5016 // vectors of any component size.
5017 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType);
5018 assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops");
5019
5020 MachineIRBuilder MIRBuilder(I);
5021 SPIRVTypeInst BaseType = GR.retrieveScalarOrVectorIntType(ResType);
5022 SPIRVTypeInst I64Type = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder);
5023 SPIRVTypeInst I64x2Type =
5024 GR.getOrCreateSPIRVVectorType(I64Type, 2, MIRBuilder, false);
5025 SPIRVTypeInst Vec2ResType =
5026 GR.getOrCreateSPIRVVectorType(BaseType, 2, MIRBuilder, false);
5027
5028 std::vector<Register> PartialRegs;
5029
5030 // Loops 0, 2, 4, ... but stops one loop early when ComponentCount is odd
5031 unsigned CurrentComponent = 0;
5032 for (; CurrentComponent + 1 < ComponentCount; CurrentComponent += 2) {
5033 // This register holds the firstbitX result for each of the i64x2 vectors
5034 // extracted from SrcReg
5035 Register BitSetResult =
5036 MRI->createVirtualRegister(GR.getRegClass(I64x2Type));
5037
5038 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
5039 TII.get(SPIRV::OpVectorShuffle))
5040 .addDef(BitSetResult)
5041 .addUse(GR.getSPIRVTypeID(I64x2Type))
5042 .addUse(SrcReg)
5043 .addUse(SrcReg)
5044 .addImm(CurrentComponent)
5045 .addImm(CurrentComponent + 1);
5046
5047 MIB.constrainAllUses(TII, TRI, RBI);
5048
5049 Register SubVecBitSetReg =
5050 MRI->createVirtualRegister(GR.getRegClass(Vec2ResType));
5051
5052 if (!selectFirstBitSet64(SubVecBitSetReg, Vec2ResType, I, BitSetResult,
5053 BitSetOpcode, SwapPrimarySide))
5054 return false;
5055
5056 PartialRegs.push_back(SubVecBitSetReg);
5057 }
5058
5059 // On odd component counts we need to handle one more component
5060 if (CurrentComponent != ComponentCount) {
5061 bool ZeroAsNull = !STI.isShader();
5062 Register FinalElemReg = MRI->createVirtualRegister(GR.getRegClass(I64Type));
5063 Register ConstIntLastIdx = GR.getOrCreateConstInt(
5064 ComponentCount - 1, I, BaseType, TII, ZeroAsNull);
5065
5066 if (!selectOpWithSrcs(FinalElemReg, I64Type, I, {SrcReg, ConstIntLastIdx},
5067 SPIRV::OpVectorExtractDynamic))
5068 return false;
5069
5070 Register FinalElemBitSetReg =
5071 MRI->createVirtualRegister(GR.getRegClass(BaseType));
5072
5073 if (!selectFirstBitSet64(FinalElemBitSetReg, BaseType, I, FinalElemReg,
5074 BitSetOpcode, SwapPrimarySide))
5075 return false;
5076
5077 PartialRegs.push_back(FinalElemBitSetReg);
5078 }
5079
5080 // Join all the resulting registers back into the return type in order
5081 // (ie i32x2, i32x2, i32x1 -> i32x5)
5082 return selectOpWithSrcs(ResVReg, ResType, I, std::move(PartialRegs),
5083 SPIRV::OpCompositeConstruct);
5084}
5085
5086bool SPIRVInstructionSelector::selectFirstBitSet64(
5087 Register ResVReg, SPIRVTypeInst ResType, MachineInstr &I, Register SrcReg,
5088 unsigned BitSetOpcode, bool SwapPrimarySide) const {
5089 unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType);
5090 SPIRVTypeInst BaseType = GR.retrieveScalarOrVectorIntType(ResType);
5091 bool ZeroAsNull = !STI.isShader();
5092 Register ConstIntZero =
5093 GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull);
5094 Register ConstIntOne =
5095 GR.getOrCreateConstInt(1, I, BaseType, TII, ZeroAsNull);
5096
5097 // SPIRV doesn't support vectors with more than 4 components. Since the
5098 // algoritm below converts i64 -> i32x2 and i64x4 -> i32x8 it can only
5099 // operate on vectors with 2 or less components. When largers vectors are
5100 // seen. Split them, recurse, then recombine them.
5101 if (ComponentCount > 2) {
5102 return selectFirstBitSet64Overflow(ResVReg, ResType, I, SrcReg,
5103 BitSetOpcode, SwapPrimarySide);
5104 }
5105
5106 // 1. Split int64 into 2 pieces using a bitcast
5107 MachineIRBuilder MIRBuilder(I);
5108 SPIRVTypeInst PostCastType = GR.getOrCreateSPIRVVectorType(
5109 BaseType, 2 * ComponentCount, MIRBuilder, false);
5110 Register BitcastReg =
5111 MRI->createVirtualRegister(GR.getRegClass(PostCastType));
5112
5113 if (!selectOpWithSrcs(BitcastReg, PostCastType, I, {SrcReg},
5114 SPIRV::OpBitcast))
5115 return false;
5116
5117 // 2. Find the first set bit from the primary side for all the pieces in #1
5118 Register FBSReg = MRI->createVirtualRegister(GR.getRegClass(PostCastType));
5119 if (!selectFirstBitSet32(FBSReg, PostCastType, I, BitcastReg, BitSetOpcode))
5120 return false;
5121
5122 // 3. Split result vector into high bits and low bits
5123 Register HighReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5124 Register LowReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5125
5126 bool IsScalarRes = ResType->getOpcode() != SPIRV::OpTypeVector;
5127 if (IsScalarRes) {
5128 // if scalar do a vector extract
5129 if (!selectOpWithSrcs(HighReg, ResType, I, {FBSReg, ConstIntZero},
5130 SPIRV::OpVectorExtractDynamic))
5131 return false;
5132 if (!selectOpWithSrcs(LowReg, ResType, I, {FBSReg, ConstIntOne},
5133 SPIRV::OpVectorExtractDynamic))
5134 return false;
5135 } else {
5136 // if vector do a shufflevector
5137 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
5138 TII.get(SPIRV::OpVectorShuffle))
5139 .addDef(HighReg)
5140 .addUse(GR.getSPIRVTypeID(ResType))
5141 .addUse(FBSReg)
5142 // Per the spec, repeat the vector if only one vec is needed
5143 .addUse(FBSReg);
5144
5145 // high bits are stored in even indexes. Extract them from FBSReg
5146 for (unsigned J = 0; J < ComponentCount * 2; J += 2) {
5147 MIB.addImm(J);
5148 }
5149
5150 MIB.constrainAllUses(TII, TRI, RBI);
5151
5152 MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
5153 TII.get(SPIRV::OpVectorShuffle))
5154 .addDef(LowReg)
5155 .addUse(GR.getSPIRVTypeID(ResType))
5156 .addUse(FBSReg)
5157 // Per the spec, repeat the vector if only one vec is needed
5158 .addUse(FBSReg);
5159
5160 // low bits are stored in odd indexes. Extract them from FBSReg
5161 for (unsigned J = 1; J < ComponentCount * 2; J += 2) {
5162 MIB.addImm(J);
5163 }
5164 MIB.constrainAllUses(TII, TRI, RBI);
5165 }
5166
5167 // 4. Check the result. When primary bits == -1 use secondary, otherwise use
5168 // primary
5169 SPIRVTypeInst BoolType = GR.getOrCreateSPIRVBoolType(I, TII);
5170 Register NegOneReg;
5171 Register Reg0;
5172 Register Reg32;
5173 unsigned SelectOp;
5174 unsigned AddOp;
5175
5176 if (IsScalarRes) {
5177 NegOneReg =
5178 GR.getOrCreateConstInt((unsigned)-1, I, ResType, TII, ZeroAsNull);
5179 Reg0 = GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
5180 Reg32 = GR.getOrCreateConstInt(32, I, ResType, TII, ZeroAsNull);
5181 SelectOp = SPIRV::OpSelectSISCond;
5182 AddOp = SPIRV::OpIAddS;
5183 } else {
5184 BoolType = GR.getOrCreateSPIRVVectorType(BoolType, ComponentCount,
5185 MIRBuilder, false);
5186 NegOneReg =
5187 GR.getOrCreateConstVector((unsigned)-1, I, ResType, TII, ZeroAsNull);
5188 Reg0 = GR.getOrCreateConstVector(0, I, ResType, TII, ZeroAsNull);
5189 Reg32 = GR.getOrCreateConstVector(32, I, ResType, TII, ZeroAsNull);
5190 SelectOp = SPIRV::OpSelectVIVCond;
5191 AddOp = SPIRV::OpIAddV;
5192 }
5193
5194 Register PrimaryReg = HighReg;
5195 Register SecondaryReg = LowReg;
5196 Register PrimaryShiftReg = Reg32;
5197 Register SecondaryShiftReg = Reg0;
5198
5199 // By default the emitted opcodes check for the set bit from the MSB side.
5200 // Setting SwapPrimarySide checks the set bit from the LSB side
5201 if (SwapPrimarySide) {
5202 PrimaryReg = LowReg;
5203 SecondaryReg = HighReg;
5204 PrimaryShiftReg = Reg0;
5205 SecondaryShiftReg = Reg32;
5206 }
5207
5208 // Check if the primary bits are == -1
5209 Register BReg = MRI->createVirtualRegister(GR.getRegClass(BoolType));
5210 if (!selectOpWithSrcs(BReg, BoolType, I, {PrimaryReg, NegOneReg},
5211 SPIRV::OpIEqual))
5212 return false;
5213
5214 // Select secondary bits if true in BReg, otherwise primary bits
5215 Register TmpReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5216 if (!selectOpWithSrcs(TmpReg, ResType, I, {BReg, SecondaryReg, PrimaryReg},
5217 SelectOp))
5218 return false;
5219
5220 // 5. Add 32 when high bits are used, otherwise 0 for low bits
5221 Register ValReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5222 if (!selectOpWithSrcs(ValReg, ResType, I,
5223 {BReg, SecondaryShiftReg, PrimaryShiftReg}, SelectOp))
5224 return false;
5225
5226 return selectOpWithSrcs(ResVReg, ResType, I, {ValReg, TmpReg}, AddOp);
5227}
5228
5229bool SPIRVInstructionSelector::selectFirstBitHigh(Register ResVReg,
5230 SPIRVTypeInst ResType,
5231 MachineInstr &I,
5232 bool IsSigned) const {
5233 // FindUMsb and FindSMsb intrinsics only support 32 bit integers
5234 Register OpReg = I.getOperand(2).getReg();
5235 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
5236 // zero or sign extend
5237 unsigned ExtendOpcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
5238 unsigned BitSetOpcode = IsSigned ? GL::FindSMsb : GL::FindUMsb;
5239
5240 switch (GR.getScalarOrVectorBitWidth(OpType)) {
5241 case 16:
5242 return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode);
5243 case 32:
5244 return selectFirstBitSet32(ResVReg, ResType, I, OpReg, BitSetOpcode);
5245 case 64:
5246 return selectFirstBitSet64(ResVReg, ResType, I, OpReg, BitSetOpcode,
5247 /*SwapPrimarySide=*/false);
5248 default:
5250 "spv_firstbituhigh and spv_firstbitshigh only support 16,32,64 bits.");
5251 }
5252}
5253
5254bool SPIRVInstructionSelector::selectFirstBitLow(Register ResVReg,
5255 SPIRVTypeInst ResType,
5256 MachineInstr &I) const {
5257 // FindILsb intrinsic only supports 32 bit integers
5258 Register OpReg = I.getOperand(2).getReg();
5259 SPIRVTypeInst OpType = GR.getSPIRVTypeForVReg(OpReg);
5260 // OpUConvert treats the operand bits as an unsigned i16 and zero extends it
5261 // to an unsigned i32. As this leaves all the least significant bits unchanged
5262 // so the first set bit from the LSB side doesn't change.
5263 unsigned ExtendOpcode = SPIRV::OpUConvert;
5264 unsigned BitSetOpcode = GL::FindILsb;
5265
5266 switch (GR.getScalarOrVectorBitWidth(OpType)) {
5267 case 16:
5268 return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode);
5269 case 32:
5270 return selectFirstBitSet32(ResVReg, ResType, I, OpReg, BitSetOpcode);
5271 case 64:
5272 return selectFirstBitSet64(ResVReg, ResType, I, OpReg, BitSetOpcode,
5273 /*SwapPrimarySide=*/true);
5274 default:
5275 report_fatal_error("spv_firstbitlow only supports 16,32,64 bits.");
5276 }
5277}
5278
5279bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg,
5280 SPIRVTypeInst ResType,
5281 MachineInstr &I) const {
5282 // there was an allocation size parameter to the allocation instruction
5283 // that is not 1
5284 MachineBasicBlock &BB = *I.getParent();
5285 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVariableLengthArrayINTEL))
5286 .addDef(ResVReg)
5287 .addUse(GR.getSPIRVTypeID(ResType))
5288 .addUse(I.getOperand(2).getReg())
5289 .constrainAllUses(TII, TRI, RBI);
5290 if (!STI.isShader()) {
5291 unsigned Alignment = I.getOperand(3).getImm();
5292 buildOpDecorate(ResVReg, I, TII, SPIRV::Decoration::Alignment, {Alignment});
5293 }
5294 return true;
5295}
5296
5297bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg,
5298 SPIRVTypeInst ResType,
5299 MachineInstr &I) const {
5300 // Change order of instructions if needed: all OpVariable instructions in a
5301 // function must be the first instructions in the first block
5302 auto It = getOpVariableMBBIt(I);
5303 BuildMI(*It->getParent(), It, It->getDebugLoc(), TII.get(SPIRV::OpVariable))
5304 .addDef(ResVReg)
5305 .addUse(GR.getSPIRVTypeID(ResType))
5306 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
5307 .constrainAllUses(TII, TRI, RBI);
5308 if (!STI.isShader()) {
5309 unsigned Alignment = I.getOperand(2).getImm();
5310 buildOpDecorate(ResVReg, *It, TII, SPIRV::Decoration::Alignment,
5311 {Alignment});
5312 }
5313 return true;
5314}
5315
5316bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const {
5317 // InstructionSelector walks backwards through the instructions. We can use
5318 // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
5319 // first, so can generate an OpBranchConditional here. If there is no
5320 // G_BRCOND, we just use OpBranch for a regular unconditional branch.
5321 const MachineInstr *PrevI = I.getPrevNode();
5322 MachineBasicBlock &MBB = *I.getParent();
5323 if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) {
5324 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
5325 .addUse(PrevI->getOperand(0).getReg())
5326 .addMBB(PrevI->getOperand(1).getMBB())
5327 .addMBB(I.getOperand(0).getMBB())
5328 .constrainAllUses(TII, TRI, RBI);
5329 return true;
5330 }
5331 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch))
5332 .addMBB(I.getOperand(0).getMBB())
5333 .constrainAllUses(TII, TRI, RBI);
5334 return true;
5335}
5336
5337bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const {
5338 // InstructionSelector walks backwards through the instructions. For an
5339 // explicit conditional branch with no fallthrough, we use both a G_BR and a
5340 // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
5341 // generate the OpBranchConditional in selectBranch above.
5342 //
5343 // If an OpBranchConditional has been generated, we simply return, as the work
5344 // is alread done. If there is no OpBranchConditional, LLVM must be relying on
5345 // implicit fallthrough to the next basic block, so we need to create an
5346 // OpBranchConditional with an explicit "false" argument pointing to the next
5347 // basic block that LLVM would fall through to.
5348 const MachineInstr *NextI = I.getNextNode();
5349 // Check if this has already been successfully selected.
5350 if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional)
5351 return true;
5352 // Must be relying on implicit block fallthrough, so generate an
5353 // OpBranchConditional with the "next" basic block as the "false" target.
5354 MachineBasicBlock &MBB = *I.getParent();
5355 unsigned NextMBBNum = MBB.getNextNode()->getNumber();
5356 MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum);
5357 BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
5358 .addUse(I.getOperand(0).getReg())
5359 .addMBB(I.getOperand(1).getMBB())
5360 .addMBB(NextMBB)
5361 .constrainAllUses(TII, TRI, RBI);
5362 return true;
5363}
5364
5365bool SPIRVInstructionSelector::selectPhi(Register ResVReg,
5366 MachineInstr &I) const {
5367 auto MIB =
5368 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::PHI))
5369 .addDef(ResVReg);
5370 const unsigned NumOps = I.getNumOperands();
5371 for (unsigned i = 1; i < NumOps; i += 2) {
5372 MIB.addUse(I.getOperand(i + 0).getReg());
5373 MIB.addMBB(I.getOperand(i + 1).getMBB());
5374 }
5375 MIB.constrainAllUses(TII, TRI, RBI);
5376 return true;
5377}
5378
5379bool SPIRVInstructionSelector::selectGlobalValue(
5380 Register ResVReg, MachineInstr &I, const MachineInstr *Init) const {
5381 // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
5382 MachineIRBuilder MIRBuilder(I);
5383 const GlobalValue *GV = I.getOperand(1).getGlobal();
5385
5386 std::string GlobalIdent;
5387 if (!GV->hasName()) {
5388 unsigned &ID = UnnamedGlobalIDs[GV];
5389 if (ID == 0)
5390 ID = UnnamedGlobalIDs.size();
5391 GlobalIdent = "__unnamed_" + Twine(ID).str();
5392 } else {
5393 GlobalIdent = GV->getName();
5394 }
5395
5396 // Behaviour of functions as operands depends on availability of the
5397 // corresponding extension (SPV_INTEL_function_pointers):
5398 // - If there is an extension to operate with functions as operands:
5399 // We create a proper constant operand and evaluate a correct type for a
5400 // function pointer.
5401 // - Without the required extension:
5402 // We have functions as operands in tests with blocks of instruction e.g. in
5403 // transcoding/global_block.ll. These operands are not used and should be
5404 // substituted by zero constants. Their type is expected to be always
5405 // OpTypePointer Function %uchar.
5406 if (isa<Function>(GV)) {
5407 const Constant *ConstVal = GV;
5408 MachineBasicBlock &BB = *I.getParent();
5409 Register NewReg = GR.find(ConstVal, GR.CurMF);
5410 if (!NewReg.isValid()) {
5411 const Function *GVFun =
5412 STI.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
5413 ? dyn_cast<Function>(GV)
5414 : nullptr;
5415 SPIRVTypeInst ResType = GR.getOrCreateSPIRVPointerType(
5416 GVType, I,
5417 GVFun ? SPIRV::StorageClass::CodeSectionINTEL
5419 if (GVFun) {
5420 // References to a function via function pointers generate virtual
5421 // registers without a definition. We will resolve it later, during
5422 // module analysis stage.
5423 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
5424 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
5425 Register FuncVReg =
5426 MRI->createGenericVirtualRegister(GR.getRegType(ResType));
5427 MRI->setRegClass(FuncVReg, &SPIRV::pIDRegClass);
5428 GR.assignSPIRVTypeToVReg(ResType, FuncVReg, *GR.CurMF);
5429 MachineInstrBuilder MIB1 =
5430 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
5431 .addDef(FuncVReg)
5432 .addUse(ResTypeReg);
5433 MachineInstrBuilder MIB2 =
5434 BuildMI(BB, I, I.getDebugLoc(),
5435 TII.get(SPIRV::OpConstantFunctionPointerINTEL))
5436 .addDef(ResVReg)
5437 .addUse(ResTypeReg)
5438 .addUse(FuncVReg);
5439 GR.add(ConstVal, MIB2);
5440 // mapping the function pointer to the used Function
5441 GR.recordFunctionPointer(&MIB2.getInstr()->getOperand(2), GVFun);
5442 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF);
5443 MIB1.constrainAllUses(TII, TRI, RBI);
5444 MIB2.constrainAllUses(TII, TRI, RBI);
5445 return true;
5446 }
5447 MachineInstrBuilder MIB3 =
5448 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
5449 .addDef(ResVReg)
5450 .addUse(GR.getSPIRVTypeID(ResType));
5451 GR.add(ConstVal, MIB3);
5452 MIB3.constrainAllUses(TII, TRI, RBI);
5453 return true;
5454 }
5455 assert(NewReg != ResVReg);
5456 return BuildCOPY(ResVReg, NewReg, I);
5457 }
5459 assert(GlobalVar->getName() != "llvm.global.annotations");
5460
5461 // Skip empty declaration for GVs with initializers till we get the decl with
5462 // passed initializer.
5463 if (hasInitializer(GlobalVar) && !Init)
5464 return true;
5465
5466 const std::optional<SPIRV::LinkageType::LinkageType> LnkType =
5467 getSpirvLinkageTypeFor(STI, *GV);
5468
5469 const unsigned AddrSpace = GV->getAddressSpace();
5470 SPIRV::StorageClass::StorageClass StorageClass =
5471 addressSpaceToStorageClass(AddrSpace, STI);
5472 SPIRVTypeInst ResType =
5475 ResVReg, ResType, GlobalIdent, GV, StorageClass, Init,
5476 GlobalVar->isConstant(), LnkType, MIRBuilder, true);
5477 // TODO: For AMDGCN, we pipe externally_initialized through via
5478 // HostAccessINTEL, with ReadWrite (3) access, which is we then handle during
5479 // reverse translation. We should remove this once SPIR-V gains the ability to
5480 // express the concept.
5481 if (GlobalVar->isExternallyInitialized() &&
5482 STI.getTargetTriple().getVendor() == Triple::AMD) {
5483 constexpr unsigned ReadWriteINTEL = 3u;
5484 buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::HostAccessINTEL,
5485 {ReadWriteINTEL});
5486 MachineInstrBuilder MIB(*MF, --MIRBuilder.getInsertPt());
5487 addStringImm(GV->getName(), MIB);
5488 }
5489 return Reg.isValid();
5490}
5491
5492bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
5493 SPIRVTypeInst ResType,
5494 MachineInstr &I) const {
5495 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
5496 return selectExtInst(ResVReg, ResType, I, CL::log10);
5497 }
5498
5499 // There is no log10 instruction in the GLSL Extended Instruction set, so it
5500 // is implemented as:
5501 // log10(x) = log2(x) * (1 / log2(10))
5502 // = log2(x) * 0.30103
5503
5504 MachineIRBuilder MIRBuilder(I);
5505 MachineBasicBlock &BB = *I.getParent();
5506
5507 // Build log2(x).
5508 Register VarReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
5509 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
5510 .addDef(VarReg)
5511 .addUse(GR.getSPIRVTypeID(ResType))
5512 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
5513 .addImm(GL::Log2)
5514 .add(I.getOperand(1))
5515 .constrainAllUses(TII, TRI, RBI);
5516
5517 // Build 0.30103.
5518 assert(ResType->getOpcode() == SPIRV::OpTypeVector ||
5519 ResType->getOpcode() == SPIRV::OpTypeFloat);
5520 // TODO: Add matrix implementation once supported by the HLSL frontend.
5521 SPIRVTypeInst SpirvScalarType = ResType->getOpcode() == SPIRV::OpTypeVector
5522 ? SPIRVTypeInst(GR.getSPIRVTypeForVReg(
5523 ResType->getOperand(1).getReg()))
5524 : ResType;
5525 Register ScaleReg =
5526 GR.buildConstantFP(APFloat(0.30103f), MIRBuilder, SpirvScalarType);
5527
5528 // Multiply log2(x) by 0.30103 to get log10(x) result.
5529 auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector
5530 ? SPIRV::OpVectorTimesScalar
5531 : SPIRV::OpFMulS;
5532 BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
5533 .addDef(ResVReg)
5534 .addUse(GR.getSPIRVTypeID(ResType))
5535 .addUse(VarReg)
5536 .addUse(ScaleReg)
5537 .constrainAllUses(TII, TRI, RBI);
5538 return true;
5539}
5540
5541bool SPIRVInstructionSelector::selectModf(Register ResVReg,
5542 SPIRVTypeInst ResType,
5543 MachineInstr &I) const {
5544 // llvm.modf has a single arg --the number to be decomposed-- and returns a
5545 // struct { restype, restype }, while OpenCLLIB::modf has two args --the
5546 // number to be decomposed and a pointer--, returns the fractional part and
5547 // the integral part is stored in the pointer argument. Therefore, we can't
5548 // use directly the OpenCLLIB::modf intrinsic. However, we can do some
5549 // scaffolding to make it work. The idea is to create an alloca instruction
5550 // to get a ptr, pass this ptr to OpenCL::modf, and then load the value
5551 // from this ptr to place it in the struct. llvm.modf returns the fractional
5552 // part as the first element of the result, and the integral part as the
5553 // second element of the result.
5554
5555 // At this point, the return type is not a struct anymore, but rather two
5556 // independent elements of SPIRVResType. We can get each independent element
5557 // from I.getDefs() or I.getOperands().
5558 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
5559 MachineIRBuilder MIRBuilder(I);
5560 // Get pointer type for alloca variable.
5561 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
5562 ResType, MIRBuilder, SPIRV::StorageClass::Function);
5563 // Create new register for the pointer type of alloca variable.
5564 Register PtrTyReg =
5565 MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
5566 MIRBuilder.getMRI()->setType(
5567 PtrTyReg,
5568 LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Function),
5569 GR.getPointerSize()));
5570
5571 // Assign SPIR-V type of the pointer type of the alloca variable to the
5572 // new register.
5573 GR.assignSPIRVTypeToVReg(PtrType, PtrTyReg, MIRBuilder.getMF());
5574 MachineBasicBlock &EntryBB = I.getMF()->front();
5577 auto AllocaMIB =
5578 BuildMI(EntryBB, VarPos, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
5579 .addDef(PtrTyReg)
5580 .addUse(GR.getSPIRVTypeID(PtrType))
5581 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function));
5582 Register Variable = AllocaMIB->getOperand(0).getReg();
5583
5584 MachineBasicBlock &BB = *I.getParent();
5585 // Create the OpenCLLIB::modf instruction.
5586 auto MIB =
5587 BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
5588 .addDef(ResVReg)
5589 .addUse(GR.getSPIRVTypeID(ResType))
5590 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
5591 .addImm(CL::modf)
5592 .setMIFlags(I.getFlags())
5593 .add(I.getOperand(I.getNumExplicitDefs())) // Floating point value.
5594 .addUse(Variable); // Pointer to integral part.
5595 // Assign the integral part stored in the ptr to the second element of the
5596 // result.
5597 Register IntegralPartReg = I.getOperand(1).getReg();
5598 if (IntegralPartReg.isValid()) {
5599 // Load the value from the pointer to integral part.
5600 auto LoadMIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
5601 .addDef(IntegralPartReg)
5602 .addUse(GR.getSPIRVTypeID(ResType))
5603 .addUse(Variable);
5604 LoadMIB.constrainAllUses(TII, TRI, RBI);
5605 return true;
5606 }
5607
5608 MIB.constrainAllUses(TII, TRI, RBI);
5609 return true;
5610 } else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
5611 assert(false && "GLSL::Modf is deprecated.");
5612 // FIXME: GL::Modf is deprecated, use Modfstruct instead.
5613 return false;
5614 }
5615 return false;
5616}
5617
5618// Generate the instructions to load 3-element vector builtin input
5619// IDs/Indices.
5620// Like: GlobalInvocationId, LocalInvocationId, etc....
5621
5622bool SPIRVInstructionSelector::loadVec3BuiltinInputID(
5623 SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg,
5624 SPIRVTypeInst ResType, MachineInstr &I) const {
5625 MachineIRBuilder MIRBuilder(I);
5626 const SPIRVTypeInst Vec3Ty =
5627 GR.getOrCreateSPIRVVectorType(ResType, 3, MIRBuilder, false);
5628 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
5629 Vec3Ty, MIRBuilder, SPIRV::StorageClass::Input);
5630
5631 // Create new register for the input ID builtin variable.
5632 Register NewRegister =
5633 MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
5634 MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 64));
5635 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
5636
5637 // Build global variable with the necessary decorations for the input ID
5638 // builtin variable.
5640 NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr,
5641 SPIRV::StorageClass::Input, nullptr, true, std::nullopt, MIRBuilder,
5642 false);
5643
5644 // Create new register for loading value.
5645 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
5646 Register LoadedRegister = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
5647 MIRBuilder.getMRI()->setType(LoadedRegister, LLT::pointer(0, 64));
5648 GR.assignSPIRVTypeToVReg(Vec3Ty, LoadedRegister, MIRBuilder.getMF());
5649
5650 // Load v3uint value from the global variable.
5651 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
5652 .addDef(LoadedRegister)
5653 .addUse(GR.getSPIRVTypeID(Vec3Ty))
5654 .addUse(Variable);
5655
5656 // Get the input ID index. Expecting operand is a constant immediate value,
5657 // wrapped in a type assignment.
5658 assert(I.getOperand(2).isReg());
5659 const uint32_t ThreadId = foldImm(I.getOperand(2), MRI);
5660
5661 // Extract the input ID from the loaded vector value.
5662 MachineBasicBlock &BB = *I.getParent();
5663 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
5664 .addDef(ResVReg)
5665 .addUse(GR.getSPIRVTypeID(ResType))
5666 .addUse(LoadedRegister)
5667 .addImm(ThreadId);
5668 MIB.constrainAllUses(TII, TRI, RBI);
5669 return true;
5670}
5671
5672// Generate the instructions to load 32-bit integer builtin input IDs/Indices.
5673// Like LocalInvocationIndex
5674bool SPIRVInstructionSelector::loadBuiltinInputID(
5675 SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg,
5676 SPIRVTypeInst ResType, MachineInstr &I) const {
5677 MachineIRBuilder MIRBuilder(I);
5678 const SPIRVTypeInst PtrType = GR.getOrCreateSPIRVPointerType(
5679 ResType, MIRBuilder, SPIRV::StorageClass::Input);
5680
5681 // Create new register for the input ID builtin variable.
5682 Register NewRegister =
5683 MIRBuilder.getMRI()->createVirtualRegister(GR.getRegClass(PtrType));
5684 MIRBuilder.getMRI()->setType(
5685 NewRegister,
5686 LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Input),
5687 GR.getPointerSize()));
5688 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
5689
5690 // Build global variable with the necessary decorations for the input ID
5691 // builtin variable.
5693 NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr,
5694 SPIRV::StorageClass::Input, nullptr, true, std::nullopt, MIRBuilder,
5695 false);
5696
5697 // Load uint value from the global variable.
5698 auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
5699 .addDef(ResVReg)
5700 .addUse(GR.getSPIRVTypeID(ResType))
5701 .addUse(Variable);
5702
5703 MIB.constrainAllUses(TII, TRI, RBI);
5704 return true;
5705}
5706
5707SPIRVTypeInst SPIRVInstructionSelector::widenTypeToVec4(SPIRVTypeInst Type,
5708 MachineInstr &I) const {
5709 MachineIRBuilder MIRBuilder(I);
5710 if (Type->getOpcode() != SPIRV::OpTypeVector)
5711 return GR.getOrCreateSPIRVVectorType(Type, 4, MIRBuilder, false);
5712
5713 uint64_t VectorSize = Type->getOperand(2).getImm();
5714 if (VectorSize == 4)
5715 return Type;
5716
5717 Register ScalarTypeReg = Type->getOperand(1).getReg();
5718 const SPIRVTypeInst ScalarType = GR.getSPIRVTypeForVReg(ScalarTypeReg);
5719 return GR.getOrCreateSPIRVVectorType(ScalarType, 4, MIRBuilder, false);
5720}
5721
5722bool SPIRVInstructionSelector::loadHandleBeforePosition(
5723 Register &HandleReg, SPIRVTypeInst ResType, GIntrinsic &HandleDef,
5724 MachineInstr &Pos) const {
5725
5726 assert(HandleDef.getIntrinsicID() ==
5727 Intrinsic::spv_resource_handlefrombinding);
5728 uint32_t Set = foldImm(HandleDef.getOperand(2), MRI);
5729 uint32_t Binding = foldImm(HandleDef.getOperand(3), MRI);
5730 uint32_t ArraySize = foldImm(HandleDef.getOperand(4), MRI);
5731 Register IndexReg = HandleDef.getOperand(5).getReg();
5732 std::string Name =
5733 getStringValueFromReg(HandleDef.getOperand(6).getReg(), *MRI);
5734
5735 bool IsStructuredBuffer = ResType->getOpcode() == SPIRV::OpTypePointer;
5736 MachineIRBuilder MIRBuilder(HandleDef);
5737 SPIRVTypeInst VarType = ResType;
5738 SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::UniformConstant;
5739
5740 if (IsStructuredBuffer) {
5741 VarType = GR.getPointeeType(ResType);
5742 SC = GR.getPointerStorageClass(ResType);
5743 }
5744
5745 Register VarReg =
5746 buildPointerToResource(SPIRVTypeInst(VarType), SC, Set, Binding,
5747 ArraySize, IndexReg, Name, MIRBuilder);
5748
5749 // The handle for the buffer is the pointer to the resource. For an image, the
5750 // handle is the image object. So images get an extra load.
5751 uint32_t LoadOpcode =
5752 IsStructuredBuffer ? SPIRV::OpCopyObject : SPIRV::OpLoad;
5753 GR.assignSPIRVTypeToVReg(ResType, HandleReg, *Pos.getMF());
5754 BuildMI(*Pos.getParent(), Pos, HandleDef.getDebugLoc(), TII.get(LoadOpcode))
5755 .addDef(HandleReg)
5756 .addUse(GR.getSPIRVTypeID(ResType))
5757 .addUse(VarReg)
5758 .constrainAllUses(TII, TRI, RBI);
5759 return true;
5760}
5761
5762void SPIRVInstructionSelector::errorIfInstrOutsideShader(
5763 MachineInstr &I) const {
5764 if (!STI.isShader()) {
5765 std::string DiagMsg;
5766 raw_string_ostream OS(DiagMsg);
5767 I.print(OS, true, false, false, false);
5768 DiagMsg += " is only supported in shaders.\n";
5769 report_fatal_error(DiagMsg.c_str(), false);
5770 }
5771}
5772
5773namespace llvm {
5774InstructionSelector *
5776 const SPIRVSubtarget &Subtarget,
5777 const RegisterBankInfo &RBI) {
5778 return new SPIRVInstructionSelector(TM, Subtarget, RBI);
5779}
5780} // namespace llvm
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
#define GET_GLOBALISEL_PREDICATES_INIT
#define GET_GLOBALISEL_TEMPORARIES_INIT
@ Generic
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares a class to represent arbitrary precision floating point values and provide a varie...
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
basic Basic Alias true
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:717
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
static StringRef getName(Value *V)
static unsigned getFCmpOpcode(CmpInst::Predicate Pred, unsigned Size)
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)
unsigned getVectorSizeOrOne(SPIRVTypeInst Type)
bool isDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
spirv structurize SPIRV
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:114
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
BinaryOperator * Mul
static const fltSemantics & IEEEsingle()
Definition APFloat.h:296
static const fltSemantics & IEEEdouble()
Definition APFloat.h:297
static const fltSemantics & IEEEhalf()
Definition APFloat.h:294
static APFloat getOne(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative One.
Definition APFloat.h:1143
static APFloat getZero(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Zero.
Definition APFloat.h:1134
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:235
ArrayRef - 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:676
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:679
@ ICMP_SLT
signed less than
Definition InstrTypes.h:705
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:706
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:682
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition InstrTypes.h:691
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:680
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:681
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:700
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:699
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:703
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition InstrTypes.h:690
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:684
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition InstrTypes.h:687
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:701
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition InstrTypes.h:688
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:683
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:685
@ ICMP_NE
not equal
Definition InstrTypes.h:698
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:704
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition InstrTypes.h:692
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:702
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition InstrTypes.h:689
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:686
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
unsigned size() const
Definition DenseMap.h:110
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:358
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:318
constexpr bool isScalar() const
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.
constexpr bool isPointer() const
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 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,...
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...
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
Analysis providing profile information.
Holds all the information related to register banks.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
bool isScalarOrVectorSigned(SPIRVTypeInst Type) const
SPIRVTypeInst getOrCreateOpTypeSampledImage(SPIRVTypeInst ImageType, MachineIRBuilder &MIRBuilder)
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg, const MachineFunction &MF)
const TargetRegisterClass * getRegClass(SPIRVTypeInst SpvType) const
MachineInstr * getOrAddMemAliasingINTELInst(MachineIRBuilder &MIRBuilder, const MDNode *AliasingListMD)
bool isAggregateType(SPIRVTypeInst Type) const
unsigned getScalarOrVectorBitWidth(SPIRVTypeInst Type) const
SPIRVTypeInst getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
Register buildGlobalVariable(Register Reg, SPIRVTypeInst BaseType, StringRef Name, const GlobalValue *GV, SPIRV::StorageClass::StorageClass Storage, const MachineInstr *Init, bool IsConst, const std::optional< SPIRV::LinkageType::LinkageType > &LinkageType, MachineIRBuilder &MIRBuilder, bool IsInstSelector)
SPIRVTypeInst getResultType(Register VReg, MachineFunction *MF=nullptr)
unsigned getScalarOrVectorComponentCount(Register VReg) const
const Type * getTypeForSPIRVType(SPIRVTypeInst Ty) const
bool isBitcastCompatible(SPIRVTypeInst Type1, SPIRVTypeInst Type2) const
Register getOrCreateConstFP(APFloat Val, MachineInstr &I, SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII, bool ZeroAsNull=true)
LLT getRegType(SPIRVTypeInst SpvType) const
void invalidateMachineInstr(MachineInstr *MI)
SPIRVTypeInst getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder, bool EmitIR)
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC)
bool isScalarOfType(Register VReg, unsigned TypeOpcode) const
Register getSPIRVTypeID(SPIRVTypeInst SpirvType) const
Register getOrCreateConstInt(uint64_t Val, MachineInstr &I, SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII, bool ZeroAsNull=true)
Register getOrCreateConstIntArray(uint64_t Val, size_t Num, MachineInstr &I, SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII)
bool findValueAttrs(const MachineInstr *Key, Type *&Ty, StringRef &Name)
SPIRVTypeInst retrieveScalarOrVectorIntType(SPIRVTypeInst Type) const
Register getOrCreateGlobalVariableWithBinding(SPIRVTypeInst VarType, uint32_t Set, uint32_t Binding, StringRef Name, MachineIRBuilder &MIRBuilder)
SPIRVTypeInst changePointerStorageClass(SPIRVTypeInst PtrType, SPIRV::StorageClass::StorageClass SC, MachineInstr &I)
Register getOrCreateConstVector(uint64_t Val, MachineInstr &I, SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII, bool ZeroAsNull=true)
Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder, SPIRVTypeInst SpvType=nullptr)
void addGlobalObject(const Value *V, const MachineFunction *MF, Register R)
SPIRVTypeInst getScalarOrVectorComponentType(SPIRVTypeInst Type) const
void recordFunctionPointer(const MachineOperand *MO, const Function *F)
SPIRVTypeInst getOrCreateSPIRVFloatType(unsigned BitWidth, MachineInstr &I, const SPIRVInstrInfo &TII)
SPIRVTypeInst getPointeeType(SPIRVTypeInst PtrType)
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const
MachineFunction * setCurrentFunc(MachineFunction &MF)
Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder, SPIRVTypeInst SpvType)
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
Type * getDeducedGlobalValueType(const GlobalValue *Global)
Register getOrCreateUndef(MachineInstr &I, SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII)
SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const
bool erase(const MachineInstr *MI)
bool add(SPIRV::IRHandle Handle, const MachineInstr *MI)
Register find(SPIRV::IRHandle Handle, const MachineFunction *MF)
bool isPhysicalSPIRV() const
bool isAtLeastSPIRVVer(VersionTuple VerToCompareTo) const
bool canUseExtInstSet(SPIRV::InstructionSet::InstructionSet E) const
bool isLogicalSPIRV() const
bool canUseExtension(SPIRV::Extension::Extension E) const
bool erase(PtrType Ptr)
Remove pointer from the set.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
constexpr size_t size() const
size - Get the string size.
Definition StringRef.h:143
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:413
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
@ HalfTyID
16-bit floating point type
Definition Type.h:56
@ FloatTyID
32-bit floating point type
Definition Type.h:58
@ DoubleTyID
64-bit floating point type
Definition Type.h:59
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:352
bool isStructTy() const
True if this is an instance of StructType.
Definition Type.h:261
bool isAggregateType() const
Return true if the type is an aggregate type.
Definition Type.h:304
TypeID getTypeID() const
Return the type id for the type.
Definition Type.h:136
Value * getOperand(unsigned i) const
Definition User.h:207
bool hasName() const
Definition Value.h:262
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:322
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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
NodeAddr< InstrNode * > Instr
Definition RDFGraph.h:389
NodeAddr< UseNode * > Use
Definition RDFGraph.h:385
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
void buildOpName(Register Target, const StringRef &Name, MachineIRBuilder &MIRBuilder)
@ Offset
Definition DWP.cpp:532
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
int64_t getIConstValSext(Register ConstReg, const MachineRegisterInfo *MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool isTypeFoldingSupported(unsigned Opcode)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
Definition InstrProf.h:296
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:1726
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:155
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
Register createVirtualRegister(SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF)
unsigned getArrayComponentCount(const MachineRegisterInfo *MRI, const MachineInstr *ResType)
uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI)
SmallVector< MachineInstr *, 4 > createContinuedInstructions(MachineIRBuilder &MIRBuilder, unsigned Opcode, unsigned MinWC, unsigned ContinuedOpcode, ArrayRef< Register > Args, Register ReturnRegister, Register TypeID)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
constexpr unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)
Definition SPIRVUtils.h:247
MachineBasicBlock::iterator getFirstValidInstructionInsertPoint(MachineBasicBlock &BB)
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, const std::vector< uint32_t > &DecArgs, StringRef StrImm)
MachineBasicBlock::iterator getOpVariableMBBIt(MachineInstr &I)
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
Type * toTypedPointer(Type *Ty)
Definition SPIRVUtils.h:461
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
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:232
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
MachineInstr * passCopy(MachineInstr *Def, const MachineRegisterInfo *MRI)
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
std::optional< SPIRV::LinkageType::LinkageType > getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV)
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
AtomicOrdering
Atomic ordering for LLVM's memory model.
SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id)
InstructionSelector * createSPIRVInstructionSelector(const SPIRVTargetMachine &TM, const SPIRVSubtarget &Subtarget, const RegisterBankInfo &RBI)
std::string getStringValueFromReg(Register Reg, MachineRegisterInfo &MRI)
int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
MachineInstr * getDefInstrMaybeConstant(Register &ConstReg, const MachineRegisterInfo *MRI)
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
bool hasInitializer(const GlobalVariable *GV)
Definition SPIRVUtils.h:349
void addStringImm(const StringRef &Str, MCInst &Inst)
MachineInstr * getVRegDef(MachineRegisterInfo &MRI, Register Reg)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
std::string getLinkStringForBuiltIn(SPIRV::BuiltIn::BuiltIn BuiltInValue)
LLVM_ABI bool isTriviallyDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
Check whether an instruction MI is dead: it only defines dead virtual registers, and doesn't have oth...
Definition Utils.cpp:221
#define N