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