1 //===- SPIRVInstructionSelector.cpp ------------------------------*- C++ -*-==//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the targeting of the InstructionSelector class for
11 // TODO: This should be generated by TableGen.
13 //===----------------------------------------------------------------------===//
15 #include "MCTargetDesc/SPIRVBaseInfo.h"
16 #include "MCTargetDesc/SPIRVMCTargetDesc.h"
18 #include "SPIRVGlobalRegistry.h"
19 #include "SPIRVInstrInfo.h"
20 #include "SPIRVRegisterBankInfo.h"
21 #include "SPIRVRegisterInfo.h"
22 #include "SPIRVTargetMachine.h"
23 #include "SPIRVUtils.h"
24 #include "llvm/ADT/APFloat.h"
25 #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
26 #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
27 #include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
28 #include "llvm/CodeGen/MachineInstrBuilder.h"
29 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
30 #include "llvm/CodeGen/MachineRegisterInfo.h"
31 #include "llvm/CodeGen/TargetOpcodes.h"
32 #include "llvm/IR/IntrinsicsSPIRV.h"
33 #include "llvm/Support/Debug.h"
37 class SPIRVMachineModuleInfo
: public MachineModuleInfoImpl
{
39 SyncScope::ID Work_ItemSSID
;
40 SyncScope::ID WorkGroupSSID
;
41 SyncScope::ID DeviceSSID
;
42 SyncScope::ID AllSVMDevicesSSID
;
43 SyncScope::ID SubGroupSSID
;
45 SPIRVMachineModuleInfo(const MachineModuleInfo
&MMI
) {
46 LLVMContext
&CTX
= MMI
.getModule()->getContext();
47 Work_ItemSSID
= CTX
.getOrInsertSyncScopeID("work_item");
48 WorkGroupSSID
= CTX
.getOrInsertSyncScopeID("workgroup");
49 DeviceSSID
= CTX
.getOrInsertSyncScopeID("device");
50 AllSVMDevicesSSID
= CTX
.getOrInsertSyncScopeID("all_svm_devices");
51 SubGroupSSID
= CTX
.getOrInsertSyncScopeID("sub_group");
55 } // end namespace llvm
57 #define DEBUG_TYPE "spirv-isel"
60 namespace CL
= SPIRV::OpenCLExtInst
;
61 namespace GL
= SPIRV::GLSLExtInst
;
64 std::vector
<std::pair
<SPIRV::InstructionSet::InstructionSet
, uint32_t>>;
68 #define GET_GLOBALISEL_PREDICATE_BITSET
69 #include "SPIRVGenGlobalISel.inc"
70 #undef GET_GLOBALISEL_PREDICATE_BITSET
72 class SPIRVInstructionSelector
: public InstructionSelector
{
73 const SPIRVSubtarget
&STI
;
74 const SPIRVInstrInfo
&TII
;
75 const SPIRVRegisterInfo
&TRI
;
76 const RegisterBankInfo
&RBI
;
77 SPIRVGlobalRegistry
&GR
;
78 MachineRegisterInfo
*MRI
;
79 SPIRVMachineModuleInfo
*MMI
= nullptr;
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
;
86 SPIRVInstructionSelector(const SPIRVTargetMachine
&TM
,
87 const SPIRVSubtarget
&ST
,
88 const RegisterBankInfo
&RBI
);
89 void setupMF(MachineFunction
&MF
, GISelKnownBits
*KB
,
90 CodeGenCoverage
*CoverageInfo
, ProfileSummaryInfo
*PSI
,
91 BlockFrequencyInfo
*BFI
) override
;
92 // Common selection code. Instruction-specific selection occurs in spvSelect.
93 bool select(MachineInstr
&I
) override
;
94 static const char *getName() { return DEBUG_TYPE
; }
96 #define GET_GLOBALISEL_PREDICATES_DECL
97 #include "SPIRVGenGlobalISel.inc"
98 #undef GET_GLOBALISEL_PREDICATES_DECL
100 #define GET_GLOBALISEL_TEMPORARIES_DECL
101 #include "SPIRVGenGlobalISel.inc"
102 #undef GET_GLOBALISEL_TEMPORARIES_DECL
105 // tblgen-erated 'select' implementation, used as the initial selector for
106 // the patterns that don't require complex C++.
107 bool selectImpl(MachineInstr
&I
, CodeGenCoverage
&CoverageInfo
) const;
109 // All instruction-specific selection that didn't happen in "select()".
110 // Is basically a large Switch/Case delegating to all other select method.
111 bool spvSelect(Register ResVReg
, const SPIRVType
*ResType
,
112 MachineInstr
&I
) const;
114 bool selectGlobalValue(Register ResVReg
, MachineInstr
&I
,
115 const MachineInstr
*Init
= nullptr) const;
117 bool selectUnOpWithSrc(Register ResVReg
, const SPIRVType
*ResType
,
118 MachineInstr
&I
, Register SrcReg
,
119 unsigned Opcode
) const;
120 bool selectUnOp(Register ResVReg
, const SPIRVType
*ResType
, MachineInstr
&I
,
121 unsigned Opcode
) const;
123 bool selectBitcast(Register ResVReg
, const SPIRVType
*ResType
,
124 MachineInstr
&I
) const;
126 bool selectLoad(Register ResVReg
, const SPIRVType
*ResType
,
127 MachineInstr
&I
) const;
128 bool selectStore(MachineInstr
&I
) const;
130 bool selectStackSave(Register ResVReg
, const SPIRVType
*ResType
,
131 MachineInstr
&I
) const;
132 bool selectStackRestore(MachineInstr
&I
) const;
134 bool selectMemOperation(Register ResVReg
, MachineInstr
&I
) const;
136 bool selectAtomicRMW(Register ResVReg
, const SPIRVType
*ResType
,
137 MachineInstr
&I
, unsigned NewOpcode
,
138 unsigned NegateOpcode
= 0) const;
140 bool selectAtomicCmpXchg(Register ResVReg
, const SPIRVType
*ResType
,
141 MachineInstr
&I
) const;
143 bool selectFence(MachineInstr
&I
) const;
145 bool selectAddrSpaceCast(Register ResVReg
, const SPIRVType
*ResType
,
146 MachineInstr
&I
) const;
148 bool selectAnyOrAll(Register ResVReg
, const SPIRVType
*ResType
,
149 MachineInstr
&I
, unsigned OpType
) const;
151 bool selectAll(Register ResVReg
, const SPIRVType
*ResType
,
152 MachineInstr
&I
) const;
154 bool selectAny(Register ResVReg
, const SPIRVType
*ResType
,
155 MachineInstr
&I
) const;
157 bool selectBitreverse(Register ResVReg
, const SPIRVType
*ResType
,
158 MachineInstr
&I
) const;
160 bool selectConstVector(Register ResVReg
, const SPIRVType
*ResType
,
161 MachineInstr
&I
) const;
162 bool selectSplatVector(Register ResVReg
, const SPIRVType
*ResType
,
163 MachineInstr
&I
) const;
165 bool selectCmp(Register ResVReg
, const SPIRVType
*ResType
,
166 unsigned comparisonOpcode
, MachineInstr
&I
) const;
168 bool selectICmp(Register ResVReg
, const SPIRVType
*ResType
,
169 MachineInstr
&I
) const;
170 bool selectFCmp(Register ResVReg
, const SPIRVType
*ResType
,
171 MachineInstr
&I
) const;
173 void renderImm32(MachineInstrBuilder
&MIB
, const MachineInstr
&I
,
175 void renderFImm32(MachineInstrBuilder
&MIB
, const MachineInstr
&I
,
178 bool selectConst(Register ResVReg
, const SPIRVType
*ResType
, const APInt
&Imm
,
179 MachineInstr
&I
) const;
181 bool selectSelect(Register ResVReg
, const SPIRVType
*ResType
, MachineInstr
&I
,
182 bool IsSigned
) const;
183 bool selectIToF(Register ResVReg
, const SPIRVType
*ResType
, MachineInstr
&I
,
184 bool IsSigned
, unsigned Opcode
) const;
185 bool selectExt(Register ResVReg
, const SPIRVType
*ResType
, MachineInstr
&I
,
186 bool IsSigned
) const;
188 bool selectTrunc(Register ResVReg
, const SPIRVType
*ResType
,
189 MachineInstr
&I
) const;
191 bool selectIntToBool(Register IntReg
, Register ResVReg
, MachineInstr
&I
,
192 const SPIRVType
*intTy
, const SPIRVType
*boolTy
) const;
194 bool selectOpUndef(Register ResVReg
, const SPIRVType
*ResType
,
195 MachineInstr
&I
) const;
196 bool selectFreeze(Register ResVReg
, const SPIRVType
*ResType
,
197 MachineInstr
&I
) const;
198 bool selectIntrinsic(Register ResVReg
, const SPIRVType
*ResType
,
199 MachineInstr
&I
) const;
200 bool selectExtractVal(Register ResVReg
, const SPIRVType
*ResType
,
201 MachineInstr
&I
) const;
202 bool selectInsertVal(Register ResVReg
, const SPIRVType
*ResType
,
203 MachineInstr
&I
) const;
204 bool selectExtractElt(Register ResVReg
, const SPIRVType
*ResType
,
205 MachineInstr
&I
) const;
206 bool selectInsertElt(Register ResVReg
, const SPIRVType
*ResType
,
207 MachineInstr
&I
) const;
208 bool selectGEP(Register ResVReg
, const SPIRVType
*ResType
,
209 MachineInstr
&I
) const;
211 bool selectFrameIndex(Register ResVReg
, const SPIRVType
*ResType
,
212 MachineInstr
&I
) const;
213 bool selectAllocaArray(Register ResVReg
, const SPIRVType
*ResType
,
214 MachineInstr
&I
) const;
216 bool selectBranch(MachineInstr
&I
) const;
217 bool selectBranchCond(MachineInstr
&I
) const;
219 bool selectPhi(Register ResVReg
, const SPIRVType
*ResType
,
220 MachineInstr
&I
) const;
222 bool selectExtInst(Register ResVReg
, const SPIRVType
*ResType
,
223 MachineInstr
&I
, CL::OpenCLExtInst CLInst
) const;
224 bool selectExtInst(Register ResVReg
, const SPIRVType
*ResType
,
225 MachineInstr
&I
, CL::OpenCLExtInst CLInst
,
226 GL::GLSLExtInst GLInst
) const;
227 bool selectExtInst(Register ResVReg
, const SPIRVType
*ResType
,
228 MachineInstr
&I
, const ExtInstList
&ExtInsts
) const;
230 bool selectLog10(Register ResVReg
, const SPIRVType
*ResType
,
231 MachineInstr
&I
) const;
233 bool selectSpvThreadId(Register ResVReg
, const SPIRVType
*ResType
,
234 MachineInstr
&I
) const;
236 bool selectUnmergeValues(MachineInstr
&I
) const;
238 Register
buildI32Constant(uint32_t Val
, MachineInstr
&I
,
239 const SPIRVType
*ResType
= nullptr) const;
241 Register
buildZerosVal(const SPIRVType
*ResType
, MachineInstr
&I
) const;
242 Register
buildZerosValF(const SPIRVType
*ResType
, MachineInstr
&I
) const;
243 Register
buildOnesVal(bool AllOnes
, const SPIRVType
*ResType
,
244 MachineInstr
&I
) const;
246 bool wrapIntoSpecConstantOp(MachineInstr
&I
,
247 SmallVector
<Register
> &CompositeArgs
) const;
250 } // end anonymous namespace
252 #define GET_GLOBALISEL_IMPL
253 #include "SPIRVGenGlobalISel.inc"
254 #undef GET_GLOBALISEL_IMPL
256 SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine
&TM
,
257 const SPIRVSubtarget
&ST
,
258 const RegisterBankInfo
&RBI
)
259 : InstructionSelector(), STI(ST
), TII(*ST
.getInstrInfo()),
260 TRI(*ST
.getRegisterInfo()), RBI(RBI
), GR(*ST
.getSPIRVGlobalRegistry()),
261 #define GET_GLOBALISEL_PREDICATES_INIT
262 #include "SPIRVGenGlobalISel.inc"
263 #undef GET_GLOBALISEL_PREDICATES_INIT
264 #define GET_GLOBALISEL_TEMPORARIES_INIT
265 #include "SPIRVGenGlobalISel.inc"
266 #undef GET_GLOBALISEL_TEMPORARIES_INIT
270 void SPIRVInstructionSelector::setupMF(MachineFunction
&MF
, GISelKnownBits
*KB
,
271 CodeGenCoverage
*CoverageInfo
,
272 ProfileSummaryInfo
*PSI
,
273 BlockFrequencyInfo
*BFI
) {
274 MMI
= &MF
.getMMI().getObjFileInfo
<SPIRVMachineModuleInfo
>();
275 MRI
= &MF
.getRegInfo();
276 GR
.setCurrentFunc(MF
);
277 InstructionSelector::setupMF(MF
, KB
, CoverageInfo
, PSI
, BFI
);
280 static bool isImm(const MachineOperand
&MO
, MachineRegisterInfo
*MRI
);
282 // Defined in SPIRVLegalizerInfo.cpp.
283 extern bool isTypeFoldingSupported(unsigned Opcode
);
285 bool SPIRVInstructionSelector::select(MachineInstr
&I
) {
286 assert(I
.getParent() && "Instruction should be in a basic block!");
287 assert(I
.getParent()->getParent() && "Instruction should be in a function!");
289 Register Opcode
= I
.getOpcode();
290 // If it's not a GMIR instruction, we've selected it already.
291 if (!isPreISelGenericOpcode(Opcode
)) {
292 if (Opcode
== SPIRV::ASSIGN_TYPE
) { // These pseudos aren't needed any more.
293 auto *Def
= MRI
->getVRegDef(I
.getOperand(1).getReg());
294 if (isTypeFoldingSupported(Def
->getOpcode())) {
295 bool Res
= selectImpl(I
, *CoverageInfo
);
296 assert(Res
|| Def
->getOpcode() == TargetOpcode::G_CONSTANT
);
300 MRI
->replaceRegWith(I
.getOperand(1).getReg(), I
.getOperand(0).getReg());
301 I
.removeFromParent();
303 } else if (I
.getNumDefs() == 1) {
304 // Make all vregs 32 bits (for SPIR-V IDs).
305 MRI
->setType(I
.getOperand(0).getReg(), LLT::scalar(32));
307 return constrainSelectedInstRegOperands(I
, TII
, TRI
, RBI
);
310 if (I
.getNumOperands() != I
.getNumExplicitOperands()) {
311 LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
315 // Common code for getting return reg+type, and removing selected instr
316 // from parent occurs here. Instr-specific selection happens in spvSelect().
317 bool HasDefs
= I
.getNumDefs() > 0;
318 Register ResVReg
= HasDefs
? I
.getOperand(0).getReg() : Register(0);
319 SPIRVType
*ResType
= HasDefs
? GR
.getSPIRVTypeForVReg(ResVReg
) : nullptr;
320 assert(!HasDefs
|| ResType
|| I
.getOpcode() == TargetOpcode::G_GLOBAL_VALUE
);
321 if (spvSelect(ResVReg
, ResType
, I
)) {
322 if (HasDefs
) // Make all vregs 32 bits (for SPIR-V IDs).
323 for (unsigned i
= 0; i
< I
.getNumDefs(); ++i
)
324 MRI
->setType(I
.getOperand(i
).getReg(), LLT::scalar(32));
325 I
.removeFromParent();
331 bool SPIRVInstructionSelector::spvSelect(Register ResVReg
,
332 const SPIRVType
*ResType
,
333 MachineInstr
&I
) const {
334 const unsigned Opcode
= I
.getOpcode();
335 if (isTypeFoldingSupported(Opcode
) && Opcode
!= TargetOpcode::G_CONSTANT
)
336 return selectImpl(I
, *CoverageInfo
);
338 case TargetOpcode::G_CONSTANT
:
339 return selectConst(ResVReg
, ResType
, I
.getOperand(1).getCImm()->getValue(),
341 case TargetOpcode::G_GLOBAL_VALUE
:
342 return selectGlobalValue(ResVReg
, I
);
343 case TargetOpcode::G_IMPLICIT_DEF
:
344 return selectOpUndef(ResVReg
, ResType
, I
);
345 case TargetOpcode::G_FREEZE
:
346 return selectFreeze(ResVReg
, ResType
, I
);
348 case TargetOpcode::G_INTRINSIC
:
349 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS
:
350 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS
:
351 return selectIntrinsic(ResVReg
, ResType
, I
);
352 case TargetOpcode::G_BITREVERSE
:
353 return selectBitreverse(ResVReg
, ResType
, I
);
355 case TargetOpcode::G_BUILD_VECTOR
:
356 return selectConstVector(ResVReg
, ResType
, I
);
357 case TargetOpcode::G_SPLAT_VECTOR
:
358 return selectSplatVector(ResVReg
, ResType
, I
);
360 case TargetOpcode::G_SHUFFLE_VECTOR
: {
361 MachineBasicBlock
&BB
= *I
.getParent();
362 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpVectorShuffle
))
364 .addUse(GR
.getSPIRVTypeID(ResType
))
365 .addUse(I
.getOperand(1).getReg())
366 .addUse(I
.getOperand(2).getReg());
367 for (auto V
: I
.getOperand(3).getShuffleMask())
369 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
371 case TargetOpcode::G_MEMMOVE
:
372 case TargetOpcode::G_MEMCPY
:
373 case TargetOpcode::G_MEMSET
:
374 return selectMemOperation(ResVReg
, I
);
376 case TargetOpcode::G_ICMP
:
377 return selectICmp(ResVReg
, ResType
, I
);
378 case TargetOpcode::G_FCMP
:
379 return selectFCmp(ResVReg
, ResType
, I
);
381 case TargetOpcode::G_FRAME_INDEX
:
382 return selectFrameIndex(ResVReg
, ResType
, I
);
384 case TargetOpcode::G_LOAD
:
385 return selectLoad(ResVReg
, ResType
, I
);
386 case TargetOpcode::G_STORE
:
387 return selectStore(I
);
389 case TargetOpcode::G_BR
:
390 return selectBranch(I
);
391 case TargetOpcode::G_BRCOND
:
392 return selectBranchCond(I
);
394 case TargetOpcode::G_PHI
:
395 return selectPhi(ResVReg
, ResType
, I
);
397 case TargetOpcode::G_FPTOSI
:
398 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpConvertFToS
);
399 case TargetOpcode::G_FPTOUI
:
400 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpConvertFToU
);
402 case TargetOpcode::G_SITOFP
:
403 return selectIToF(ResVReg
, ResType
, I
, true, SPIRV::OpConvertSToF
);
404 case TargetOpcode::G_UITOFP
:
405 return selectIToF(ResVReg
, ResType
, I
, false, SPIRV::OpConvertUToF
);
407 case TargetOpcode::G_CTPOP
:
408 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpBitCount
);
409 case TargetOpcode::G_SMIN
:
410 return selectExtInst(ResVReg
, ResType
, I
, CL::s_min
, GL::SMin
);
411 case TargetOpcode::G_UMIN
:
412 return selectExtInst(ResVReg
, ResType
, I
, CL::u_min
, GL::UMin
);
414 case TargetOpcode::G_SMAX
:
415 return selectExtInst(ResVReg
, ResType
, I
, CL::s_max
, GL::SMax
);
416 case TargetOpcode::G_UMAX
:
417 return selectExtInst(ResVReg
, ResType
, I
, CL::u_max
, GL::UMax
);
419 case TargetOpcode::G_FMA
:
420 return selectExtInst(ResVReg
, ResType
, I
, CL::fma
, GL::Fma
);
422 case TargetOpcode::G_FPOW
:
423 return selectExtInst(ResVReg
, ResType
, I
, CL::pow
, GL::Pow
);
424 case TargetOpcode::G_FPOWI
:
425 return selectExtInst(ResVReg
, ResType
, I
, CL::pown
);
427 case TargetOpcode::G_FEXP
:
428 return selectExtInst(ResVReg
, ResType
, I
, CL::exp
, GL::Exp
);
429 case TargetOpcode::G_FEXP2
:
430 return selectExtInst(ResVReg
, ResType
, I
, CL::exp2
, GL::Exp2
);
432 case TargetOpcode::G_FLOG
:
433 return selectExtInst(ResVReg
, ResType
, I
, CL::log
, GL::Log
);
434 case TargetOpcode::G_FLOG2
:
435 return selectExtInst(ResVReg
, ResType
, I
, CL::log2
, GL::Log2
);
436 case TargetOpcode::G_FLOG10
:
437 return selectLog10(ResVReg
, ResType
, I
);
439 case TargetOpcode::G_FABS
:
440 return selectExtInst(ResVReg
, ResType
, I
, CL::fabs
, GL::FAbs
);
441 case TargetOpcode::G_ABS
:
442 return selectExtInst(ResVReg
, ResType
, I
, CL::s_abs
, GL::SAbs
);
444 case TargetOpcode::G_FMINNUM
:
445 case TargetOpcode::G_FMINIMUM
:
446 return selectExtInst(ResVReg
, ResType
, I
, CL::fmin
, GL::NMin
);
447 case TargetOpcode::G_FMAXNUM
:
448 case TargetOpcode::G_FMAXIMUM
:
449 return selectExtInst(ResVReg
, ResType
, I
, CL::fmax
, GL::NMax
);
451 case TargetOpcode::G_FCOPYSIGN
:
452 return selectExtInst(ResVReg
, ResType
, I
, CL::copysign
);
454 case TargetOpcode::G_FCEIL
:
455 return selectExtInst(ResVReg
, ResType
, I
, CL::ceil
, GL::Ceil
);
456 case TargetOpcode::G_FFLOOR
:
457 return selectExtInst(ResVReg
, ResType
, I
, CL::floor
, GL::Floor
);
459 case TargetOpcode::G_FCOS
:
460 return selectExtInst(ResVReg
, ResType
, I
, CL::cos
, GL::Cos
);
461 case TargetOpcode::G_FSIN
:
462 return selectExtInst(ResVReg
, ResType
, I
, CL::sin
, GL::Sin
);
464 case TargetOpcode::G_FSQRT
:
465 return selectExtInst(ResVReg
, ResType
, I
, CL::sqrt
, GL::Sqrt
);
467 case TargetOpcode::G_CTTZ
:
468 case TargetOpcode::G_CTTZ_ZERO_UNDEF
:
469 return selectExtInst(ResVReg
, ResType
, I
, CL::ctz
);
470 case TargetOpcode::G_CTLZ
:
471 case TargetOpcode::G_CTLZ_ZERO_UNDEF
:
472 return selectExtInst(ResVReg
, ResType
, I
, CL::clz
);
474 case TargetOpcode::G_INTRINSIC_ROUND
:
475 return selectExtInst(ResVReg
, ResType
, I
, CL::round
, GL::Round
);
476 case TargetOpcode::G_INTRINSIC_ROUNDEVEN
:
477 return selectExtInst(ResVReg
, ResType
, I
, CL::rint
, GL::RoundEven
);
478 case TargetOpcode::G_INTRINSIC_TRUNC
:
479 return selectExtInst(ResVReg
, ResType
, I
, CL::trunc
, GL::Trunc
);
480 case TargetOpcode::G_FRINT
:
481 case TargetOpcode::G_FNEARBYINT
:
482 return selectExtInst(ResVReg
, ResType
, I
, CL::rint
, GL::RoundEven
);
484 case TargetOpcode::G_SMULH
:
485 return selectExtInst(ResVReg
, ResType
, I
, CL::s_mul_hi
);
486 case TargetOpcode::G_UMULH
:
487 return selectExtInst(ResVReg
, ResType
, I
, CL::u_mul_hi
);
489 case TargetOpcode::G_SEXT
:
490 return selectExt(ResVReg
, ResType
, I
, true);
491 case TargetOpcode::G_ANYEXT
:
492 case TargetOpcode::G_ZEXT
:
493 return selectExt(ResVReg
, ResType
, I
, false);
494 case TargetOpcode::G_TRUNC
:
495 return selectTrunc(ResVReg
, ResType
, I
);
496 case TargetOpcode::G_FPTRUNC
:
497 case TargetOpcode::G_FPEXT
:
498 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpFConvert
);
500 case TargetOpcode::G_PTRTOINT
:
501 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpConvertPtrToU
);
502 case TargetOpcode::G_INTTOPTR
:
503 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpConvertUToPtr
);
504 case TargetOpcode::G_BITCAST
:
505 return selectBitcast(ResVReg
, ResType
, I
);
506 case TargetOpcode::G_ADDRSPACE_CAST
:
507 return selectAddrSpaceCast(ResVReg
, ResType
, I
);
508 case TargetOpcode::G_PTR_ADD
: {
509 // Currently, we get G_PTR_ADD only as a result of translating
510 // global variables, initialized with constant expressions like GV + Const
511 // (see test opencl/basic/progvar_prog_scope_init.ll).
512 // TODO: extend the handler once we have other cases.
513 assert(I
.getOperand(1).isReg() && I
.getOperand(2).isReg());
514 Register GV
= I
.getOperand(1).getReg();
515 MachineRegisterInfo::def_instr_iterator II
= MRI
->def_instr_begin(GV
);
517 assert(((*II
).getOpcode() == TargetOpcode::G_GLOBAL_VALUE
||
518 (*II
).getOpcode() == TargetOpcode::COPY
||
519 (*II
).getOpcode() == SPIRV::OpVariable
) &&
520 isImm(I
.getOperand(2), MRI
));
521 Register Idx
= buildZerosVal(GR
.getOrCreateSPIRVIntegerType(32, I
, TII
), I
);
522 MachineBasicBlock
&BB
= *I
.getParent();
523 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpSpecConstantOp
))
525 .addUse(GR
.getSPIRVTypeID(ResType
))
526 .addImm(static_cast<uint32_t>(
527 SPIRV::Opcode::InBoundsPtrAccessChain
))
530 .addUse(I
.getOperand(2).getReg());
531 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
534 case TargetOpcode::G_ATOMICRMW_OR
:
535 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicOr
);
536 case TargetOpcode::G_ATOMICRMW_ADD
:
537 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicIAdd
);
538 case TargetOpcode::G_ATOMICRMW_AND
:
539 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicAnd
);
540 case TargetOpcode::G_ATOMICRMW_MAX
:
541 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicSMax
);
542 case TargetOpcode::G_ATOMICRMW_MIN
:
543 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicSMin
);
544 case TargetOpcode::G_ATOMICRMW_SUB
:
545 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicISub
);
546 case TargetOpcode::G_ATOMICRMW_XOR
:
547 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicXor
);
548 case TargetOpcode::G_ATOMICRMW_UMAX
:
549 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicUMax
);
550 case TargetOpcode::G_ATOMICRMW_UMIN
:
551 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicUMin
);
552 case TargetOpcode::G_ATOMICRMW_XCHG
:
553 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicExchange
);
554 case TargetOpcode::G_ATOMIC_CMPXCHG
:
555 return selectAtomicCmpXchg(ResVReg
, ResType
, I
);
557 case TargetOpcode::G_ATOMICRMW_FADD
:
558 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicFAddEXT
);
559 case TargetOpcode::G_ATOMICRMW_FSUB
:
560 // Translate G_ATOMICRMW_FSUB to OpAtomicFAddEXT with negative value operand
561 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicFAddEXT
,
563 case TargetOpcode::G_ATOMICRMW_FMIN
:
564 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicFMinEXT
);
565 case TargetOpcode::G_ATOMICRMW_FMAX
:
566 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicFMaxEXT
);
568 case TargetOpcode::G_FENCE
:
569 return selectFence(I
);
571 case TargetOpcode::G_STACKSAVE
:
572 return selectStackSave(ResVReg
, ResType
, I
);
573 case TargetOpcode::G_STACKRESTORE
:
574 return selectStackRestore(I
);
576 case TargetOpcode::G_UNMERGE_VALUES
:
577 return selectUnmergeValues(I
);
584 bool SPIRVInstructionSelector::selectExtInst(Register ResVReg
,
585 const SPIRVType
*ResType
,
587 CL::OpenCLExtInst CLInst
) const {
588 return selectExtInst(ResVReg
, ResType
, I
,
589 {{SPIRV::InstructionSet::OpenCL_std
, CLInst
}});
592 bool SPIRVInstructionSelector::selectExtInst(Register ResVReg
,
593 const SPIRVType
*ResType
,
595 CL::OpenCLExtInst CLInst
,
596 GL::GLSLExtInst GLInst
) const {
597 ExtInstList ExtInsts
= {{SPIRV::InstructionSet::OpenCL_std
, CLInst
},
598 {SPIRV::InstructionSet::GLSL_std_450
, GLInst
}};
599 return selectExtInst(ResVReg
, ResType
, I
, ExtInsts
);
602 bool SPIRVInstructionSelector::selectExtInst(Register ResVReg
,
603 const SPIRVType
*ResType
,
605 const ExtInstList
&Insts
) const {
607 for (const auto &Ex
: Insts
) {
608 SPIRV::InstructionSet::InstructionSet Set
= Ex
.first
;
609 uint32_t Opcode
= Ex
.second
;
610 if (STI
.canUseExtInstSet(Set
)) {
611 MachineBasicBlock
&BB
= *I
.getParent();
612 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpExtInst
))
614 .addUse(GR
.getSPIRVTypeID(ResType
))
615 .addImm(static_cast<uint32_t>(Set
))
617 const unsigned NumOps
= I
.getNumOperands();
618 for (unsigned i
= 1; i
< NumOps
; ++i
)
619 MIB
.add(I
.getOperand(i
));
620 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
626 bool SPIRVInstructionSelector::selectUnOpWithSrc(Register ResVReg
,
627 const SPIRVType
*ResType
,
630 unsigned Opcode
) const {
631 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(Opcode
))
633 .addUse(GR
.getSPIRVTypeID(ResType
))
635 .constrainAllUses(TII
, TRI
, RBI
);
638 bool SPIRVInstructionSelector::selectUnOp(Register ResVReg
,
639 const SPIRVType
*ResType
,
641 unsigned Opcode
) const {
642 return selectUnOpWithSrc(ResVReg
, ResType
, I
, I
.getOperand(1).getReg(),
646 bool SPIRVInstructionSelector::selectBitcast(Register ResVReg
,
647 const SPIRVType
*ResType
,
648 MachineInstr
&I
) const {
649 Register OpReg
= I
.getOperand(1).getReg();
650 SPIRVType
*OpType
= OpReg
.isValid() ? GR
.getSPIRVTypeForVReg(OpReg
) : nullptr;
651 if (!GR
.isBitcastCompatible(ResType
, OpType
))
652 report_fatal_error("incompatible result and operand types in a bitcast");
653 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpBitcast
);
656 static SPIRV::Scope::Scope
getScope(SyncScope::ID Ord
,
657 SPIRVMachineModuleInfo
*MMI
) {
658 if (Ord
== SyncScope::SingleThread
|| Ord
== MMI
->Work_ItemSSID
)
659 return SPIRV::Scope::Invocation
;
660 else if (Ord
== SyncScope::System
|| Ord
== MMI
->DeviceSSID
)
661 return SPIRV::Scope::Device
;
662 else if (Ord
== MMI
->WorkGroupSSID
)
663 return SPIRV::Scope::Workgroup
;
664 else if (Ord
== MMI
->AllSVMDevicesSSID
)
665 return SPIRV::Scope::CrossDevice
;
666 else if (Ord
== MMI
->SubGroupSSID
)
667 return SPIRV::Scope::Subgroup
;
669 // OpenCL approach is: "The functions that do not have memory_scope argument
670 // have the same semantics as the corresponding functions with the
671 // memory_scope argument set to memory_scope_device." See ref.: //
672 // https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_C.html#atomic-functions
673 // In our case if the scope is unknown, assuming that SPIR-V code is to be
674 // consumed in an OpenCL environment, we use the same approach and set the
675 // scope to memory_scope_device.
676 return SPIRV::Scope::Device
;
679 static void addMemoryOperands(MachineMemOperand
*MemOp
,
680 MachineInstrBuilder
&MIB
) {
681 uint32_t SpvMemOp
= static_cast<uint32_t>(SPIRV::MemoryOperand::None
);
682 if (MemOp
->isVolatile())
683 SpvMemOp
|= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile
);
684 if (MemOp
->isNonTemporal())
685 SpvMemOp
|= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal
);
686 if (MemOp
->getAlign().value())
687 SpvMemOp
|= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned
);
689 if (SpvMemOp
!= static_cast<uint32_t>(SPIRV::MemoryOperand::None
)) {
690 MIB
.addImm(SpvMemOp
);
691 if (SpvMemOp
& static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned
))
692 MIB
.addImm(MemOp
->getAlign().value());
696 static void addMemoryOperands(uint64_t Flags
, MachineInstrBuilder
&MIB
) {
697 uint32_t SpvMemOp
= static_cast<uint32_t>(SPIRV::MemoryOperand::None
);
698 if (Flags
& MachineMemOperand::Flags::MOVolatile
)
699 SpvMemOp
|= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile
);
700 if (Flags
& MachineMemOperand::Flags::MONonTemporal
)
701 SpvMemOp
|= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal
);
703 if (SpvMemOp
!= static_cast<uint32_t>(SPIRV::MemoryOperand::None
))
704 MIB
.addImm(SpvMemOp
);
707 bool SPIRVInstructionSelector::selectLoad(Register ResVReg
,
708 const SPIRVType
*ResType
,
709 MachineInstr
&I
) const {
710 unsigned OpOffset
= isa
<GIntrinsic
>(I
) ? 1 : 0;
711 Register Ptr
= I
.getOperand(1 + OpOffset
).getReg();
712 auto MIB
= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(SPIRV::OpLoad
))
714 .addUse(GR
.getSPIRVTypeID(ResType
))
716 if (!I
.getNumMemOperands()) {
717 assert(I
.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS
||
719 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS
);
720 addMemoryOperands(I
.getOperand(2 + OpOffset
).getImm(), MIB
);
722 addMemoryOperands(*I
.memoperands_begin(), MIB
);
724 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
727 bool SPIRVInstructionSelector::selectStore(MachineInstr
&I
) const {
728 unsigned OpOffset
= isa
<GIntrinsic
>(I
) ? 1 : 0;
729 Register StoreVal
= I
.getOperand(0 + OpOffset
).getReg();
730 Register Ptr
= I
.getOperand(1 + OpOffset
).getReg();
731 MachineBasicBlock
&BB
= *I
.getParent();
732 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpStore
))
735 if (!I
.getNumMemOperands()) {
736 assert(I
.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS
||
738 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS
);
739 addMemoryOperands(I
.getOperand(2 + OpOffset
).getImm(), MIB
);
741 addMemoryOperands(*I
.memoperands_begin(), MIB
);
743 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
746 bool SPIRVInstructionSelector::selectStackSave(Register ResVReg
,
747 const SPIRVType
*ResType
,
748 MachineInstr
&I
) const {
749 if (!STI
.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array
))
751 "llvm.stacksave intrinsic: this instruction requires the following "
752 "SPIR-V extension: SPV_INTEL_variable_length_array",
754 MachineBasicBlock
&BB
= *I
.getParent();
755 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpSaveMemoryINTEL
))
757 .addUse(GR
.getSPIRVTypeID(ResType
))
758 .constrainAllUses(TII
, TRI
, RBI
);
761 bool SPIRVInstructionSelector::selectStackRestore(MachineInstr
&I
) const {
762 if (!STI
.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array
))
764 "llvm.stackrestore intrinsic: this instruction requires the following "
765 "SPIR-V extension: SPV_INTEL_variable_length_array",
767 if (!I
.getOperand(0).isReg())
769 MachineBasicBlock
&BB
= *I
.getParent();
770 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpRestoreMemoryINTEL
))
771 .addUse(I
.getOperand(0).getReg())
772 .constrainAllUses(TII
, TRI
, RBI
);
775 bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg
,
776 MachineInstr
&I
) const {
777 MachineBasicBlock
&BB
= *I
.getParent();
778 Register SrcReg
= I
.getOperand(1).getReg();
779 if (I
.getOpcode() == TargetOpcode::G_MEMSET
) {
780 assert(I
.getOperand(1).isReg() && I
.getOperand(2).isReg());
781 unsigned Val
= getIConstVal(I
.getOperand(1).getReg(), MRI
);
782 unsigned Num
= getIConstVal(I
.getOperand(2).getReg(), MRI
);
783 SPIRVType
*ValTy
= GR
.getOrCreateSPIRVIntegerType(8, I
, TII
);
784 SPIRVType
*ArrTy
= GR
.getOrCreateSPIRVArrayType(ValTy
, Num
, I
, TII
);
785 Register Const
= GR
.getOrCreateConsIntArray(Val
, I
, ArrTy
, TII
);
786 SPIRVType
*VarTy
= GR
.getOrCreateSPIRVPointerType(
787 ArrTy
, I
, TII
, SPIRV::StorageClass::UniformConstant
);
788 // TODO: check if we have such GV, add init, use buildGlobalVariable.
789 Function
&CurFunction
= GR
.CurMF
->getFunction();
791 ArrayType::get(IntegerType::get(CurFunction
.getContext(), 8), Num
);
792 // Module takes ownership of the global var.
793 GlobalVariable
*GV
= new GlobalVariable(*CurFunction
.getParent(), LLVMArrTy
,
794 true, GlobalValue::InternalLinkage
,
795 Constant::getNullValue(LLVMArrTy
));
796 Register VarReg
= MRI
->createGenericVirtualRegister(LLT::scalar(32));
797 GR
.add(GV
, GR
.CurMF
, VarReg
);
799 buildOpDecorate(VarReg
, I
, TII
, SPIRV::Decoration::Constant
, {});
800 BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(SPIRV::OpVariable
))
802 .addUse(GR
.getSPIRVTypeID(VarTy
))
803 .addImm(SPIRV::StorageClass::UniformConstant
)
805 .constrainAllUses(TII
, TRI
, RBI
);
806 SPIRVType
*SourceTy
= GR
.getOrCreateSPIRVPointerType(
807 ValTy
, I
, TII
, SPIRV::StorageClass::UniformConstant
);
808 SrcReg
= MRI
->createGenericVirtualRegister(LLT::scalar(32));
809 selectUnOpWithSrc(SrcReg
, SourceTy
, I
, VarReg
, SPIRV::OpBitcast
);
811 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpCopyMemorySized
))
812 .addUse(I
.getOperand(0).getReg())
814 .addUse(I
.getOperand(2).getReg());
815 if (I
.getNumMemOperands())
816 addMemoryOperands(*I
.memoperands_begin(), MIB
);
817 bool Result
= MIB
.constrainAllUses(TII
, TRI
, RBI
);
818 if (ResVReg
.isValid() && ResVReg
!= MIB
->getOperand(0).getReg())
819 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(TargetOpcode::COPY
), ResVReg
)
820 .addUse(MIB
->getOperand(0).getReg());
824 bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg
,
825 const SPIRVType
*ResType
,
828 unsigned NegateOpcode
) const {
829 assert(I
.hasOneMemOperand());
830 const MachineMemOperand
*MemOp
= *I
.memoperands_begin();
832 static_cast<uint32_t>(getScope(MemOp
->getSyncScopeID(), MMI
));
833 Register ScopeReg
= buildI32Constant(Scope
, I
);
835 Register Ptr
= I
.getOperand(1).getReg();
836 // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll
838 // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr));
839 AtomicOrdering AO
= MemOp
->getSuccessOrdering();
840 uint32_t MemSem
= static_cast<uint32_t>(getMemSemantics(AO
));
841 Register MemSemReg
= buildI32Constant(MemSem
/*| ScSem*/, I
);
844 Register ValueReg
= I
.getOperand(2).getReg();
845 if (NegateOpcode
!= 0) {
846 // Translation with negative value operand is requested
847 Register TmpReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
848 Result
|= selectUnOpWithSrc(TmpReg
, ResType
, I
, ValueReg
, NegateOpcode
);
852 Result
|= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(NewOpcode
))
854 .addUse(GR
.getSPIRVTypeID(ResType
))
859 .constrainAllUses(TII
, TRI
, RBI
);
863 bool SPIRVInstructionSelector::selectUnmergeValues(MachineInstr
&I
) const {
864 unsigned ArgI
= I
.getNumOperands() - 1;
866 I
.getOperand(ArgI
).isReg() ? I
.getOperand(ArgI
).getReg() : Register(0);
868 SrcReg
.isValid() ? GR
.getSPIRVTypeForVReg(SrcReg
) : nullptr;
869 if (!DefType
|| DefType
->getOpcode() != SPIRV::OpTypeVector
)
871 "cannot select G_UNMERGE_VALUES with a non-vector argument");
873 SPIRVType
*ScalarType
=
874 GR
.getSPIRVTypeForVReg(DefType
->getOperand(1).getReg());
875 MachineBasicBlock
&BB
= *I
.getParent();
877 for (unsigned i
= 0; i
< I
.getNumDefs(); ++i
) {
878 Register ResVReg
= I
.getOperand(i
).getReg();
879 SPIRVType
*ResType
= GR
.getSPIRVTypeForVReg(ResVReg
);
881 // There was no "assign type" actions, let's fix this now
882 ResType
= ScalarType
;
883 MRI
->setRegClass(ResVReg
, &SPIRV::IDRegClass
);
884 MRI
->setType(ResVReg
, LLT::scalar(GR
.getScalarOrVectorBitWidth(ResType
)));
885 GR
.assignSPIRVTypeToVReg(ResType
, ResVReg
, *GR
.CurMF
);
888 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpCompositeExtract
))
890 .addUse(GR
.getSPIRVTypeID(ResType
))
892 .addImm(static_cast<int64_t>(i
));
893 Res
|= MIB
.constrainAllUses(TII
, TRI
, RBI
);
898 bool SPIRVInstructionSelector::selectFence(MachineInstr
&I
) const {
899 AtomicOrdering AO
= AtomicOrdering(I
.getOperand(0).getImm());
900 uint32_t MemSem
= static_cast<uint32_t>(getMemSemantics(AO
));
901 Register MemSemReg
= buildI32Constant(MemSem
, I
);
902 SyncScope::ID Ord
= SyncScope::ID(I
.getOperand(1).getImm());
903 uint32_t Scope
= static_cast<uint32_t>(getScope(Ord
, MMI
));
904 Register ScopeReg
= buildI32Constant(Scope
, I
);
905 MachineBasicBlock
&BB
= *I
.getParent();
906 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpMemoryBarrier
))
909 .constrainAllUses(TII
, TRI
, RBI
);
912 bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg
,
913 const SPIRVType
*ResType
,
914 MachineInstr
&I
) const {
916 Register MemSemEqReg
;
917 Register MemSemNeqReg
;
918 Register Ptr
= I
.getOperand(2).getReg();
919 if (!isa
<GIntrinsic
>(I
)) {
920 assert(I
.hasOneMemOperand());
921 const MachineMemOperand
*MemOp
= *I
.memoperands_begin();
923 static_cast<uint32_t>(getScope(MemOp
->getSyncScopeID(), MMI
));
924 ScopeReg
= buildI32Constant(Scope
, I
);
926 unsigned ScSem
= static_cast<uint32_t>(
927 getMemSemanticsForStorageClass(GR
.getPointerStorageClass(Ptr
)));
928 AtomicOrdering AO
= MemOp
->getSuccessOrdering();
929 unsigned MemSemEq
= static_cast<uint32_t>(getMemSemantics(AO
)) | ScSem
;
930 MemSemEqReg
= buildI32Constant(MemSemEq
, I
);
931 AtomicOrdering FO
= MemOp
->getFailureOrdering();
932 unsigned MemSemNeq
= static_cast<uint32_t>(getMemSemantics(FO
)) | ScSem
;
934 MemSemEq
== MemSemNeq
? MemSemEqReg
: buildI32Constant(MemSemNeq
, I
);
936 ScopeReg
= I
.getOperand(5).getReg();
937 MemSemEqReg
= I
.getOperand(6).getReg();
938 MemSemNeqReg
= I
.getOperand(7).getReg();
941 Register Cmp
= I
.getOperand(3).getReg();
942 Register Val
= I
.getOperand(4).getReg();
943 SPIRVType
*SpvValTy
= GR
.getSPIRVTypeForVReg(Val
);
944 Register ACmpRes
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
945 const DebugLoc
&DL
= I
.getDebugLoc();
947 BuildMI(*I
.getParent(), I
, DL
, TII
.get(SPIRV::OpAtomicCompareExchange
))
949 .addUse(GR
.getSPIRVTypeID(SpvValTy
))
953 .addUse(MemSemNeqReg
)
956 .constrainAllUses(TII
, TRI
, RBI
);
957 Register CmpSuccReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
958 SPIRVType
*BoolTy
= GR
.getOrCreateSPIRVBoolType(I
, TII
);
959 Result
|= BuildMI(*I
.getParent(), I
, DL
, TII
.get(SPIRV::OpIEqual
))
961 .addUse(GR
.getSPIRVTypeID(BoolTy
))
964 .constrainAllUses(TII
, TRI
, RBI
);
965 Register TmpReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
966 Result
|= BuildMI(*I
.getParent(), I
, DL
, TII
.get(SPIRV::OpCompositeInsert
))
968 .addUse(GR
.getSPIRVTypeID(ResType
))
970 .addUse(GR
.getOrCreateUndef(I
, ResType
, TII
))
972 .constrainAllUses(TII
, TRI
, RBI
);
973 Result
|= BuildMI(*I
.getParent(), I
, DL
, TII
.get(SPIRV::OpCompositeInsert
))
975 .addUse(GR
.getSPIRVTypeID(ResType
))
979 .constrainAllUses(TII
, TRI
, RBI
);
983 static bool isGenericCastablePtr(SPIRV::StorageClass::StorageClass SC
) {
985 case SPIRV::StorageClass::Workgroup
:
986 case SPIRV::StorageClass::CrossWorkgroup
:
987 case SPIRV::StorageClass::Function
:
994 static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC
) {
996 case SPIRV::StorageClass::DeviceOnlyINTEL
:
997 case SPIRV::StorageClass::HostOnlyINTEL
:
1004 // In SPIR-V address space casting can only happen to and from the Generic
1005 // storage class. We can also only cast Workgroup, CrossWorkgroup, or Function
1006 // pointers to and from Generic pointers. As such, we can convert e.g. from
1007 // Workgroup to Function by going via a Generic pointer as an intermediary. All
1008 // other combinations can only be done by a bitcast, and are probably not safe.
1009 bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg
,
1010 const SPIRVType
*ResType
,
1011 MachineInstr
&I
) const {
1012 // If the AddrSpaceCast user is single and in OpConstantComposite or
1013 // OpVariable, we should select OpSpecConstantOp.
1014 auto UIs
= MRI
->use_instructions(ResVReg
);
1015 if (!UIs
.empty() && ++UIs
.begin() == UIs
.end() &&
1016 (UIs
.begin()->getOpcode() == SPIRV::OpConstantComposite
||
1017 UIs
.begin()->getOpcode() == SPIRV::OpVariable
||
1018 isSpvIntrinsic(*UIs
.begin(), Intrinsic::spv_init_global
))) {
1019 Register NewReg
= I
.getOperand(1).getReg();
1020 MachineBasicBlock
&BB
= *I
.getParent();
1021 SPIRVType
*SpvBaseTy
= GR
.getOrCreateSPIRVIntegerType(8, I
, TII
);
1022 ResType
= GR
.getOrCreateSPIRVPointerType(SpvBaseTy
, I
, TII
,
1023 SPIRV::StorageClass::Generic
);
1025 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpSpecConstantOp
))
1027 .addUse(GR
.getSPIRVTypeID(ResType
))
1028 .addImm(static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric
))
1030 .constrainAllUses(TII
, TRI
, RBI
);
1033 Register SrcPtr
= I
.getOperand(1).getReg();
1034 SPIRVType
*SrcPtrTy
= GR
.getSPIRVTypeForVReg(SrcPtr
);
1035 SPIRV::StorageClass::StorageClass SrcSC
= GR
.getPointerStorageClass(SrcPtr
);
1036 SPIRV::StorageClass::StorageClass DstSC
= GR
.getPointerStorageClass(ResVReg
);
1038 // don't generate a cast between identical storage classes
1042 // Casting from an eligible pointer to Generic.
1043 if (DstSC
== SPIRV::StorageClass::Generic
&& isGenericCastablePtr(SrcSC
))
1044 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpPtrCastToGeneric
);
1045 // Casting from Generic to an eligible pointer.
1046 if (SrcSC
== SPIRV::StorageClass::Generic
&& isGenericCastablePtr(DstSC
))
1047 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpGenericCastToPtr
);
1048 // Casting between 2 eligible pointers using Generic as an intermediary.
1049 if (isGenericCastablePtr(SrcSC
) && isGenericCastablePtr(DstSC
)) {
1050 Register Tmp
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1051 SPIRVType
*GenericPtrTy
= GR
.getOrCreateSPIRVPointerType(
1052 SrcPtrTy
, I
, TII
, SPIRV::StorageClass::Generic
);
1053 MachineBasicBlock
&BB
= *I
.getParent();
1054 const DebugLoc
&DL
= I
.getDebugLoc();
1055 bool Success
= BuildMI(BB
, I
, DL
, TII
.get(SPIRV::OpPtrCastToGeneric
))
1057 .addUse(GR
.getSPIRVTypeID(GenericPtrTy
))
1059 .constrainAllUses(TII
, TRI
, RBI
);
1060 return Success
&& BuildMI(BB
, I
, DL
, TII
.get(SPIRV::OpGenericCastToPtr
))
1062 .addUse(GR
.getSPIRVTypeID(ResType
))
1064 .constrainAllUses(TII
, TRI
, RBI
);
1067 // Check if instructions from the SPV_INTEL_usm_storage_classes extension may
1069 if (isUSMStorageClass(SrcSC
) && DstSC
== SPIRV::StorageClass::CrossWorkgroup
)
1070 return selectUnOp(ResVReg
, ResType
, I
,
1071 SPIRV::OpPtrCastToCrossWorkgroupINTEL
);
1072 if (SrcSC
== SPIRV::StorageClass::CrossWorkgroup
&& isUSMStorageClass(DstSC
))
1073 return selectUnOp(ResVReg
, ResType
, I
,
1074 SPIRV::OpCrossWorkgroupCastToPtrINTEL
);
1076 // TODO Should this case just be disallowed completely?
1077 // We're casting 2 other arbitrary address spaces, so have to bitcast.
1078 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpBitcast
);
1081 static unsigned getFCmpOpcode(unsigned PredNum
) {
1082 auto Pred
= static_cast<CmpInst::Predicate
>(PredNum
);
1084 case CmpInst::FCMP_OEQ
:
1085 return SPIRV::OpFOrdEqual
;
1086 case CmpInst::FCMP_OGE
:
1087 return SPIRV::OpFOrdGreaterThanEqual
;
1088 case CmpInst::FCMP_OGT
:
1089 return SPIRV::OpFOrdGreaterThan
;
1090 case CmpInst::FCMP_OLE
:
1091 return SPIRV::OpFOrdLessThanEqual
;
1092 case CmpInst::FCMP_OLT
:
1093 return SPIRV::OpFOrdLessThan
;
1094 case CmpInst::FCMP_ONE
:
1095 return SPIRV::OpFOrdNotEqual
;
1096 case CmpInst::FCMP_ORD
:
1097 return SPIRV::OpOrdered
;
1098 case CmpInst::FCMP_UEQ
:
1099 return SPIRV::OpFUnordEqual
;
1100 case CmpInst::FCMP_UGE
:
1101 return SPIRV::OpFUnordGreaterThanEqual
;
1102 case CmpInst::FCMP_UGT
:
1103 return SPIRV::OpFUnordGreaterThan
;
1104 case CmpInst::FCMP_ULE
:
1105 return SPIRV::OpFUnordLessThanEqual
;
1106 case CmpInst::FCMP_ULT
:
1107 return SPIRV::OpFUnordLessThan
;
1108 case CmpInst::FCMP_UNE
:
1109 return SPIRV::OpFUnordNotEqual
;
1110 case CmpInst::FCMP_UNO
:
1111 return SPIRV::OpUnordered
;
1113 llvm_unreachable("Unknown predicate type for FCmp");
1117 static unsigned getICmpOpcode(unsigned PredNum
) {
1118 auto Pred
= static_cast<CmpInst::Predicate
>(PredNum
);
1120 case CmpInst::ICMP_EQ
:
1121 return SPIRV::OpIEqual
;
1122 case CmpInst::ICMP_NE
:
1123 return SPIRV::OpINotEqual
;
1124 case CmpInst::ICMP_SGE
:
1125 return SPIRV::OpSGreaterThanEqual
;
1126 case CmpInst::ICMP_SGT
:
1127 return SPIRV::OpSGreaterThan
;
1128 case CmpInst::ICMP_SLE
:
1129 return SPIRV::OpSLessThanEqual
;
1130 case CmpInst::ICMP_SLT
:
1131 return SPIRV::OpSLessThan
;
1132 case CmpInst::ICMP_UGE
:
1133 return SPIRV::OpUGreaterThanEqual
;
1134 case CmpInst::ICMP_UGT
:
1135 return SPIRV::OpUGreaterThan
;
1136 case CmpInst::ICMP_ULE
:
1137 return SPIRV::OpULessThanEqual
;
1138 case CmpInst::ICMP_ULT
:
1139 return SPIRV::OpULessThan
;
1141 llvm_unreachable("Unknown predicate type for ICmp");
1145 static unsigned getPtrCmpOpcode(unsigned Pred
) {
1146 switch (static_cast<CmpInst::Predicate
>(Pred
)) {
1147 case CmpInst::ICMP_EQ
:
1148 return SPIRV::OpPtrEqual
;
1149 case CmpInst::ICMP_NE
:
1150 return SPIRV::OpPtrNotEqual
;
1152 llvm_unreachable("Unknown predicate type for pointer comparison");
1156 // Return the logical operation, or abort if none exists.
1157 static unsigned getBoolCmpOpcode(unsigned PredNum
) {
1158 auto Pred
= static_cast<CmpInst::Predicate
>(PredNum
);
1160 case CmpInst::ICMP_EQ
:
1161 return SPIRV::OpLogicalEqual
;
1162 case CmpInst::ICMP_NE
:
1163 return SPIRV::OpLogicalNotEqual
;
1165 llvm_unreachable("Unknown predicate type for Bool comparison");
1169 bool SPIRVInstructionSelector::selectAnyOrAll(Register ResVReg
,
1170 const SPIRVType
*ResType
,
1172 unsigned OpAnyOrAll
) const {
1173 assert(I
.getNumOperands() == 3);
1174 assert(I
.getOperand(2).isReg());
1175 MachineBasicBlock
&BB
= *I
.getParent();
1176 Register InputRegister
= I
.getOperand(2).getReg();
1177 SPIRVType
*InputType
= GR
.getSPIRVTypeForVReg(InputRegister
);
1180 report_fatal_error("Input Type could not be determined.");
1182 bool IsBoolTy
= GR
.isScalarOrVectorOfType(InputRegister
, SPIRV::OpTypeBool
);
1183 bool IsVectorTy
= InputType
->getOpcode() == SPIRV::OpTypeVector
;
1184 if (IsBoolTy
&& !IsVectorTy
) {
1185 assert(ResVReg
== I
.getOperand(0).getReg());
1186 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(),
1187 TII
.get(TargetOpcode::COPY
))
1189 .addUse(InputRegister
)
1190 .constrainAllUses(TII
, TRI
, RBI
);
1193 bool IsFloatTy
= GR
.isScalarOrVectorOfType(InputRegister
, SPIRV::OpTypeFloat
);
1194 unsigned SpirvNotEqualId
=
1195 IsFloatTy
? SPIRV::OpFOrdNotEqual
: SPIRV::OpINotEqual
;
1196 SPIRVType
*SpvBoolScalarTy
= GR
.getOrCreateSPIRVBoolType(I
, TII
);
1197 SPIRVType
*SpvBoolTy
= SpvBoolScalarTy
;
1198 Register NotEqualReg
= ResVReg
;
1201 NotEqualReg
= IsBoolTy
? InputRegister
1202 : MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1203 const unsigned NumElts
= InputType
->getOperand(2).getImm();
1204 SpvBoolTy
= GR
.getOrCreateSPIRVVectorType(SpvBoolTy
, NumElts
, I
, TII
);
1208 Register ConstZeroReg
=
1209 IsFloatTy
? buildZerosValF(InputType
, I
) : buildZerosVal(InputType
, I
);
1211 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SpirvNotEqualId
))
1212 .addDef(NotEqualReg
)
1213 .addUse(GR
.getSPIRVTypeID(SpvBoolTy
))
1214 .addUse(InputRegister
)
1215 .addUse(ConstZeroReg
)
1216 .constrainAllUses(TII
, TRI
, RBI
);
1222 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(OpAnyOrAll
))
1224 .addUse(GR
.getSPIRVTypeID(SpvBoolScalarTy
))
1225 .addUse(NotEqualReg
)
1226 .constrainAllUses(TII
, TRI
, RBI
);
1229 bool SPIRVInstructionSelector::selectAll(Register ResVReg
,
1230 const SPIRVType
*ResType
,
1231 MachineInstr
&I
) const {
1232 return selectAnyOrAll(ResVReg
, ResType
, I
, SPIRV::OpAll
);
1235 bool SPIRVInstructionSelector::selectAny(Register ResVReg
,
1236 const SPIRVType
*ResType
,
1237 MachineInstr
&I
) const {
1238 return selectAnyOrAll(ResVReg
, ResType
, I
, SPIRV::OpAny
);
1241 bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg
,
1242 const SPIRVType
*ResType
,
1243 MachineInstr
&I
) const {
1244 MachineBasicBlock
&BB
= *I
.getParent();
1245 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpBitReverse
))
1247 .addUse(GR
.getSPIRVTypeID(ResType
))
1248 .addUse(I
.getOperand(1).getReg())
1249 .constrainAllUses(TII
, TRI
, RBI
);
1252 bool SPIRVInstructionSelector::selectFreeze(Register ResVReg
,
1253 const SPIRVType
*ResType
,
1254 MachineInstr
&I
) const {
1255 // There is no way to implement `freeze` correctly without support on SPIR-V
1256 // standard side, but we may at least address a simple (static) case when
1257 // undef/poison value presence is obvious. The main benefit of even
1258 // incomplete `freeze` support is preventing of translation from crashing due
1259 // to lack of support on legalization and instruction selection steps.
1260 if (!I
.getOperand(0).isReg() || !I
.getOperand(1).isReg())
1262 Register OpReg
= I
.getOperand(1).getReg();
1263 if (MachineInstr
*Def
= MRI
->getVRegDef(OpReg
)) {
1265 switch (Def
->getOpcode()) {
1266 case SPIRV::ASSIGN_TYPE
:
1267 if (MachineInstr
*AssignToDef
=
1268 MRI
->getVRegDef(Def
->getOperand(1).getReg())) {
1269 if (AssignToDef
->getOpcode() == TargetOpcode::G_IMPLICIT_DEF
)
1270 Reg
= Def
->getOperand(2).getReg();
1273 case SPIRV::OpUndef
:
1274 Reg
= Def
->getOperand(1).getReg();
1277 unsigned DestOpCode
;
1278 if (Reg
.isValid()) {
1279 DestOpCode
= SPIRV::OpConstantNull
;
1281 DestOpCode
= TargetOpcode::COPY
;
1284 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(DestOpCode
))
1285 .addDef(I
.getOperand(0).getReg())
1287 .constrainAllUses(TII
, TRI
, RBI
);
1292 bool SPIRVInstructionSelector::selectConstVector(Register ResVReg
,
1293 const SPIRVType
*ResType
,
1294 MachineInstr
&I
) const {
1295 // TODO: only const case is supported for now.
1297 I
.operands_begin(), I
.operands_end(), [this](const MachineOperand
&MO
) {
1302 SPIRVType
*ConstTy
= this->MRI
->getVRegDef(MO
.getReg());
1303 assert(ConstTy
&& ConstTy
->getOpcode() == SPIRV::ASSIGN_TYPE
&&
1304 ConstTy
->getOperand(1).isReg());
1305 Register ConstReg
= ConstTy
->getOperand(1).getReg();
1306 const MachineInstr
*Const
= this->MRI
->getVRegDef(ConstReg
);
1308 return (Const
->getOpcode() == TargetOpcode::G_CONSTANT
||
1309 Const
->getOpcode() == TargetOpcode::G_FCONSTANT
);
1312 auto MIB
= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(),
1313 TII
.get(SPIRV::OpConstantComposite
))
1315 .addUse(GR
.getSPIRVTypeID(ResType
));
1316 for (unsigned i
= I
.getNumExplicitDefs(); i
< I
.getNumExplicitOperands(); ++i
)
1317 MIB
.addUse(I
.getOperand(i
).getReg());
1318 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1321 static unsigned getArrayComponentCount(MachineRegisterInfo
*MRI
,
1322 const SPIRVType
*ResType
) {
1323 Register OpReg
= ResType
->getOperand(2).getReg();
1324 SPIRVType
*OpDef
= MRI
->getVRegDef(OpReg
);
1327 if (OpDef
->getOpcode() == SPIRV::ASSIGN_TYPE
&&
1328 OpDef
->getOperand(1).isReg()) {
1329 if (SPIRVType
*RefDef
= MRI
->getVRegDef(OpDef
->getOperand(1).getReg()))
1332 unsigned N
= OpDef
->getOpcode() == TargetOpcode::G_CONSTANT
1333 ? OpDef
->getOperand(1).getCImm()->getValue().getZExtValue()
1338 // Return true if the type represents a constant register
1339 static bool isConstReg(MachineRegisterInfo
*MRI
, SPIRVType
*OpDef
) {
1340 if (OpDef
->getOpcode() == SPIRV::ASSIGN_TYPE
&&
1341 OpDef
->getOperand(1).isReg()) {
1342 if (SPIRVType
*RefDef
= MRI
->getVRegDef(OpDef
->getOperand(1).getReg()))
1345 return OpDef
->getOpcode() == TargetOpcode::G_CONSTANT
||
1346 OpDef
->getOpcode() == TargetOpcode::G_FCONSTANT
;
1349 // Return true if the virtual register represents a constant
1350 static bool isConstReg(MachineRegisterInfo
*MRI
, Register OpReg
) {
1351 if (SPIRVType
*OpDef
= MRI
->getVRegDef(OpReg
))
1352 return isConstReg(MRI
, OpDef
);
1356 bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg
,
1357 const SPIRVType
*ResType
,
1358 MachineInstr
&I
) const {
1360 if (ResType
->getOpcode() == SPIRV::OpTypeVector
)
1361 N
= GR
.getScalarOrVectorComponentCount(ResType
);
1362 else if (ResType
->getOpcode() == SPIRV::OpTypeArray
)
1363 N
= getArrayComponentCount(MRI
, ResType
);
1365 report_fatal_error("Cannot select G_SPLAT_VECTOR with a non-vector result");
1367 unsigned OpIdx
= I
.getNumExplicitDefs();
1368 if (!I
.getOperand(OpIdx
).isReg())
1369 report_fatal_error("Unexpected argument in G_SPLAT_VECTOR");
1371 // check if we may construct a constant vector
1372 Register OpReg
= I
.getOperand(OpIdx
).getReg();
1373 bool IsConst
= isConstReg(MRI
, OpReg
);
1375 if (!IsConst
&& N
< 2)
1377 "There must be at least two constituent operands in a vector");
1379 auto MIB
= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(),
1380 TII
.get(IsConst
? SPIRV::OpConstantComposite
1381 : SPIRV::OpCompositeConstruct
))
1383 .addUse(GR
.getSPIRVTypeID(ResType
));
1384 for (unsigned i
= 0; i
< N
; ++i
)
1386 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1389 bool SPIRVInstructionSelector::selectCmp(Register ResVReg
,
1390 const SPIRVType
*ResType
,
1392 MachineInstr
&I
) const {
1393 Register Cmp0
= I
.getOperand(2).getReg();
1394 Register Cmp1
= I
.getOperand(3).getReg();
1395 assert(GR
.getSPIRVTypeForVReg(Cmp0
)->getOpcode() ==
1396 GR
.getSPIRVTypeForVReg(Cmp1
)->getOpcode() &&
1397 "CMP operands should have the same type");
1398 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(CmpOpc
))
1400 .addUse(GR
.getSPIRVTypeID(ResType
))
1403 .constrainAllUses(TII
, TRI
, RBI
);
1406 bool SPIRVInstructionSelector::selectICmp(Register ResVReg
,
1407 const SPIRVType
*ResType
,
1408 MachineInstr
&I
) const {
1409 auto Pred
= I
.getOperand(1).getPredicate();
1412 Register CmpOperand
= I
.getOperand(2).getReg();
1413 if (GR
.isScalarOfType(CmpOperand
, SPIRV::OpTypePointer
))
1414 CmpOpc
= getPtrCmpOpcode(Pred
);
1415 else if (GR
.isScalarOrVectorOfType(CmpOperand
, SPIRV::OpTypeBool
))
1416 CmpOpc
= getBoolCmpOpcode(Pred
);
1418 CmpOpc
= getICmpOpcode(Pred
);
1419 return selectCmp(ResVReg
, ResType
, CmpOpc
, I
);
1422 void SPIRVInstructionSelector::renderFImm32(MachineInstrBuilder
&MIB
,
1423 const MachineInstr
&I
,
1425 assert(I
.getOpcode() == TargetOpcode::G_FCONSTANT
&& OpIdx
== -1 &&
1426 "Expected G_FCONSTANT");
1427 const ConstantFP
*FPImm
= I
.getOperand(1).getFPImm();
1428 addNumImm(FPImm
->getValueAPF().bitcastToAPInt(), MIB
);
1431 void SPIRVInstructionSelector::renderImm32(MachineInstrBuilder
&MIB
,
1432 const MachineInstr
&I
,
1434 assert(I
.getOpcode() == TargetOpcode::G_CONSTANT
&& OpIdx
== -1 &&
1435 "Expected G_CONSTANT");
1436 addNumImm(I
.getOperand(1).getCImm()->getValue(), MIB
);
1440 SPIRVInstructionSelector::buildI32Constant(uint32_t Val
, MachineInstr
&I
,
1441 const SPIRVType
*ResType
) const {
1442 Type
*LLVMTy
= IntegerType::get(GR
.CurMF
->getFunction().getContext(), 32);
1443 const SPIRVType
*SpvI32Ty
=
1444 ResType
? ResType
: GR
.getOrCreateSPIRVIntegerType(32, I
, TII
);
1445 // Find a constant in DT or build a new one.
1446 auto ConstInt
= ConstantInt::get(LLVMTy
, Val
);
1447 Register NewReg
= GR
.find(ConstInt
, GR
.CurMF
);
1448 if (!NewReg
.isValid()) {
1449 NewReg
= MRI
->createGenericVirtualRegister(LLT::scalar(32));
1450 GR
.add(ConstInt
, GR
.CurMF
, NewReg
);
1452 MachineBasicBlock
&BB
= *I
.getParent();
1454 MI
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpConstantNull
))
1456 .addUse(GR
.getSPIRVTypeID(SpvI32Ty
));
1458 MI
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpConstantI
))
1460 .addUse(GR
.getSPIRVTypeID(SpvI32Ty
))
1461 .addImm(APInt(32, Val
).getZExtValue());
1463 constrainSelectedInstRegOperands(*MI
, TII
, TRI
, RBI
);
1468 bool SPIRVInstructionSelector::selectFCmp(Register ResVReg
,
1469 const SPIRVType
*ResType
,
1470 MachineInstr
&I
) const {
1471 unsigned CmpOp
= getFCmpOpcode(I
.getOperand(1).getPredicate());
1472 return selectCmp(ResVReg
, ResType
, CmpOp
, I
);
1475 Register
SPIRVInstructionSelector::buildZerosVal(const SPIRVType
*ResType
,
1476 MachineInstr
&I
) const {
1477 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
1478 bool ZeroAsNull
= STI
.isOpenCLEnv();
1479 if (ResType
->getOpcode() == SPIRV::OpTypeVector
)
1480 return GR
.getOrCreateConstVector(0UL, I
, ResType
, TII
, ZeroAsNull
);
1481 return GR
.getOrCreateConstInt(0, I
, ResType
, TII
, ZeroAsNull
);
1484 static APFloat
getZeroFP(const Type
*LLVMFloatTy
) {
1486 return APFloat::getZero(APFloat::IEEEsingle());
1487 switch (LLVMFloatTy
->getScalarType()->getTypeID()) {
1488 case Type::HalfTyID
:
1489 return APFloat::getZero(APFloat::IEEEhalf());
1491 case Type::FloatTyID
:
1492 return APFloat::getZero(APFloat::IEEEsingle());
1493 case Type::DoubleTyID
:
1494 return APFloat::getZero(APFloat::IEEEdouble());
1498 Register
SPIRVInstructionSelector::buildZerosValF(const SPIRVType
*ResType
,
1499 MachineInstr
&I
) const {
1500 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
1501 bool ZeroAsNull
= STI
.isOpenCLEnv();
1502 APFloat VZero
= getZeroFP(GR
.getTypeForSPIRVType(ResType
));
1503 if (ResType
->getOpcode() == SPIRV::OpTypeVector
)
1504 return GR
.getOrCreateConstVector(VZero
, I
, ResType
, TII
, ZeroAsNull
);
1505 return GR
.getOrCreateConstFP(VZero
, I
, ResType
, TII
, ZeroAsNull
);
1508 Register
SPIRVInstructionSelector::buildOnesVal(bool AllOnes
,
1509 const SPIRVType
*ResType
,
1510 MachineInstr
&I
) const {
1511 unsigned BitWidth
= GR
.getScalarOrVectorBitWidth(ResType
);
1513 AllOnes
? APInt::getAllOnes(BitWidth
) : APInt::getOneBitSet(BitWidth
, 0);
1514 if (ResType
->getOpcode() == SPIRV::OpTypeVector
)
1515 return GR
.getOrCreateConstVector(One
.getZExtValue(), I
, ResType
, TII
);
1516 return GR
.getOrCreateConstInt(One
.getZExtValue(), I
, ResType
, TII
);
1519 bool SPIRVInstructionSelector::selectSelect(Register ResVReg
,
1520 const SPIRVType
*ResType
,
1522 bool IsSigned
) const {
1523 // To extend a bool, we need to use OpSelect between constants.
1524 Register ZeroReg
= buildZerosVal(ResType
, I
);
1525 Register OneReg
= buildOnesVal(IsSigned
, ResType
, I
);
1527 GR
.isScalarOfType(I
.getOperand(1).getReg(), SPIRV::OpTypeBool
);
1529 IsScalarBool
? SPIRV::OpSelectSISCond
: SPIRV::OpSelectSIVCond
;
1530 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(Opcode
))
1532 .addUse(GR
.getSPIRVTypeID(ResType
))
1533 .addUse(I
.getOperand(1).getReg())
1536 .constrainAllUses(TII
, TRI
, RBI
);
1539 bool SPIRVInstructionSelector::selectIToF(Register ResVReg
,
1540 const SPIRVType
*ResType
,
1541 MachineInstr
&I
, bool IsSigned
,
1542 unsigned Opcode
) const {
1543 Register SrcReg
= I
.getOperand(1).getReg();
1544 // We can convert bool value directly to float type without OpConvert*ToF,
1545 // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
1546 if (GR
.isScalarOrVectorOfType(I
.getOperand(1).getReg(), SPIRV::OpTypeBool
)) {
1547 unsigned BitWidth
= GR
.getScalarOrVectorBitWidth(ResType
);
1548 SPIRVType
*TmpType
= GR
.getOrCreateSPIRVIntegerType(BitWidth
, I
, TII
);
1549 if (ResType
->getOpcode() == SPIRV::OpTypeVector
) {
1550 const unsigned NumElts
= ResType
->getOperand(2).getImm();
1551 TmpType
= GR
.getOrCreateSPIRVVectorType(TmpType
, NumElts
, I
, TII
);
1553 SrcReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1554 selectSelect(SrcReg
, TmpType
, I
, false);
1556 return selectUnOpWithSrc(ResVReg
, ResType
, I
, SrcReg
, Opcode
);
1559 bool SPIRVInstructionSelector::selectExt(Register ResVReg
,
1560 const SPIRVType
*ResType
,
1561 MachineInstr
&I
, bool IsSigned
) const {
1562 if (GR
.isScalarOrVectorOfType(I
.getOperand(1).getReg(), SPIRV::OpTypeBool
))
1563 return selectSelect(ResVReg
, ResType
, I
, IsSigned
);
1564 unsigned Opcode
= IsSigned
? SPIRV::OpSConvert
: SPIRV::OpUConvert
;
1565 return selectUnOp(ResVReg
, ResType
, I
, Opcode
);
1568 bool SPIRVInstructionSelector::selectIntToBool(Register IntReg
,
1571 const SPIRVType
*IntTy
,
1572 const SPIRVType
*BoolTy
) const {
1573 // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
1574 Register BitIntReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1575 bool IsVectorTy
= IntTy
->getOpcode() == SPIRV::OpTypeVector
;
1576 unsigned Opcode
= IsVectorTy
? SPIRV::OpBitwiseAndV
: SPIRV::OpBitwiseAndS
;
1577 Register Zero
= buildZerosVal(IntTy
, I
);
1578 Register One
= buildOnesVal(false, IntTy
, I
);
1579 MachineBasicBlock
&BB
= *I
.getParent();
1580 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(Opcode
))
1582 .addUse(GR
.getSPIRVTypeID(IntTy
))
1585 .constrainAllUses(TII
, TRI
, RBI
);
1586 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpINotEqual
))
1588 .addUse(GR
.getSPIRVTypeID(BoolTy
))
1591 .constrainAllUses(TII
, TRI
, RBI
);
1594 bool SPIRVInstructionSelector::selectTrunc(Register ResVReg
,
1595 const SPIRVType
*ResType
,
1596 MachineInstr
&I
) const {
1597 if (GR
.isScalarOrVectorOfType(ResVReg
, SPIRV::OpTypeBool
)) {
1598 Register IntReg
= I
.getOperand(1).getReg();
1599 const SPIRVType
*ArgType
= GR
.getSPIRVTypeForVReg(IntReg
);
1600 return selectIntToBool(IntReg
, ResVReg
, I
, ArgType
, ResType
);
1602 bool IsSigned
= GR
.isScalarOrVectorSigned(ResType
);
1603 unsigned Opcode
= IsSigned
? SPIRV::OpSConvert
: SPIRV::OpUConvert
;
1604 return selectUnOp(ResVReg
, ResType
, I
, Opcode
);
1607 bool SPIRVInstructionSelector::selectConst(Register ResVReg
,
1608 const SPIRVType
*ResType
,
1610 MachineInstr
&I
) const {
1611 unsigned TyOpcode
= ResType
->getOpcode();
1612 assert(TyOpcode
!= SPIRV::OpTypePointer
|| Imm
.isZero());
1613 MachineBasicBlock
&BB
= *I
.getParent();
1614 if ((TyOpcode
== SPIRV::OpTypePointer
|| TyOpcode
== SPIRV::OpTypeEvent
) &&
1616 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpConstantNull
))
1618 .addUse(GR
.getSPIRVTypeID(ResType
))
1619 .constrainAllUses(TII
, TRI
, RBI
);
1620 if (TyOpcode
== SPIRV::OpTypeInt
) {
1621 assert(Imm
.getBitWidth() <= 64 && "Unsupported integer width!");
1622 Register Reg
= GR
.getOrCreateConstInt(Imm
.getZExtValue(), I
, ResType
, TII
);
1625 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(TargetOpcode::COPY
))
1628 .constrainAllUses(TII
, TRI
, RBI
);
1630 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpConstantI
))
1632 .addUse(GR
.getSPIRVTypeID(ResType
));
1633 // <=32-bit integers should be caught by the sdag pattern.
1634 assert(Imm
.getBitWidth() > 32);
1635 addNumImm(Imm
, MIB
);
1636 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1639 bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg
,
1640 const SPIRVType
*ResType
,
1641 MachineInstr
&I
) const {
1642 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(SPIRV::OpUndef
))
1644 .addUse(GR
.getSPIRVTypeID(ResType
))
1645 .constrainAllUses(TII
, TRI
, RBI
);
1648 static bool isImm(const MachineOperand
&MO
, MachineRegisterInfo
*MRI
) {
1650 const SPIRVType
*TypeInst
= MRI
->getVRegDef(MO
.getReg());
1651 if (TypeInst
->getOpcode() != SPIRV::ASSIGN_TYPE
)
1653 assert(TypeInst
->getOperand(1).isReg());
1654 MachineInstr
*ImmInst
= MRI
->getVRegDef(TypeInst
->getOperand(1).getReg());
1655 return ImmInst
->getOpcode() == TargetOpcode::G_CONSTANT
;
1658 static int64_t foldImm(const MachineOperand
&MO
, MachineRegisterInfo
*MRI
) {
1659 const SPIRVType
*TypeInst
= MRI
->getVRegDef(MO
.getReg());
1660 MachineInstr
*ImmInst
= MRI
->getVRegDef(TypeInst
->getOperand(1).getReg());
1661 assert(ImmInst
->getOpcode() == TargetOpcode::G_CONSTANT
);
1662 return ImmInst
->getOperand(1).getCImm()->getZExtValue();
1665 bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg
,
1666 const SPIRVType
*ResType
,
1667 MachineInstr
&I
) const {
1668 MachineBasicBlock
&BB
= *I
.getParent();
1669 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpCompositeInsert
))
1671 .addUse(GR
.getSPIRVTypeID(ResType
))
1673 .addUse(I
.getOperand(3).getReg())
1674 // composite to insert into
1675 .addUse(I
.getOperand(2).getReg());
1676 for (unsigned i
= 4; i
< I
.getNumOperands(); i
++)
1677 MIB
.addImm(foldImm(I
.getOperand(i
), MRI
));
1678 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1681 bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg
,
1682 const SPIRVType
*ResType
,
1683 MachineInstr
&I
) const {
1684 MachineBasicBlock
&BB
= *I
.getParent();
1685 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpCompositeExtract
))
1687 .addUse(GR
.getSPIRVTypeID(ResType
))
1688 .addUse(I
.getOperand(2).getReg());
1689 for (unsigned i
= 3; i
< I
.getNumOperands(); i
++)
1690 MIB
.addImm(foldImm(I
.getOperand(i
), MRI
));
1691 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1694 bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg
,
1695 const SPIRVType
*ResType
,
1696 MachineInstr
&I
) const {
1697 if (isImm(I
.getOperand(4), MRI
))
1698 return selectInsertVal(ResVReg
, ResType
, I
);
1699 MachineBasicBlock
&BB
= *I
.getParent();
1700 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpVectorInsertDynamic
))
1702 .addUse(GR
.getSPIRVTypeID(ResType
))
1703 .addUse(I
.getOperand(2).getReg())
1704 .addUse(I
.getOperand(3).getReg())
1705 .addUse(I
.getOperand(4).getReg())
1706 .constrainAllUses(TII
, TRI
, RBI
);
1709 bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg
,
1710 const SPIRVType
*ResType
,
1711 MachineInstr
&I
) const {
1712 if (isImm(I
.getOperand(3), MRI
))
1713 return selectExtractVal(ResVReg
, ResType
, I
);
1714 MachineBasicBlock
&BB
= *I
.getParent();
1715 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpVectorExtractDynamic
))
1717 .addUse(GR
.getSPIRVTypeID(ResType
))
1718 .addUse(I
.getOperand(2).getReg())
1719 .addUse(I
.getOperand(3).getReg())
1720 .constrainAllUses(TII
, TRI
, RBI
);
1723 bool SPIRVInstructionSelector::selectGEP(Register ResVReg
,
1724 const SPIRVType
*ResType
,
1725 MachineInstr
&I
) const {
1726 const bool IsGEPInBounds
= I
.getOperand(2).getImm();
1728 // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator only
1729 // relies on PtrAccessChain, so we'll try not to deviate. For Vulkan however,
1730 // we have to use Op[InBounds]AccessChain.
1731 const unsigned Opcode
= STI
.isVulkanEnv()
1732 ? (IsGEPInBounds
? SPIRV::OpInBoundsAccessChain
1733 : SPIRV::OpAccessChain
)
1734 : (IsGEPInBounds
? SPIRV::OpInBoundsPtrAccessChain
1735 : SPIRV::OpPtrAccessChain
);
1737 auto Res
= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(Opcode
))
1739 .addUse(GR
.getSPIRVTypeID(ResType
))
1740 // Object to get a pointer to.
1741 .addUse(I
.getOperand(3).getReg());
1743 const unsigned StartingIndex
=
1744 (Opcode
== SPIRV::OpAccessChain
|| Opcode
== SPIRV::OpInBoundsAccessChain
)
1747 for (unsigned i
= StartingIndex
; i
< I
.getNumExplicitOperands(); ++i
)
1748 Res
.addUse(I
.getOperand(i
).getReg());
1749 return Res
.constrainAllUses(TII
, TRI
, RBI
);
1752 // Maybe wrap a value into OpSpecConstantOp
1753 bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
1754 MachineInstr
&I
, SmallVector
<Register
> &CompositeArgs
) const {
1756 unsigned Lim
= I
.getNumExplicitOperands();
1757 for (unsigned i
= I
.getNumExplicitDefs() + 1; i
< Lim
; ++i
) {
1758 Register OpReg
= I
.getOperand(i
).getReg();
1759 SPIRVType
*OpDefine
= MRI
->getVRegDef(OpReg
);
1760 SPIRVType
*OpType
= GR
.getSPIRVTypeForVReg(OpReg
);
1761 if (!OpDefine
|| !OpType
|| isConstReg(MRI
, OpDefine
) ||
1762 OpDefine
->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST
) {
1763 // The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed
1764 // by selectAddrSpaceCast()
1765 CompositeArgs
.push_back(OpReg
);
1768 MachineFunction
*MF
= I
.getMF();
1769 Register WrapReg
= GR
.find(OpDefine
, MF
);
1770 if (WrapReg
.isValid()) {
1771 CompositeArgs
.push_back(WrapReg
);
1774 // Create a new register for the wrapper
1775 WrapReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1776 GR
.add(OpDefine
, MF
, WrapReg
);
1777 CompositeArgs
.push_back(WrapReg
);
1778 // Decorate the wrapper register and generate a new instruction
1779 MRI
->setType(WrapReg
, LLT::pointer(0, 32));
1780 GR
.assignSPIRVTypeToVReg(OpType
, WrapReg
, *MF
);
1781 MachineBasicBlock
&BB
= *I
.getParent();
1782 Result
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpSpecConstantOp
))
1784 .addUse(GR
.getSPIRVTypeID(OpType
))
1785 .addImm(static_cast<uint32_t>(SPIRV::Opcode::Bitcast
))
1787 .constrainAllUses(TII
, TRI
, RBI
);
1794 bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg
,
1795 const SPIRVType
*ResType
,
1796 MachineInstr
&I
) const {
1797 MachineBasicBlock
&BB
= *I
.getParent();
1798 Intrinsic::ID IID
= cast
<GIntrinsic
>(I
).getIntrinsicID();
1800 case Intrinsic::spv_load
:
1801 return selectLoad(ResVReg
, ResType
, I
);
1802 case Intrinsic::spv_store
:
1803 return selectStore(I
);
1804 case Intrinsic::spv_extractv
:
1805 return selectExtractVal(ResVReg
, ResType
, I
);
1806 case Intrinsic::spv_insertv
:
1807 return selectInsertVal(ResVReg
, ResType
, I
);
1808 case Intrinsic::spv_extractelt
:
1809 return selectExtractElt(ResVReg
, ResType
, I
);
1810 case Intrinsic::spv_insertelt
:
1811 return selectInsertElt(ResVReg
, ResType
, I
);
1812 case Intrinsic::spv_gep
:
1813 return selectGEP(ResVReg
, ResType
, I
);
1814 case Intrinsic::spv_unref_global
:
1815 case Intrinsic::spv_init_global
: {
1816 MachineInstr
*MI
= MRI
->getVRegDef(I
.getOperand(1).getReg());
1817 MachineInstr
*Init
= I
.getNumExplicitOperands() > 2
1818 ? MRI
->getVRegDef(I
.getOperand(2).getReg())
1821 return selectGlobalValue(MI
->getOperand(0).getReg(), *MI
, Init
);
1823 case Intrinsic::spv_undef
: {
1824 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpUndef
))
1826 .addUse(GR
.getSPIRVTypeID(ResType
));
1827 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1829 case Intrinsic::spv_const_composite
: {
1830 // If no values are attached, the composite is null constant.
1831 bool IsNull
= I
.getNumExplicitDefs() + 1 == I
.getNumExplicitOperands();
1832 // Select a proper instruction.
1833 unsigned Opcode
= SPIRV::OpConstantNull
;
1834 SmallVector
<Register
> CompositeArgs
;
1836 Opcode
= SPIRV::OpConstantComposite
;
1837 if (!wrapIntoSpecConstantOp(I
, CompositeArgs
))
1840 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(Opcode
))
1842 .addUse(GR
.getSPIRVTypeID(ResType
));
1843 // skip type MD node we already used when generated assign.type for this
1845 for (Register OpReg
: CompositeArgs
)
1848 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1850 case Intrinsic::spv_assign_name
: {
1851 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpName
));
1852 MIB
.addUse(I
.getOperand(I
.getNumExplicitDefs() + 1).getReg());
1853 for (unsigned i
= I
.getNumExplicitDefs() + 2;
1854 i
< I
.getNumExplicitOperands(); ++i
) {
1855 MIB
.addImm(I
.getOperand(i
).getImm());
1857 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1859 case Intrinsic::spv_switch
: {
1860 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpSwitch
));
1861 for (unsigned i
= 1; i
< I
.getNumExplicitOperands(); ++i
) {
1862 if (I
.getOperand(i
).isReg())
1863 MIB
.addReg(I
.getOperand(i
).getReg());
1864 else if (I
.getOperand(i
).isCImm())
1865 addNumImm(I
.getOperand(i
).getCImm()->getValue(), MIB
);
1866 else if (I
.getOperand(i
).isMBB())
1867 MIB
.addMBB(I
.getOperand(i
).getMBB());
1869 llvm_unreachable("Unexpected OpSwitch operand");
1871 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1873 case Intrinsic::spv_cmpxchg
:
1874 return selectAtomicCmpXchg(ResVReg
, ResType
, I
);
1875 case Intrinsic::spv_unreachable
:
1876 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpUnreachable
));
1878 case Intrinsic::spv_alloca
:
1879 return selectFrameIndex(ResVReg
, ResType
, I
);
1880 case Intrinsic::spv_alloca_array
:
1881 return selectAllocaArray(ResVReg
, ResType
, I
);
1882 case Intrinsic::spv_assume
:
1883 if (STI
.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume
))
1884 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpAssumeTrueKHR
))
1885 .addUse(I
.getOperand(1).getReg());
1887 case Intrinsic::spv_expect
:
1888 if (STI
.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume
))
1889 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpExpectKHR
))
1891 .addUse(GR
.getSPIRVTypeID(ResType
))
1892 .addUse(I
.getOperand(2).getReg())
1893 .addUse(I
.getOperand(3).getReg());
1895 case Intrinsic::spv_thread_id
:
1896 return selectSpvThreadId(ResVReg
, ResType
, I
);
1897 case Intrinsic::spv_all
:
1898 return selectAll(ResVReg
, ResType
, I
);
1899 case Intrinsic::spv_any
:
1900 return selectAny(ResVReg
, ResType
, I
);
1901 case Intrinsic::spv_lifetime_start
:
1902 case Intrinsic::spv_lifetime_end
: {
1903 unsigned Op
= IID
== Intrinsic::spv_lifetime_start
? SPIRV::OpLifetimeStart
1904 : SPIRV::OpLifetimeStop
;
1905 int64_t Size
= I
.getOperand(I
.getNumExplicitDefs() + 1).getImm();
1906 Register PtrReg
= I
.getOperand(I
.getNumExplicitDefs() + 2).getReg();
1907 unsigned PonteeOpType
= GR
.getPointeeTypeOp(PtrReg
);
1908 bool IsNonvoidPtr
= PonteeOpType
!= 0 && PonteeOpType
!= SPIRV::OpTypeVoid
;
1909 if (Size
== -1 || IsNonvoidPtr
)
1911 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(Op
)).addUse(PtrReg
).addImm(Size
);
1914 std::string DiagMsg
;
1915 raw_string_ostream
OS(DiagMsg
);
1917 DiagMsg
= "Intrinsic selection not implemented: " + DiagMsg
;
1918 report_fatal_error(DiagMsg
.c_str(), false);
1924 bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg
,
1925 const SPIRVType
*ResType
,
1926 MachineInstr
&I
) const {
1927 // there was an allocation size parameter to the allocation instruction
1929 MachineBasicBlock
&BB
= *I
.getParent();
1930 return BuildMI(BB
, I
, I
.getDebugLoc(),
1931 TII
.get(SPIRV::OpVariableLengthArrayINTEL
))
1933 .addUse(GR
.getSPIRVTypeID(ResType
))
1934 .addUse(I
.getOperand(2).getReg())
1935 .constrainAllUses(TII
, TRI
, RBI
);
1938 bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg
,
1939 const SPIRVType
*ResType
,
1940 MachineInstr
&I
) const {
1941 // Change order of instructions if needed: all OpVariable instructions in a
1942 // function must be the first instructions in the first block
1943 MachineFunction
*MF
= I
.getParent()->getParent();
1944 MachineBasicBlock
*MBB
= &MF
->front();
1945 auto It
= MBB
->SkipPHIsAndLabels(MBB
->begin()), E
= MBB
->end();
1946 bool IsHeader
= false;
1948 for (; It
!= E
&& It
!= I
; ++It
) {
1949 Opcode
= It
->getOpcode();
1950 if (Opcode
== SPIRV::OpFunction
|| Opcode
== SPIRV::OpFunctionParameter
) {
1952 } else if (IsHeader
&&
1953 !(Opcode
== SPIRV::ASSIGN_TYPE
|| Opcode
== SPIRV::OpLabel
)) {
1958 return BuildMI(*MBB
, It
, It
->getDebugLoc(), TII
.get(SPIRV::OpVariable
))
1960 .addUse(GR
.getSPIRVTypeID(ResType
))
1961 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function
))
1962 .constrainAllUses(TII
, TRI
, RBI
);
1965 bool SPIRVInstructionSelector::selectBranch(MachineInstr
&I
) const {
1966 // InstructionSelector walks backwards through the instructions. We can use
1967 // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
1968 // first, so can generate an OpBranchConditional here. If there is no
1969 // G_BRCOND, we just use OpBranch for a regular unconditional branch.
1970 const MachineInstr
*PrevI
= I
.getPrevNode();
1971 MachineBasicBlock
&MBB
= *I
.getParent();
1972 if (PrevI
!= nullptr && PrevI
->getOpcode() == TargetOpcode::G_BRCOND
) {
1973 return BuildMI(MBB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpBranchConditional
))
1974 .addUse(PrevI
->getOperand(0).getReg())
1975 .addMBB(PrevI
->getOperand(1).getMBB())
1976 .addMBB(I
.getOperand(0).getMBB())
1977 .constrainAllUses(TII
, TRI
, RBI
);
1979 return BuildMI(MBB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpBranch
))
1980 .addMBB(I
.getOperand(0).getMBB())
1981 .constrainAllUses(TII
, TRI
, RBI
);
1984 bool SPIRVInstructionSelector::selectBranchCond(MachineInstr
&I
) const {
1985 // InstructionSelector walks backwards through the instructions. For an
1986 // explicit conditional branch with no fallthrough, we use both a G_BR and a
1987 // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
1988 // generate the OpBranchConditional in selectBranch above.
1990 // If an OpBranchConditional has been generated, we simply return, as the work
1991 // is alread done. If there is no OpBranchConditional, LLVM must be relying on
1992 // implicit fallthrough to the next basic block, so we need to create an
1993 // OpBranchConditional with an explicit "false" argument pointing to the next
1994 // basic block that LLVM would fall through to.
1995 const MachineInstr
*NextI
= I
.getNextNode();
1996 // Check if this has already been successfully selected.
1997 if (NextI
!= nullptr && NextI
->getOpcode() == SPIRV::OpBranchConditional
)
1999 // Must be relying on implicit block fallthrough, so generate an
2000 // OpBranchConditional with the "next" basic block as the "false" target.
2001 MachineBasicBlock
&MBB
= *I
.getParent();
2002 unsigned NextMBBNum
= MBB
.getNextNode()->getNumber();
2003 MachineBasicBlock
*NextMBB
= I
.getMF()->getBlockNumbered(NextMBBNum
);
2004 return BuildMI(MBB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpBranchConditional
))
2005 .addUse(I
.getOperand(0).getReg())
2006 .addMBB(I
.getOperand(1).getMBB())
2008 .constrainAllUses(TII
, TRI
, RBI
);
2011 bool SPIRVInstructionSelector::selectPhi(Register ResVReg
,
2012 const SPIRVType
*ResType
,
2013 MachineInstr
&I
) const {
2014 auto MIB
= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(SPIRV::OpPhi
))
2016 .addUse(GR
.getSPIRVTypeID(ResType
));
2017 const unsigned NumOps
= I
.getNumOperands();
2018 for (unsigned i
= 1; i
< NumOps
; i
+= 2) {
2019 MIB
.addUse(I
.getOperand(i
+ 0).getReg());
2020 MIB
.addMBB(I
.getOperand(i
+ 1).getMBB());
2022 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
2025 bool SPIRVInstructionSelector::selectGlobalValue(
2026 Register ResVReg
, MachineInstr
&I
, const MachineInstr
*Init
) const {
2027 // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
2028 MachineIRBuilder
MIRBuilder(I
);
2029 const GlobalValue
*GV
= I
.getOperand(1).getGlobal();
2030 Type
*GVType
= GR
.getDeducedGlobalValueType(GV
);
2031 SPIRVType
*PointerBaseType
;
2032 if (GVType
->isArrayTy()) {
2033 SPIRVType
*ArrayElementType
=
2034 GR
.getOrCreateSPIRVType(GVType
->getArrayElementType(), MIRBuilder
,
2035 SPIRV::AccessQualifier::ReadWrite
, false);
2036 PointerBaseType
= GR
.getOrCreateSPIRVArrayType(
2037 ArrayElementType
, GVType
->getArrayNumElements(), I
, TII
);
2039 PointerBaseType
= GR
.getOrCreateSPIRVType(
2040 GVType
, MIRBuilder
, SPIRV::AccessQualifier::ReadWrite
, false);
2042 SPIRVType
*ResType
= GR
.getOrCreateSPIRVPointerType(
2043 PointerBaseType
, I
, TII
,
2044 addressSpaceToStorageClass(GV
->getAddressSpace(), STI
));
2046 std::string GlobalIdent
;
2047 if (!GV
->hasName()) {
2048 unsigned &ID
= UnnamedGlobalIDs
[GV
];
2050 ID
= UnnamedGlobalIDs
.size();
2051 GlobalIdent
= "__unnamed_" + Twine(ID
).str();
2053 GlobalIdent
= GV
->getGlobalIdentifier();
2056 // Behaviour of functions as operands depends on availability of the
2057 // corresponding extension (SPV_INTEL_function_pointers):
2058 // - If there is an extension to operate with functions as operands:
2059 // We create a proper constant operand and evaluate a correct type for a
2060 // function pointer.
2061 // - Without the required extension:
2062 // We have functions as operands in tests with blocks of instruction e.g. in
2063 // transcoding/global_block.ll. These operands are not used and should be
2064 // substituted by zero constants. Their type is expected to be always
2065 // OpTypePointer Function %uchar.
2066 if (isa
<Function
>(GV
)) {
2067 const Constant
*ConstVal
= GV
;
2068 MachineBasicBlock
&BB
= *I
.getParent();
2069 Register NewReg
= GR
.find(ConstVal
, GR
.CurMF
);
2070 if (!NewReg
.isValid()) {
2071 Register NewReg
= ResVReg
;
2072 GR
.add(ConstVal
, GR
.CurMF
, NewReg
);
2073 const Function
*GVFun
=
2074 STI
.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers
)
2075 ? dyn_cast
<Function
>(GV
)
2078 // References to a function via function pointers generate virtual
2079 // registers without a definition. We will resolve it later, during
2080 // module analysis stage.
2081 MachineRegisterInfo
*MRI
= MIRBuilder
.getMRI();
2082 Register FuncVReg
= MRI
->createGenericVirtualRegister(LLT::scalar(32));
2083 MRI
->setRegClass(FuncVReg
, &SPIRV::IDRegClass
);
2084 MachineInstrBuilder MB
=
2085 BuildMI(BB
, I
, I
.getDebugLoc(),
2086 TII
.get(SPIRV::OpConstantFunctionPointerINTEL
))
2088 .addUse(GR
.getSPIRVTypeID(ResType
))
2090 // mapping the function pointer to the used Function
2091 GR
.recordFunctionPointer(&MB
.getInstr()->getOperand(2), GVFun
);
2092 return MB
.constrainAllUses(TII
, TRI
, RBI
);
2094 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpConstantNull
))
2096 .addUse(GR
.getSPIRVTypeID(ResType
))
2097 .constrainAllUses(TII
, TRI
, RBI
);
2099 assert(NewReg
!= ResVReg
);
2100 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(TargetOpcode::COPY
))
2103 .constrainAllUses(TII
, TRI
, RBI
);
2105 auto GlobalVar
= cast
<GlobalVariable
>(GV
);
2106 assert(GlobalVar
->getName() != "llvm.global.annotations");
2108 bool HasInit
= GlobalVar
->hasInitializer() &&
2109 !isa
<UndefValue
>(GlobalVar
->getInitializer());
2110 // Skip empty declaration for GVs with initilaizers till we get the decl with
2111 // passed initializer.
2112 if (HasInit
&& !Init
)
2115 unsigned AddrSpace
= GV
->getAddressSpace();
2116 SPIRV::StorageClass::StorageClass Storage
=
2117 addressSpaceToStorageClass(AddrSpace
, STI
);
2118 bool HasLnkTy
= GV
->getLinkage() != GlobalValue::InternalLinkage
&&
2119 Storage
!= SPIRV::StorageClass::Function
;
2120 SPIRV::LinkageType::LinkageType LnkType
=
2121 (GV
->isDeclaration() || GV
->hasAvailableExternallyLinkage())
2122 ? SPIRV::LinkageType::Import
2123 : (GV
->getLinkage() == GlobalValue::LinkOnceODRLinkage
&&
2124 STI
.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr
)
2125 ? SPIRV::LinkageType::LinkOnceODR
2126 : SPIRV::LinkageType::Export
);
2128 Register Reg
= GR
.buildGlobalVariable(ResVReg
, ResType
, GlobalIdent
, GV
,
2129 Storage
, Init
, GlobalVar
->isConstant(),
2130 HasLnkTy
, LnkType
, MIRBuilder
, true);
2131 return Reg
.isValid();
2134 bool SPIRVInstructionSelector::selectLog10(Register ResVReg
,
2135 const SPIRVType
*ResType
,
2136 MachineInstr
&I
) const {
2137 if (STI
.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std
)) {
2138 return selectExtInst(ResVReg
, ResType
, I
, CL::log10
);
2141 // There is no log10 instruction in the GLSL Extended Instruction set, so it
2142 // is implemented as:
2143 // log10(x) = log2(x) * (1 / log2(10))
2144 // = log2(x) * 0.30103
2146 MachineIRBuilder
MIRBuilder(I
);
2147 MachineBasicBlock
&BB
= *I
.getParent();
2150 Register VarReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
2152 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpExtInst
))
2154 .addUse(GR
.getSPIRVTypeID(ResType
))
2155 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450
))
2157 .add(I
.getOperand(1))
2158 .constrainAllUses(TII
, TRI
, RBI
);
2161 assert(ResType
->getOpcode() == SPIRV::OpTypeVector
||
2162 ResType
->getOpcode() == SPIRV::OpTypeFloat
);
2163 // TODO: Add matrix implementation once supported by the HLSL frontend.
2164 const SPIRVType
*SpirvScalarType
=
2165 ResType
->getOpcode() == SPIRV::OpTypeVector
2166 ? GR
.getSPIRVTypeForVReg(ResType
->getOperand(1).getReg())
2169 GR
.buildConstantFP(APFloat(0.30103f
), MIRBuilder
, SpirvScalarType
);
2171 // Multiply log2(x) by 0.30103 to get log10(x) result.
2172 auto Opcode
= ResType
->getOpcode() == SPIRV::OpTypeVector
2173 ? SPIRV::OpVectorTimesScalar
2175 Result
&= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(Opcode
))
2177 .addUse(GR
.getSPIRVTypeID(ResType
))
2180 .constrainAllUses(TII
, TRI
, RBI
);
2185 bool SPIRVInstructionSelector::selectSpvThreadId(Register ResVReg
,
2186 const SPIRVType
*ResType
,
2187 MachineInstr
&I
) const {
2188 // DX intrinsic: @llvm.dx.thread.id(i32)
2189 // ID Name Description
2190 // 93 ThreadId reads the thread ID
2192 MachineIRBuilder
MIRBuilder(I
);
2193 const SPIRVType
*U32Type
= GR
.getOrCreateSPIRVIntegerType(32, MIRBuilder
);
2194 const SPIRVType
*Vec3Ty
=
2195 GR
.getOrCreateSPIRVVectorType(U32Type
, 3, MIRBuilder
);
2196 const SPIRVType
*PtrType
= GR
.getOrCreateSPIRVPointerType(
2197 Vec3Ty
, MIRBuilder
, SPIRV::StorageClass::Input
);
2199 // Create new register for GlobalInvocationID builtin variable.
2200 Register NewRegister
=
2201 MIRBuilder
.getMRI()->createVirtualRegister(&SPIRV::IDRegClass
);
2202 MIRBuilder
.getMRI()->setType(NewRegister
, LLT::pointer(0, 32));
2203 GR
.assignSPIRVTypeToVReg(PtrType
, NewRegister
, MIRBuilder
.getMF());
2205 // Build GlobalInvocationID global variable with the necessary decorations.
2206 Register Variable
= GR
.buildGlobalVariable(
2207 NewRegister
, PtrType
,
2208 getLinkStringForBuiltIn(SPIRV::BuiltIn::GlobalInvocationId
), nullptr,
2209 SPIRV::StorageClass::Input
, nullptr, true, true,
2210 SPIRV::LinkageType::Import
, MIRBuilder
, false);
2212 // Create new register for loading value.
2213 MachineRegisterInfo
*MRI
= MIRBuilder
.getMRI();
2214 Register LoadedRegister
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
2215 MIRBuilder
.getMRI()->setType(LoadedRegister
, LLT::pointer(0, 32));
2216 GR
.assignSPIRVTypeToVReg(Vec3Ty
, LoadedRegister
, MIRBuilder
.getMF());
2218 // Load v3uint value from the global variable.
2219 BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(SPIRV::OpLoad
))
2220 .addDef(LoadedRegister
)
2221 .addUse(GR
.getSPIRVTypeID(Vec3Ty
))
2224 // Get Thread ID index. Expecting operand is a constant immediate value,
2225 // wrapped in a type assignment.
2226 assert(I
.getOperand(2).isReg());
2227 Register ThreadIdReg
= I
.getOperand(2).getReg();
2228 SPIRVType
*ConstTy
= this->MRI
->getVRegDef(ThreadIdReg
);
2229 assert(ConstTy
&& ConstTy
->getOpcode() == SPIRV::ASSIGN_TYPE
&&
2230 ConstTy
->getOperand(1).isReg());
2231 Register ConstReg
= ConstTy
->getOperand(1).getReg();
2232 const MachineInstr
*Const
= this->MRI
->getVRegDef(ConstReg
);
2233 assert(Const
&& Const
->getOpcode() == TargetOpcode::G_CONSTANT
);
2234 const llvm::APInt
&Val
= Const
->getOperand(1).getCImm()->getValue();
2235 const uint32_t ThreadId
= Val
.getZExtValue();
2237 // Extract the thread ID from the loaded vector value.
2238 MachineBasicBlock
&BB
= *I
.getParent();
2239 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpCompositeExtract
))
2241 .addUse(GR
.getSPIRVTypeID(ResType
))
2242 .addUse(LoadedRegister
)
2244 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
2248 InstructionSelector
*
2249 createSPIRVInstructionSelector(const SPIRVTargetMachine
&TM
,
2250 const SPIRVSubtarget
&Subtarget
,
2251 const RegisterBankInfo
&RBI
) {
2252 return new SPIRVInstructionSelector(TM
, Subtarget
, RBI
);