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 bool selectFmix(Register ResVReg
, const SPIRVType
*ResType
,
174 MachineInstr
&I
) const;
176 void renderImm32(MachineInstrBuilder
&MIB
, const MachineInstr
&I
,
178 void renderFImm32(MachineInstrBuilder
&MIB
, const MachineInstr
&I
,
181 bool selectConst(Register ResVReg
, const SPIRVType
*ResType
, const APInt
&Imm
,
182 MachineInstr
&I
) const;
184 bool selectSelect(Register ResVReg
, const SPIRVType
*ResType
, MachineInstr
&I
,
185 bool IsSigned
) const;
186 bool selectIToF(Register ResVReg
, const SPIRVType
*ResType
, MachineInstr
&I
,
187 bool IsSigned
, unsigned Opcode
) const;
188 bool selectExt(Register ResVReg
, const SPIRVType
*ResType
, MachineInstr
&I
,
189 bool IsSigned
) const;
191 bool selectTrunc(Register ResVReg
, const SPIRVType
*ResType
,
192 MachineInstr
&I
) const;
194 bool selectIntToBool(Register IntReg
, Register ResVReg
, MachineInstr
&I
,
195 const SPIRVType
*intTy
, const SPIRVType
*boolTy
) const;
197 bool selectOpUndef(Register ResVReg
, const SPIRVType
*ResType
,
198 MachineInstr
&I
) const;
199 bool selectFreeze(Register ResVReg
, const SPIRVType
*ResType
,
200 MachineInstr
&I
) const;
201 bool selectIntrinsic(Register ResVReg
, const SPIRVType
*ResType
,
202 MachineInstr
&I
) const;
203 bool selectExtractVal(Register ResVReg
, const SPIRVType
*ResType
,
204 MachineInstr
&I
) const;
205 bool selectInsertVal(Register ResVReg
, const SPIRVType
*ResType
,
206 MachineInstr
&I
) const;
207 bool selectExtractElt(Register ResVReg
, const SPIRVType
*ResType
,
208 MachineInstr
&I
) const;
209 bool selectInsertElt(Register ResVReg
, const SPIRVType
*ResType
,
210 MachineInstr
&I
) const;
211 bool selectGEP(Register ResVReg
, const SPIRVType
*ResType
,
212 MachineInstr
&I
) const;
214 bool selectFrameIndex(Register ResVReg
, const SPIRVType
*ResType
,
215 MachineInstr
&I
) const;
216 bool selectAllocaArray(Register ResVReg
, const SPIRVType
*ResType
,
217 MachineInstr
&I
) const;
219 bool selectBranch(MachineInstr
&I
) const;
220 bool selectBranchCond(MachineInstr
&I
) const;
222 bool selectPhi(Register ResVReg
, const SPIRVType
*ResType
,
223 MachineInstr
&I
) const;
225 bool selectExtInst(Register ResVReg
, const SPIRVType
*ResType
,
226 MachineInstr
&I
, CL::OpenCLExtInst CLInst
) const;
227 bool selectExtInst(Register ResVReg
, const SPIRVType
*ResType
,
228 MachineInstr
&I
, CL::OpenCLExtInst CLInst
,
229 GL::GLSLExtInst GLInst
) const;
230 bool selectExtInst(Register ResVReg
, const SPIRVType
*ResType
,
231 MachineInstr
&I
, const ExtInstList
&ExtInsts
) const;
233 bool selectLog10(Register ResVReg
, const SPIRVType
*ResType
,
234 MachineInstr
&I
) const;
236 bool selectSpvThreadId(Register ResVReg
, const SPIRVType
*ResType
,
237 MachineInstr
&I
) const;
239 bool selectUnmergeValues(MachineInstr
&I
) const;
241 Register
buildI32Constant(uint32_t Val
, MachineInstr
&I
,
242 const SPIRVType
*ResType
= nullptr) const;
244 Register
buildZerosVal(const SPIRVType
*ResType
, MachineInstr
&I
) const;
245 Register
buildZerosValF(const SPIRVType
*ResType
, MachineInstr
&I
) const;
246 Register
buildOnesVal(bool AllOnes
, const SPIRVType
*ResType
,
247 MachineInstr
&I
) const;
249 bool wrapIntoSpecConstantOp(MachineInstr
&I
,
250 SmallVector
<Register
> &CompositeArgs
) const;
253 } // end anonymous namespace
255 #define GET_GLOBALISEL_IMPL
256 #include "SPIRVGenGlobalISel.inc"
257 #undef GET_GLOBALISEL_IMPL
259 SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine
&TM
,
260 const SPIRVSubtarget
&ST
,
261 const RegisterBankInfo
&RBI
)
262 : InstructionSelector(), STI(ST
), TII(*ST
.getInstrInfo()),
263 TRI(*ST
.getRegisterInfo()), RBI(RBI
), GR(*ST
.getSPIRVGlobalRegistry()),
264 #define GET_GLOBALISEL_PREDICATES_INIT
265 #include "SPIRVGenGlobalISel.inc"
266 #undef GET_GLOBALISEL_PREDICATES_INIT
267 #define GET_GLOBALISEL_TEMPORARIES_INIT
268 #include "SPIRVGenGlobalISel.inc"
269 #undef GET_GLOBALISEL_TEMPORARIES_INIT
273 void SPIRVInstructionSelector::setupMF(MachineFunction
&MF
, GISelKnownBits
*KB
,
274 CodeGenCoverage
*CoverageInfo
,
275 ProfileSummaryInfo
*PSI
,
276 BlockFrequencyInfo
*BFI
) {
277 MMI
= &MF
.getMMI().getObjFileInfo
<SPIRVMachineModuleInfo
>();
278 MRI
= &MF
.getRegInfo();
279 GR
.setCurrentFunc(MF
);
280 InstructionSelector::setupMF(MF
, KB
, CoverageInfo
, PSI
, BFI
);
283 static bool isImm(const MachineOperand
&MO
, MachineRegisterInfo
*MRI
);
285 // Defined in SPIRVLegalizerInfo.cpp.
286 extern bool isTypeFoldingSupported(unsigned Opcode
);
288 bool SPIRVInstructionSelector::select(MachineInstr
&I
) {
289 assert(I
.getParent() && "Instruction should be in a basic block!");
290 assert(I
.getParent()->getParent() && "Instruction should be in a function!");
292 Register Opcode
= I
.getOpcode();
293 // If it's not a GMIR instruction, we've selected it already.
294 if (!isPreISelGenericOpcode(Opcode
)) {
295 if (Opcode
== SPIRV::ASSIGN_TYPE
) { // These pseudos aren't needed any more.
296 Register DstReg
= I
.getOperand(0).getReg();
297 Register SrcReg
= I
.getOperand(1).getReg();
298 auto *Def
= MRI
->getVRegDef(SrcReg
);
299 if (isTypeFoldingSupported(Def
->getOpcode())) {
300 if (MRI
->getType(DstReg
).isPointer())
301 MRI
->setType(DstReg
, LLT::scalar(32));
302 bool Res
= selectImpl(I
, *CoverageInfo
);
303 assert(Res
|| Def
->getOpcode() == TargetOpcode::G_CONSTANT
);
307 MRI
->replaceRegWith(SrcReg
, DstReg
);
308 I
.removeFromParent();
310 } else if (I
.getNumDefs() == 1) {
311 // Make all vregs 32 bits (for SPIR-V IDs).
312 MRI
->setType(I
.getOperand(0).getReg(), LLT::scalar(32));
314 return constrainSelectedInstRegOperands(I
, TII
, TRI
, RBI
);
317 if (I
.getNumOperands() != I
.getNumExplicitOperands()) {
318 LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
322 // Common code for getting return reg+type, and removing selected instr
323 // from parent occurs here. Instr-specific selection happens in spvSelect().
324 bool HasDefs
= I
.getNumDefs() > 0;
325 Register ResVReg
= HasDefs
? I
.getOperand(0).getReg() : Register(0);
326 SPIRVType
*ResType
= HasDefs
? GR
.getSPIRVTypeForVReg(ResVReg
) : nullptr;
327 assert(!HasDefs
|| ResType
|| I
.getOpcode() == TargetOpcode::G_GLOBAL_VALUE
);
328 if (spvSelect(ResVReg
, ResType
, I
)) {
329 if (HasDefs
) // Make all vregs 32 bits (for SPIR-V IDs).
330 for (unsigned i
= 0; i
< I
.getNumDefs(); ++i
)
331 MRI
->setType(I
.getOperand(i
).getReg(), LLT::scalar(32));
332 I
.removeFromParent();
338 bool SPIRVInstructionSelector::spvSelect(Register ResVReg
,
339 const SPIRVType
*ResType
,
340 MachineInstr
&I
) const {
341 const unsigned Opcode
= I
.getOpcode();
342 if (isTypeFoldingSupported(Opcode
) && Opcode
!= TargetOpcode::G_CONSTANT
)
343 return selectImpl(I
, *CoverageInfo
);
345 case TargetOpcode::G_CONSTANT
:
346 return selectConst(ResVReg
, ResType
, I
.getOperand(1).getCImm()->getValue(),
348 case TargetOpcode::G_GLOBAL_VALUE
:
349 return selectGlobalValue(ResVReg
, I
);
350 case TargetOpcode::G_IMPLICIT_DEF
:
351 return selectOpUndef(ResVReg
, ResType
, I
);
352 case TargetOpcode::G_FREEZE
:
353 return selectFreeze(ResVReg
, ResType
, I
);
355 case TargetOpcode::G_INTRINSIC
:
356 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS
:
357 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS
:
358 return selectIntrinsic(ResVReg
, ResType
, I
);
359 case TargetOpcode::G_BITREVERSE
:
360 return selectBitreverse(ResVReg
, ResType
, I
);
362 case TargetOpcode::G_BUILD_VECTOR
:
363 return selectConstVector(ResVReg
, ResType
, I
);
364 case TargetOpcode::G_SPLAT_VECTOR
:
365 return selectSplatVector(ResVReg
, ResType
, I
);
367 case TargetOpcode::G_SHUFFLE_VECTOR
: {
368 MachineBasicBlock
&BB
= *I
.getParent();
369 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpVectorShuffle
))
371 .addUse(GR
.getSPIRVTypeID(ResType
))
372 .addUse(I
.getOperand(1).getReg())
373 .addUse(I
.getOperand(2).getReg());
374 for (auto V
: I
.getOperand(3).getShuffleMask())
376 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
378 case TargetOpcode::G_MEMMOVE
:
379 case TargetOpcode::G_MEMCPY
:
380 case TargetOpcode::G_MEMSET
:
381 return selectMemOperation(ResVReg
, I
);
383 case TargetOpcode::G_ICMP
:
384 return selectICmp(ResVReg
, ResType
, I
);
385 case TargetOpcode::G_FCMP
:
386 return selectFCmp(ResVReg
, ResType
, I
);
388 case TargetOpcode::G_FRAME_INDEX
:
389 return selectFrameIndex(ResVReg
, ResType
, I
);
391 case TargetOpcode::G_LOAD
:
392 return selectLoad(ResVReg
, ResType
, I
);
393 case TargetOpcode::G_STORE
:
394 return selectStore(I
);
396 case TargetOpcode::G_BR
:
397 return selectBranch(I
);
398 case TargetOpcode::G_BRCOND
:
399 return selectBranchCond(I
);
401 case TargetOpcode::G_PHI
:
402 return selectPhi(ResVReg
, ResType
, I
);
404 case TargetOpcode::G_FPTOSI
:
405 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpConvertFToS
);
406 case TargetOpcode::G_FPTOUI
:
407 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpConvertFToU
);
409 case TargetOpcode::G_SITOFP
:
410 return selectIToF(ResVReg
, ResType
, I
, true, SPIRV::OpConvertSToF
);
411 case TargetOpcode::G_UITOFP
:
412 return selectIToF(ResVReg
, ResType
, I
, false, SPIRV::OpConvertUToF
);
414 case TargetOpcode::G_CTPOP
:
415 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpBitCount
);
416 case TargetOpcode::G_SMIN
:
417 return selectExtInst(ResVReg
, ResType
, I
, CL::s_min
, GL::SMin
);
418 case TargetOpcode::G_UMIN
:
419 return selectExtInst(ResVReg
, ResType
, I
, CL::u_min
, GL::UMin
);
421 case TargetOpcode::G_SMAX
:
422 return selectExtInst(ResVReg
, ResType
, I
, CL::s_max
, GL::SMax
);
423 case TargetOpcode::G_UMAX
:
424 return selectExtInst(ResVReg
, ResType
, I
, CL::u_max
, GL::UMax
);
426 case TargetOpcode::G_FMA
:
427 return selectExtInst(ResVReg
, ResType
, I
, CL::fma
, GL::Fma
);
429 case TargetOpcode::G_FPOW
:
430 return selectExtInst(ResVReg
, ResType
, I
, CL::pow
, GL::Pow
);
431 case TargetOpcode::G_FPOWI
:
432 return selectExtInst(ResVReg
, ResType
, I
, CL::pown
);
434 case TargetOpcode::G_FEXP
:
435 return selectExtInst(ResVReg
, ResType
, I
, CL::exp
, GL::Exp
);
436 case TargetOpcode::G_FEXP2
:
437 return selectExtInst(ResVReg
, ResType
, I
, CL::exp2
, GL::Exp2
);
439 case TargetOpcode::G_FLOG
:
440 return selectExtInst(ResVReg
, ResType
, I
, CL::log
, GL::Log
);
441 case TargetOpcode::G_FLOG2
:
442 return selectExtInst(ResVReg
, ResType
, I
, CL::log2
, GL::Log2
);
443 case TargetOpcode::G_FLOG10
:
444 return selectLog10(ResVReg
, ResType
, I
);
446 case TargetOpcode::G_FABS
:
447 return selectExtInst(ResVReg
, ResType
, I
, CL::fabs
, GL::FAbs
);
448 case TargetOpcode::G_ABS
:
449 return selectExtInst(ResVReg
, ResType
, I
, CL::s_abs
, GL::SAbs
);
451 case TargetOpcode::G_FMINNUM
:
452 case TargetOpcode::G_FMINIMUM
:
453 return selectExtInst(ResVReg
, ResType
, I
, CL::fmin
, GL::NMin
);
454 case TargetOpcode::G_FMAXNUM
:
455 case TargetOpcode::G_FMAXIMUM
:
456 return selectExtInst(ResVReg
, ResType
, I
, CL::fmax
, GL::NMax
);
458 case TargetOpcode::G_FCOPYSIGN
:
459 return selectExtInst(ResVReg
, ResType
, I
, CL::copysign
);
461 case TargetOpcode::G_FCEIL
:
462 return selectExtInst(ResVReg
, ResType
, I
, CL::ceil
, GL::Ceil
);
463 case TargetOpcode::G_FFLOOR
:
464 return selectExtInst(ResVReg
, ResType
, I
, CL::floor
, GL::Floor
);
466 case TargetOpcode::G_FCOS
:
467 return selectExtInst(ResVReg
, ResType
, I
, CL::cos
, GL::Cos
);
468 case TargetOpcode::G_FSIN
:
469 return selectExtInst(ResVReg
, ResType
, I
, CL::sin
, GL::Sin
);
470 case TargetOpcode::G_FTAN
:
471 return selectExtInst(ResVReg
, ResType
, I
, CL::tan
, GL::Tan
);
473 case TargetOpcode::G_FSQRT
:
474 return selectExtInst(ResVReg
, ResType
, I
, CL::sqrt
, GL::Sqrt
);
476 case TargetOpcode::G_CTTZ
:
477 case TargetOpcode::G_CTTZ_ZERO_UNDEF
:
478 return selectExtInst(ResVReg
, ResType
, I
, CL::ctz
);
479 case TargetOpcode::G_CTLZ
:
480 case TargetOpcode::G_CTLZ_ZERO_UNDEF
:
481 return selectExtInst(ResVReg
, ResType
, I
, CL::clz
);
483 case TargetOpcode::G_INTRINSIC_ROUND
:
484 return selectExtInst(ResVReg
, ResType
, I
, CL::round
, GL::Round
);
485 case TargetOpcode::G_INTRINSIC_ROUNDEVEN
:
486 return selectExtInst(ResVReg
, ResType
, I
, CL::rint
, GL::RoundEven
);
487 case TargetOpcode::G_INTRINSIC_TRUNC
:
488 return selectExtInst(ResVReg
, ResType
, I
, CL::trunc
, GL::Trunc
);
489 case TargetOpcode::G_FRINT
:
490 case TargetOpcode::G_FNEARBYINT
:
491 return selectExtInst(ResVReg
, ResType
, I
, CL::rint
, GL::RoundEven
);
493 case TargetOpcode::G_SMULH
:
494 return selectExtInst(ResVReg
, ResType
, I
, CL::s_mul_hi
);
495 case TargetOpcode::G_UMULH
:
496 return selectExtInst(ResVReg
, ResType
, I
, CL::u_mul_hi
);
498 case TargetOpcode::G_SEXT
:
499 return selectExt(ResVReg
, ResType
, I
, true);
500 case TargetOpcode::G_ANYEXT
:
501 case TargetOpcode::G_ZEXT
:
502 return selectExt(ResVReg
, ResType
, I
, false);
503 case TargetOpcode::G_TRUNC
:
504 return selectTrunc(ResVReg
, ResType
, I
);
505 case TargetOpcode::G_FPTRUNC
:
506 case TargetOpcode::G_FPEXT
:
507 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpFConvert
);
509 case TargetOpcode::G_PTRTOINT
:
510 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpConvertPtrToU
);
511 case TargetOpcode::G_INTTOPTR
:
512 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpConvertUToPtr
);
513 case TargetOpcode::G_BITCAST
:
514 return selectBitcast(ResVReg
, ResType
, I
);
515 case TargetOpcode::G_ADDRSPACE_CAST
:
516 return selectAddrSpaceCast(ResVReg
, ResType
, I
);
517 case TargetOpcode::G_PTR_ADD
: {
518 // Currently, we get G_PTR_ADD only as a result of translating
519 // global variables, initialized with constant expressions like GV + Const
520 // (see test opencl/basic/progvar_prog_scope_init.ll).
521 // TODO: extend the handler once we have other cases.
522 assert(I
.getOperand(1).isReg() && I
.getOperand(2).isReg());
523 Register GV
= I
.getOperand(1).getReg();
524 MachineRegisterInfo::def_instr_iterator II
= MRI
->def_instr_begin(GV
);
526 assert(((*II
).getOpcode() == TargetOpcode::G_GLOBAL_VALUE
||
527 (*II
).getOpcode() == TargetOpcode::COPY
||
528 (*II
).getOpcode() == SPIRV::OpVariable
) &&
529 isImm(I
.getOperand(2), MRI
));
530 Register Idx
= buildZerosVal(GR
.getOrCreateSPIRVIntegerType(32, I
, TII
), I
);
531 MachineBasicBlock
&BB
= *I
.getParent();
532 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpSpecConstantOp
))
534 .addUse(GR
.getSPIRVTypeID(ResType
))
535 .addImm(static_cast<uint32_t>(
536 SPIRV::Opcode::InBoundsPtrAccessChain
))
539 .addUse(I
.getOperand(2).getReg());
540 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
543 case TargetOpcode::G_ATOMICRMW_OR
:
544 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicOr
);
545 case TargetOpcode::G_ATOMICRMW_ADD
:
546 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicIAdd
);
547 case TargetOpcode::G_ATOMICRMW_AND
:
548 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicAnd
);
549 case TargetOpcode::G_ATOMICRMW_MAX
:
550 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicSMax
);
551 case TargetOpcode::G_ATOMICRMW_MIN
:
552 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicSMin
);
553 case TargetOpcode::G_ATOMICRMW_SUB
:
554 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicISub
);
555 case TargetOpcode::G_ATOMICRMW_XOR
:
556 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicXor
);
557 case TargetOpcode::G_ATOMICRMW_UMAX
:
558 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicUMax
);
559 case TargetOpcode::G_ATOMICRMW_UMIN
:
560 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicUMin
);
561 case TargetOpcode::G_ATOMICRMW_XCHG
:
562 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicExchange
);
563 case TargetOpcode::G_ATOMIC_CMPXCHG
:
564 return selectAtomicCmpXchg(ResVReg
, ResType
, I
);
566 case TargetOpcode::G_ATOMICRMW_FADD
:
567 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicFAddEXT
);
568 case TargetOpcode::G_ATOMICRMW_FSUB
:
569 // Translate G_ATOMICRMW_FSUB to OpAtomicFAddEXT with negative value operand
570 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicFAddEXT
,
572 case TargetOpcode::G_ATOMICRMW_FMIN
:
573 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicFMinEXT
);
574 case TargetOpcode::G_ATOMICRMW_FMAX
:
575 return selectAtomicRMW(ResVReg
, ResType
, I
, SPIRV::OpAtomicFMaxEXT
);
577 case TargetOpcode::G_FENCE
:
578 return selectFence(I
);
580 case TargetOpcode::G_STACKSAVE
:
581 return selectStackSave(ResVReg
, ResType
, I
);
582 case TargetOpcode::G_STACKRESTORE
:
583 return selectStackRestore(I
);
585 case TargetOpcode::G_UNMERGE_VALUES
:
586 return selectUnmergeValues(I
);
593 bool SPIRVInstructionSelector::selectExtInst(Register ResVReg
,
594 const SPIRVType
*ResType
,
596 CL::OpenCLExtInst CLInst
) const {
597 return selectExtInst(ResVReg
, ResType
, I
,
598 {{SPIRV::InstructionSet::OpenCL_std
, CLInst
}});
601 bool SPIRVInstructionSelector::selectExtInst(Register ResVReg
,
602 const SPIRVType
*ResType
,
604 CL::OpenCLExtInst CLInst
,
605 GL::GLSLExtInst GLInst
) const {
606 ExtInstList ExtInsts
= {{SPIRV::InstructionSet::OpenCL_std
, CLInst
},
607 {SPIRV::InstructionSet::GLSL_std_450
, GLInst
}};
608 return selectExtInst(ResVReg
, ResType
, I
, ExtInsts
);
611 bool SPIRVInstructionSelector::selectExtInst(Register ResVReg
,
612 const SPIRVType
*ResType
,
614 const ExtInstList
&Insts
) const {
616 for (const auto &Ex
: Insts
) {
617 SPIRV::InstructionSet::InstructionSet Set
= Ex
.first
;
618 uint32_t Opcode
= Ex
.second
;
619 if (STI
.canUseExtInstSet(Set
)) {
620 MachineBasicBlock
&BB
= *I
.getParent();
621 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpExtInst
))
623 .addUse(GR
.getSPIRVTypeID(ResType
))
624 .addImm(static_cast<uint32_t>(Set
))
626 const unsigned NumOps
= I
.getNumOperands();
627 for (unsigned i
= 1; i
< NumOps
; ++i
)
628 MIB
.add(I
.getOperand(i
));
629 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
635 bool SPIRVInstructionSelector::selectUnOpWithSrc(Register ResVReg
,
636 const SPIRVType
*ResType
,
639 unsigned Opcode
) const {
640 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(Opcode
))
642 .addUse(GR
.getSPIRVTypeID(ResType
))
644 .constrainAllUses(TII
, TRI
, RBI
);
647 bool SPIRVInstructionSelector::selectUnOp(Register ResVReg
,
648 const SPIRVType
*ResType
,
650 unsigned Opcode
) const {
651 if (STI
.isOpenCLEnv() && I
.getOperand(1).isReg()) {
652 Register SrcReg
= I
.getOperand(1).getReg();
654 for (MachineRegisterInfo::def_instr_iterator DefIt
=
655 MRI
->def_instr_begin(SrcReg
);
656 DefIt
!= MRI
->def_instr_end(); DefIt
= std::next(DefIt
)) {
657 if ((*DefIt
).getOpcode() == TargetOpcode::G_GLOBAL_VALUE
) {
663 uint32_t SpecOpcode
= 0;
665 case SPIRV::OpConvertPtrToU
:
666 SpecOpcode
= static_cast<uint32_t>(SPIRV::Opcode::ConvertPtrToU
);
668 case SPIRV::OpConvertUToPtr
:
669 SpecOpcode
= static_cast<uint32_t>(SPIRV::Opcode::ConvertUToPtr
);
673 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(),
674 TII
.get(SPIRV::OpSpecConstantOp
))
676 .addUse(GR
.getSPIRVTypeID(ResType
))
679 .constrainAllUses(TII
, TRI
, RBI
);
682 return selectUnOpWithSrc(ResVReg
, ResType
, I
, I
.getOperand(1).getReg(),
686 bool SPIRVInstructionSelector::selectBitcast(Register ResVReg
,
687 const SPIRVType
*ResType
,
688 MachineInstr
&I
) const {
689 Register OpReg
= I
.getOperand(1).getReg();
690 SPIRVType
*OpType
= OpReg
.isValid() ? GR
.getSPIRVTypeForVReg(OpReg
) : nullptr;
691 if (!GR
.isBitcastCompatible(ResType
, OpType
))
692 report_fatal_error("incompatible result and operand types in a bitcast");
693 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpBitcast
);
696 static SPIRV::Scope::Scope
getScope(SyncScope::ID Ord
,
697 SPIRVMachineModuleInfo
*MMI
) {
698 if (Ord
== SyncScope::SingleThread
|| Ord
== MMI
->Work_ItemSSID
)
699 return SPIRV::Scope::Invocation
;
700 else if (Ord
== SyncScope::System
|| Ord
== MMI
->DeviceSSID
)
701 return SPIRV::Scope::Device
;
702 else if (Ord
== MMI
->WorkGroupSSID
)
703 return SPIRV::Scope::Workgroup
;
704 else if (Ord
== MMI
->AllSVMDevicesSSID
)
705 return SPIRV::Scope::CrossDevice
;
706 else if (Ord
== MMI
->SubGroupSSID
)
707 return SPIRV::Scope::Subgroup
;
709 // OpenCL approach is: "The functions that do not have memory_scope argument
710 // have the same semantics as the corresponding functions with the
711 // memory_scope argument set to memory_scope_device." See ref.: //
712 // https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_C.html#atomic-functions
713 // In our case if the scope is unknown, assuming that SPIR-V code is to be
714 // consumed in an OpenCL environment, we use the same approach and set the
715 // scope to memory_scope_device.
716 return SPIRV::Scope::Device
;
719 static void addMemoryOperands(MachineMemOperand
*MemOp
,
720 MachineInstrBuilder
&MIB
) {
721 uint32_t SpvMemOp
= static_cast<uint32_t>(SPIRV::MemoryOperand::None
);
722 if (MemOp
->isVolatile())
723 SpvMemOp
|= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile
);
724 if (MemOp
->isNonTemporal())
725 SpvMemOp
|= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal
);
726 if (MemOp
->getAlign().value())
727 SpvMemOp
|= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned
);
729 if (SpvMemOp
!= static_cast<uint32_t>(SPIRV::MemoryOperand::None
)) {
730 MIB
.addImm(SpvMemOp
);
731 if (SpvMemOp
& static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned
))
732 MIB
.addImm(MemOp
->getAlign().value());
736 static void addMemoryOperands(uint64_t Flags
, MachineInstrBuilder
&MIB
) {
737 uint32_t SpvMemOp
= static_cast<uint32_t>(SPIRV::MemoryOperand::None
);
738 if (Flags
& MachineMemOperand::Flags::MOVolatile
)
739 SpvMemOp
|= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile
);
740 if (Flags
& MachineMemOperand::Flags::MONonTemporal
)
741 SpvMemOp
|= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal
);
743 if (SpvMemOp
!= static_cast<uint32_t>(SPIRV::MemoryOperand::None
))
744 MIB
.addImm(SpvMemOp
);
747 bool SPIRVInstructionSelector::selectLoad(Register ResVReg
,
748 const SPIRVType
*ResType
,
749 MachineInstr
&I
) const {
750 unsigned OpOffset
= isa
<GIntrinsic
>(I
) ? 1 : 0;
751 Register Ptr
= I
.getOperand(1 + OpOffset
).getReg();
752 auto MIB
= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(SPIRV::OpLoad
))
754 .addUse(GR
.getSPIRVTypeID(ResType
))
756 if (!I
.getNumMemOperands()) {
757 assert(I
.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS
||
759 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS
);
760 addMemoryOperands(I
.getOperand(2 + OpOffset
).getImm(), MIB
);
762 addMemoryOperands(*I
.memoperands_begin(), MIB
);
764 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
767 bool SPIRVInstructionSelector::selectStore(MachineInstr
&I
) const {
768 unsigned OpOffset
= isa
<GIntrinsic
>(I
) ? 1 : 0;
769 Register StoreVal
= I
.getOperand(0 + OpOffset
).getReg();
770 Register Ptr
= I
.getOperand(1 + OpOffset
).getReg();
771 MachineBasicBlock
&BB
= *I
.getParent();
772 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpStore
))
775 if (!I
.getNumMemOperands()) {
776 assert(I
.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS
||
778 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS
);
779 addMemoryOperands(I
.getOperand(2 + OpOffset
).getImm(), MIB
);
781 addMemoryOperands(*I
.memoperands_begin(), MIB
);
783 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
786 bool SPIRVInstructionSelector::selectStackSave(Register ResVReg
,
787 const SPIRVType
*ResType
,
788 MachineInstr
&I
) const {
789 if (!STI
.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array
))
791 "llvm.stacksave intrinsic: this instruction requires the following "
792 "SPIR-V extension: SPV_INTEL_variable_length_array",
794 MachineBasicBlock
&BB
= *I
.getParent();
795 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpSaveMemoryINTEL
))
797 .addUse(GR
.getSPIRVTypeID(ResType
))
798 .constrainAllUses(TII
, TRI
, RBI
);
801 bool SPIRVInstructionSelector::selectStackRestore(MachineInstr
&I
) const {
802 if (!STI
.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array
))
804 "llvm.stackrestore intrinsic: this instruction requires the following "
805 "SPIR-V extension: SPV_INTEL_variable_length_array",
807 if (!I
.getOperand(0).isReg())
809 MachineBasicBlock
&BB
= *I
.getParent();
810 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpRestoreMemoryINTEL
))
811 .addUse(I
.getOperand(0).getReg())
812 .constrainAllUses(TII
, TRI
, RBI
);
815 bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg
,
816 MachineInstr
&I
) const {
817 MachineBasicBlock
&BB
= *I
.getParent();
818 Register SrcReg
= I
.getOperand(1).getReg();
819 if (I
.getOpcode() == TargetOpcode::G_MEMSET
) {
820 assert(I
.getOperand(1).isReg() && I
.getOperand(2).isReg());
821 unsigned Val
= getIConstVal(I
.getOperand(1).getReg(), MRI
);
822 unsigned Num
= getIConstVal(I
.getOperand(2).getReg(), MRI
);
823 SPIRVType
*ValTy
= GR
.getOrCreateSPIRVIntegerType(8, I
, TII
);
824 SPIRVType
*ArrTy
= GR
.getOrCreateSPIRVArrayType(ValTy
, Num
, I
, TII
);
825 Register Const
= GR
.getOrCreateConsIntArray(Val
, I
, ArrTy
, TII
);
826 SPIRVType
*VarTy
= GR
.getOrCreateSPIRVPointerType(
827 ArrTy
, I
, TII
, SPIRV::StorageClass::UniformConstant
);
828 // TODO: check if we have such GV, add init, use buildGlobalVariable.
829 Function
&CurFunction
= GR
.CurMF
->getFunction();
831 ArrayType::get(IntegerType::get(CurFunction
.getContext(), 8), Num
);
832 // Module takes ownership of the global var.
833 GlobalVariable
*GV
= new GlobalVariable(*CurFunction
.getParent(), LLVMArrTy
,
834 true, GlobalValue::InternalLinkage
,
835 Constant::getNullValue(LLVMArrTy
));
836 Register VarReg
= MRI
->createGenericVirtualRegister(LLT::scalar(32));
837 GR
.add(GV
, GR
.CurMF
, VarReg
);
839 buildOpDecorate(VarReg
, I
, TII
, SPIRV::Decoration::Constant
, {});
840 BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(SPIRV::OpVariable
))
842 .addUse(GR
.getSPIRVTypeID(VarTy
))
843 .addImm(SPIRV::StorageClass::UniformConstant
)
845 .constrainAllUses(TII
, TRI
, RBI
);
846 SPIRVType
*SourceTy
= GR
.getOrCreateSPIRVPointerType(
847 ValTy
, I
, TII
, SPIRV::StorageClass::UniformConstant
);
848 SrcReg
= MRI
->createGenericVirtualRegister(LLT::scalar(32));
849 selectUnOpWithSrc(SrcReg
, SourceTy
, I
, VarReg
, SPIRV::OpBitcast
);
851 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpCopyMemorySized
))
852 .addUse(I
.getOperand(0).getReg())
854 .addUse(I
.getOperand(2).getReg());
855 if (I
.getNumMemOperands())
856 addMemoryOperands(*I
.memoperands_begin(), MIB
);
857 bool Result
= MIB
.constrainAllUses(TII
, TRI
, RBI
);
858 if (ResVReg
.isValid() && ResVReg
!= MIB
->getOperand(0).getReg())
859 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(TargetOpcode::COPY
), ResVReg
)
860 .addUse(MIB
->getOperand(0).getReg());
864 bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg
,
865 const SPIRVType
*ResType
,
868 unsigned NegateOpcode
) const {
869 assert(I
.hasOneMemOperand());
870 const MachineMemOperand
*MemOp
= *I
.memoperands_begin();
872 static_cast<uint32_t>(getScope(MemOp
->getSyncScopeID(), MMI
));
873 Register ScopeReg
= buildI32Constant(Scope
, I
);
875 Register Ptr
= I
.getOperand(1).getReg();
876 // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll
878 // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr));
879 AtomicOrdering AO
= MemOp
->getSuccessOrdering();
880 uint32_t MemSem
= static_cast<uint32_t>(getMemSemantics(AO
));
881 Register MemSemReg
= buildI32Constant(MemSem
/*| ScSem*/, I
);
884 Register ValueReg
= I
.getOperand(2).getReg();
885 if (NegateOpcode
!= 0) {
886 // Translation with negative value operand is requested
887 Register TmpReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
888 Result
|= selectUnOpWithSrc(TmpReg
, ResType
, I
, ValueReg
, NegateOpcode
);
892 Result
|= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(NewOpcode
))
894 .addUse(GR
.getSPIRVTypeID(ResType
))
899 .constrainAllUses(TII
, TRI
, RBI
);
903 bool SPIRVInstructionSelector::selectUnmergeValues(MachineInstr
&I
) const {
904 unsigned ArgI
= I
.getNumOperands() - 1;
906 I
.getOperand(ArgI
).isReg() ? I
.getOperand(ArgI
).getReg() : Register(0);
908 SrcReg
.isValid() ? GR
.getSPIRVTypeForVReg(SrcReg
) : nullptr;
909 if (!DefType
|| DefType
->getOpcode() != SPIRV::OpTypeVector
)
911 "cannot select G_UNMERGE_VALUES with a non-vector argument");
913 SPIRVType
*ScalarType
=
914 GR
.getSPIRVTypeForVReg(DefType
->getOperand(1).getReg());
915 MachineBasicBlock
&BB
= *I
.getParent();
917 for (unsigned i
= 0; i
< I
.getNumDefs(); ++i
) {
918 Register ResVReg
= I
.getOperand(i
).getReg();
919 SPIRVType
*ResType
= GR
.getSPIRVTypeForVReg(ResVReg
);
921 // There was no "assign type" actions, let's fix this now
922 ResType
= ScalarType
;
923 MRI
->setRegClass(ResVReg
, &SPIRV::IDRegClass
);
924 MRI
->setType(ResVReg
, LLT::scalar(GR
.getScalarOrVectorBitWidth(ResType
)));
925 GR
.assignSPIRVTypeToVReg(ResType
, ResVReg
, *GR
.CurMF
);
928 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpCompositeExtract
))
930 .addUse(GR
.getSPIRVTypeID(ResType
))
932 .addImm(static_cast<int64_t>(i
));
933 Res
|= MIB
.constrainAllUses(TII
, TRI
, RBI
);
938 bool SPIRVInstructionSelector::selectFence(MachineInstr
&I
) const {
939 AtomicOrdering AO
= AtomicOrdering(I
.getOperand(0).getImm());
940 uint32_t MemSem
= static_cast<uint32_t>(getMemSemantics(AO
));
941 Register MemSemReg
= buildI32Constant(MemSem
, I
);
942 SyncScope::ID Ord
= SyncScope::ID(I
.getOperand(1).getImm());
943 uint32_t Scope
= static_cast<uint32_t>(getScope(Ord
, MMI
));
944 Register ScopeReg
= buildI32Constant(Scope
, I
);
945 MachineBasicBlock
&BB
= *I
.getParent();
946 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpMemoryBarrier
))
949 .constrainAllUses(TII
, TRI
, RBI
);
952 bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg
,
953 const SPIRVType
*ResType
,
954 MachineInstr
&I
) const {
956 Register MemSemEqReg
;
957 Register MemSemNeqReg
;
958 Register Ptr
= I
.getOperand(2).getReg();
959 if (!isa
<GIntrinsic
>(I
)) {
960 assert(I
.hasOneMemOperand());
961 const MachineMemOperand
*MemOp
= *I
.memoperands_begin();
963 static_cast<uint32_t>(getScope(MemOp
->getSyncScopeID(), MMI
));
964 ScopeReg
= buildI32Constant(Scope
, I
);
966 unsigned ScSem
= static_cast<uint32_t>(
967 getMemSemanticsForStorageClass(GR
.getPointerStorageClass(Ptr
)));
968 AtomicOrdering AO
= MemOp
->getSuccessOrdering();
969 unsigned MemSemEq
= static_cast<uint32_t>(getMemSemantics(AO
)) | ScSem
;
970 MemSemEqReg
= buildI32Constant(MemSemEq
, I
);
971 AtomicOrdering FO
= MemOp
->getFailureOrdering();
972 unsigned MemSemNeq
= static_cast<uint32_t>(getMemSemantics(FO
)) | ScSem
;
974 MemSemEq
== MemSemNeq
? MemSemEqReg
: buildI32Constant(MemSemNeq
, I
);
976 ScopeReg
= I
.getOperand(5).getReg();
977 MemSemEqReg
= I
.getOperand(6).getReg();
978 MemSemNeqReg
= I
.getOperand(7).getReg();
981 Register Cmp
= I
.getOperand(3).getReg();
982 Register Val
= I
.getOperand(4).getReg();
983 SPIRVType
*SpvValTy
= GR
.getSPIRVTypeForVReg(Val
);
984 Register ACmpRes
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
985 const DebugLoc
&DL
= I
.getDebugLoc();
987 BuildMI(*I
.getParent(), I
, DL
, TII
.get(SPIRV::OpAtomicCompareExchange
))
989 .addUse(GR
.getSPIRVTypeID(SpvValTy
))
993 .addUse(MemSemNeqReg
)
996 .constrainAllUses(TII
, TRI
, RBI
);
997 Register CmpSuccReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
998 SPIRVType
*BoolTy
= GR
.getOrCreateSPIRVBoolType(I
, TII
);
999 Result
|= BuildMI(*I
.getParent(), I
, DL
, TII
.get(SPIRV::OpIEqual
))
1001 .addUse(GR
.getSPIRVTypeID(BoolTy
))
1004 .constrainAllUses(TII
, TRI
, RBI
);
1005 Register TmpReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1006 Result
|= BuildMI(*I
.getParent(), I
, DL
, TII
.get(SPIRV::OpCompositeInsert
))
1008 .addUse(GR
.getSPIRVTypeID(ResType
))
1010 .addUse(GR
.getOrCreateUndef(I
, ResType
, TII
))
1012 .constrainAllUses(TII
, TRI
, RBI
);
1013 Result
|= BuildMI(*I
.getParent(), I
, DL
, TII
.get(SPIRV::OpCompositeInsert
))
1015 .addUse(GR
.getSPIRVTypeID(ResType
))
1019 .constrainAllUses(TII
, TRI
, RBI
);
1023 static bool isGenericCastablePtr(SPIRV::StorageClass::StorageClass SC
) {
1025 case SPIRV::StorageClass::Workgroup
:
1026 case SPIRV::StorageClass::CrossWorkgroup
:
1027 case SPIRV::StorageClass::Function
:
1034 static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC
) {
1036 case SPIRV::StorageClass::DeviceOnlyINTEL
:
1037 case SPIRV::StorageClass::HostOnlyINTEL
:
1044 // In SPIR-V address space casting can only happen to and from the Generic
1045 // storage class. We can also only cast Workgroup, CrossWorkgroup, or Function
1046 // pointers to and from Generic pointers. As such, we can convert e.g. from
1047 // Workgroup to Function by going via a Generic pointer as an intermediary. All
1048 // other combinations can only be done by a bitcast, and are probably not safe.
1049 bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg
,
1050 const SPIRVType
*ResType
,
1051 MachineInstr
&I
) const {
1052 // If the AddrSpaceCast user is single and in OpConstantComposite or
1053 // OpVariable, we should select OpSpecConstantOp.
1054 auto UIs
= MRI
->use_instructions(ResVReg
);
1055 if (!UIs
.empty() && ++UIs
.begin() == UIs
.end() &&
1056 (UIs
.begin()->getOpcode() == SPIRV::OpConstantComposite
||
1057 UIs
.begin()->getOpcode() == SPIRV::OpVariable
||
1058 isSpvIntrinsic(*UIs
.begin(), Intrinsic::spv_init_global
))) {
1059 Register NewReg
= I
.getOperand(1).getReg();
1060 MachineBasicBlock
&BB
= *I
.getParent();
1061 SPIRVType
*SpvBaseTy
= GR
.getOrCreateSPIRVIntegerType(8, I
, TII
);
1062 ResType
= GR
.getOrCreateSPIRVPointerType(SpvBaseTy
, I
, TII
,
1063 SPIRV::StorageClass::Generic
);
1065 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpSpecConstantOp
))
1067 .addUse(GR
.getSPIRVTypeID(ResType
))
1068 .addImm(static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric
))
1070 .constrainAllUses(TII
, TRI
, RBI
);
1073 Register SrcPtr
= I
.getOperand(1).getReg();
1074 SPIRVType
*SrcPtrTy
= GR
.getSPIRVTypeForVReg(SrcPtr
);
1075 SPIRV::StorageClass::StorageClass SrcSC
= GR
.getPointerStorageClass(SrcPtr
);
1076 SPIRV::StorageClass::StorageClass DstSC
= GR
.getPointerStorageClass(ResVReg
);
1078 // don't generate a cast between identical storage classes
1082 // Casting from an eligible pointer to Generic.
1083 if (DstSC
== SPIRV::StorageClass::Generic
&& isGenericCastablePtr(SrcSC
))
1084 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpPtrCastToGeneric
);
1085 // Casting from Generic to an eligible pointer.
1086 if (SrcSC
== SPIRV::StorageClass::Generic
&& isGenericCastablePtr(DstSC
))
1087 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpGenericCastToPtr
);
1088 // Casting between 2 eligible pointers using Generic as an intermediary.
1089 if (isGenericCastablePtr(SrcSC
) && isGenericCastablePtr(DstSC
)) {
1090 Register Tmp
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1091 SPIRVType
*GenericPtrTy
= GR
.getOrCreateSPIRVPointerType(
1092 SrcPtrTy
, I
, TII
, SPIRV::StorageClass::Generic
);
1093 MachineBasicBlock
&BB
= *I
.getParent();
1094 const DebugLoc
&DL
= I
.getDebugLoc();
1095 bool Success
= BuildMI(BB
, I
, DL
, TII
.get(SPIRV::OpPtrCastToGeneric
))
1097 .addUse(GR
.getSPIRVTypeID(GenericPtrTy
))
1099 .constrainAllUses(TII
, TRI
, RBI
);
1100 return Success
&& BuildMI(BB
, I
, DL
, TII
.get(SPIRV::OpGenericCastToPtr
))
1102 .addUse(GR
.getSPIRVTypeID(ResType
))
1104 .constrainAllUses(TII
, TRI
, RBI
);
1107 // Check if instructions from the SPV_INTEL_usm_storage_classes extension may
1109 if (isUSMStorageClass(SrcSC
) && DstSC
== SPIRV::StorageClass::CrossWorkgroup
)
1110 return selectUnOp(ResVReg
, ResType
, I
,
1111 SPIRV::OpPtrCastToCrossWorkgroupINTEL
);
1112 if (SrcSC
== SPIRV::StorageClass::CrossWorkgroup
&& isUSMStorageClass(DstSC
))
1113 return selectUnOp(ResVReg
, ResType
, I
,
1114 SPIRV::OpCrossWorkgroupCastToPtrINTEL
);
1116 // TODO Should this case just be disallowed completely?
1117 // We're casting 2 other arbitrary address spaces, so have to bitcast.
1118 return selectUnOp(ResVReg
, ResType
, I
, SPIRV::OpBitcast
);
1121 static unsigned getFCmpOpcode(unsigned PredNum
) {
1122 auto Pred
= static_cast<CmpInst::Predicate
>(PredNum
);
1124 case CmpInst::FCMP_OEQ
:
1125 return SPIRV::OpFOrdEqual
;
1126 case CmpInst::FCMP_OGE
:
1127 return SPIRV::OpFOrdGreaterThanEqual
;
1128 case CmpInst::FCMP_OGT
:
1129 return SPIRV::OpFOrdGreaterThan
;
1130 case CmpInst::FCMP_OLE
:
1131 return SPIRV::OpFOrdLessThanEqual
;
1132 case CmpInst::FCMP_OLT
:
1133 return SPIRV::OpFOrdLessThan
;
1134 case CmpInst::FCMP_ONE
:
1135 return SPIRV::OpFOrdNotEqual
;
1136 case CmpInst::FCMP_ORD
:
1137 return SPIRV::OpOrdered
;
1138 case CmpInst::FCMP_UEQ
:
1139 return SPIRV::OpFUnordEqual
;
1140 case CmpInst::FCMP_UGE
:
1141 return SPIRV::OpFUnordGreaterThanEqual
;
1142 case CmpInst::FCMP_UGT
:
1143 return SPIRV::OpFUnordGreaterThan
;
1144 case CmpInst::FCMP_ULE
:
1145 return SPIRV::OpFUnordLessThanEqual
;
1146 case CmpInst::FCMP_ULT
:
1147 return SPIRV::OpFUnordLessThan
;
1148 case CmpInst::FCMP_UNE
:
1149 return SPIRV::OpFUnordNotEqual
;
1150 case CmpInst::FCMP_UNO
:
1151 return SPIRV::OpUnordered
;
1153 llvm_unreachable("Unknown predicate type for FCmp");
1157 static unsigned getICmpOpcode(unsigned PredNum
) {
1158 auto Pred
= static_cast<CmpInst::Predicate
>(PredNum
);
1160 case CmpInst::ICMP_EQ
:
1161 return SPIRV::OpIEqual
;
1162 case CmpInst::ICMP_NE
:
1163 return SPIRV::OpINotEqual
;
1164 case CmpInst::ICMP_SGE
:
1165 return SPIRV::OpSGreaterThanEqual
;
1166 case CmpInst::ICMP_SGT
:
1167 return SPIRV::OpSGreaterThan
;
1168 case CmpInst::ICMP_SLE
:
1169 return SPIRV::OpSLessThanEqual
;
1170 case CmpInst::ICMP_SLT
:
1171 return SPIRV::OpSLessThan
;
1172 case CmpInst::ICMP_UGE
:
1173 return SPIRV::OpUGreaterThanEqual
;
1174 case CmpInst::ICMP_UGT
:
1175 return SPIRV::OpUGreaterThan
;
1176 case CmpInst::ICMP_ULE
:
1177 return SPIRV::OpULessThanEqual
;
1178 case CmpInst::ICMP_ULT
:
1179 return SPIRV::OpULessThan
;
1181 llvm_unreachable("Unknown predicate type for ICmp");
1185 static unsigned getPtrCmpOpcode(unsigned Pred
) {
1186 switch (static_cast<CmpInst::Predicate
>(Pred
)) {
1187 case CmpInst::ICMP_EQ
:
1188 return SPIRV::OpPtrEqual
;
1189 case CmpInst::ICMP_NE
:
1190 return SPIRV::OpPtrNotEqual
;
1192 llvm_unreachable("Unknown predicate type for pointer comparison");
1196 // Return the logical operation, or abort if none exists.
1197 static unsigned getBoolCmpOpcode(unsigned PredNum
) {
1198 auto Pred
= static_cast<CmpInst::Predicate
>(PredNum
);
1200 case CmpInst::ICMP_EQ
:
1201 return SPIRV::OpLogicalEqual
;
1202 case CmpInst::ICMP_NE
:
1203 return SPIRV::OpLogicalNotEqual
;
1205 llvm_unreachable("Unknown predicate type for Bool comparison");
1209 bool SPIRVInstructionSelector::selectAnyOrAll(Register ResVReg
,
1210 const SPIRVType
*ResType
,
1212 unsigned OpAnyOrAll
) const {
1213 assert(I
.getNumOperands() == 3);
1214 assert(I
.getOperand(2).isReg());
1215 MachineBasicBlock
&BB
= *I
.getParent();
1216 Register InputRegister
= I
.getOperand(2).getReg();
1217 SPIRVType
*InputType
= GR
.getSPIRVTypeForVReg(InputRegister
);
1220 report_fatal_error("Input Type could not be determined.");
1222 bool IsBoolTy
= GR
.isScalarOrVectorOfType(InputRegister
, SPIRV::OpTypeBool
);
1223 bool IsVectorTy
= InputType
->getOpcode() == SPIRV::OpTypeVector
;
1224 if (IsBoolTy
&& !IsVectorTy
) {
1225 assert(ResVReg
== I
.getOperand(0).getReg());
1226 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(),
1227 TII
.get(TargetOpcode::COPY
))
1229 .addUse(InputRegister
)
1230 .constrainAllUses(TII
, TRI
, RBI
);
1233 bool IsFloatTy
= GR
.isScalarOrVectorOfType(InputRegister
, SPIRV::OpTypeFloat
);
1234 unsigned SpirvNotEqualId
=
1235 IsFloatTy
? SPIRV::OpFOrdNotEqual
: SPIRV::OpINotEqual
;
1236 SPIRVType
*SpvBoolScalarTy
= GR
.getOrCreateSPIRVBoolType(I
, TII
);
1237 SPIRVType
*SpvBoolTy
= SpvBoolScalarTy
;
1238 Register NotEqualReg
= ResVReg
;
1241 NotEqualReg
= IsBoolTy
? InputRegister
1242 : MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1243 const unsigned NumElts
= InputType
->getOperand(2).getImm();
1244 SpvBoolTy
= GR
.getOrCreateSPIRVVectorType(SpvBoolTy
, NumElts
, I
, TII
);
1248 Register ConstZeroReg
=
1249 IsFloatTy
? buildZerosValF(InputType
, I
) : buildZerosVal(InputType
, I
);
1251 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SpirvNotEqualId
))
1252 .addDef(NotEqualReg
)
1253 .addUse(GR
.getSPIRVTypeID(SpvBoolTy
))
1254 .addUse(InputRegister
)
1255 .addUse(ConstZeroReg
)
1256 .constrainAllUses(TII
, TRI
, RBI
);
1262 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(OpAnyOrAll
))
1264 .addUse(GR
.getSPIRVTypeID(SpvBoolScalarTy
))
1265 .addUse(NotEqualReg
)
1266 .constrainAllUses(TII
, TRI
, RBI
);
1269 bool SPIRVInstructionSelector::selectAll(Register ResVReg
,
1270 const SPIRVType
*ResType
,
1271 MachineInstr
&I
) const {
1272 return selectAnyOrAll(ResVReg
, ResType
, I
, SPIRV::OpAll
);
1275 bool SPIRVInstructionSelector::selectAny(Register ResVReg
,
1276 const SPIRVType
*ResType
,
1277 MachineInstr
&I
) const {
1278 return selectAnyOrAll(ResVReg
, ResType
, I
, SPIRV::OpAny
);
1281 bool SPIRVInstructionSelector::selectFmix(Register ResVReg
,
1282 const SPIRVType
*ResType
,
1283 MachineInstr
&I
) const {
1285 assert(I
.getNumOperands() == 5);
1286 assert(I
.getOperand(2).isReg());
1287 assert(I
.getOperand(3).isReg());
1288 assert(I
.getOperand(4).isReg());
1289 MachineBasicBlock
&BB
= *I
.getParent();
1291 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpExtInst
))
1293 .addUse(GR
.getSPIRVTypeID(ResType
))
1294 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450
))
1296 .addUse(I
.getOperand(2).getReg())
1297 .addUse(I
.getOperand(3).getReg())
1298 .addUse(I
.getOperand(4).getReg())
1299 .constrainAllUses(TII
, TRI
, RBI
);
1302 bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg
,
1303 const SPIRVType
*ResType
,
1304 MachineInstr
&I
) const {
1305 MachineBasicBlock
&BB
= *I
.getParent();
1306 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpBitReverse
))
1308 .addUse(GR
.getSPIRVTypeID(ResType
))
1309 .addUse(I
.getOperand(1).getReg())
1310 .constrainAllUses(TII
, TRI
, RBI
);
1313 bool SPIRVInstructionSelector::selectFreeze(Register ResVReg
,
1314 const SPIRVType
*ResType
,
1315 MachineInstr
&I
) const {
1316 // There is no way to implement `freeze` correctly without support on SPIR-V
1317 // standard side, but we may at least address a simple (static) case when
1318 // undef/poison value presence is obvious. The main benefit of even
1319 // incomplete `freeze` support is preventing of translation from crashing due
1320 // to lack of support on legalization and instruction selection steps.
1321 if (!I
.getOperand(0).isReg() || !I
.getOperand(1).isReg())
1323 Register OpReg
= I
.getOperand(1).getReg();
1324 if (MachineInstr
*Def
= MRI
->getVRegDef(OpReg
)) {
1326 switch (Def
->getOpcode()) {
1327 case SPIRV::ASSIGN_TYPE
:
1328 if (MachineInstr
*AssignToDef
=
1329 MRI
->getVRegDef(Def
->getOperand(1).getReg())) {
1330 if (AssignToDef
->getOpcode() == TargetOpcode::G_IMPLICIT_DEF
)
1331 Reg
= Def
->getOperand(2).getReg();
1334 case SPIRV::OpUndef
:
1335 Reg
= Def
->getOperand(1).getReg();
1338 unsigned DestOpCode
;
1339 if (Reg
.isValid()) {
1340 DestOpCode
= SPIRV::OpConstantNull
;
1342 DestOpCode
= TargetOpcode::COPY
;
1345 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(DestOpCode
))
1346 .addDef(I
.getOperand(0).getReg())
1348 .constrainAllUses(TII
, TRI
, RBI
);
1353 bool SPIRVInstructionSelector::selectConstVector(Register ResVReg
,
1354 const SPIRVType
*ResType
,
1355 MachineInstr
&I
) const {
1356 // TODO: only const case is supported for now.
1358 I
.operands_begin(), I
.operands_end(), [this](const MachineOperand
&MO
) {
1363 SPIRVType
*ConstTy
= this->MRI
->getVRegDef(MO
.getReg());
1364 assert(ConstTy
&& ConstTy
->getOpcode() == SPIRV::ASSIGN_TYPE
&&
1365 ConstTy
->getOperand(1).isReg());
1366 Register ConstReg
= ConstTy
->getOperand(1).getReg();
1367 const MachineInstr
*Const
= this->MRI
->getVRegDef(ConstReg
);
1369 return (Const
->getOpcode() == TargetOpcode::G_CONSTANT
||
1370 Const
->getOpcode() == TargetOpcode::G_FCONSTANT
);
1373 auto MIB
= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(),
1374 TII
.get(SPIRV::OpConstantComposite
))
1376 .addUse(GR
.getSPIRVTypeID(ResType
));
1377 for (unsigned i
= I
.getNumExplicitDefs(); i
< I
.getNumExplicitOperands(); ++i
)
1378 MIB
.addUse(I
.getOperand(i
).getReg());
1379 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1382 static unsigned getArrayComponentCount(MachineRegisterInfo
*MRI
,
1383 const SPIRVType
*ResType
) {
1384 Register OpReg
= ResType
->getOperand(2).getReg();
1385 SPIRVType
*OpDef
= MRI
->getVRegDef(OpReg
);
1388 if (OpDef
->getOpcode() == SPIRV::ASSIGN_TYPE
&&
1389 OpDef
->getOperand(1).isReg()) {
1390 if (SPIRVType
*RefDef
= MRI
->getVRegDef(OpDef
->getOperand(1).getReg()))
1393 unsigned N
= OpDef
->getOpcode() == TargetOpcode::G_CONSTANT
1394 ? OpDef
->getOperand(1).getCImm()->getValue().getZExtValue()
1399 // Return true if the type represents a constant register
1400 static bool isConstReg(MachineRegisterInfo
*MRI
, SPIRVType
*OpDef
) {
1401 if (OpDef
->getOpcode() == SPIRV::ASSIGN_TYPE
&&
1402 OpDef
->getOperand(1).isReg()) {
1403 if (SPIRVType
*RefDef
= MRI
->getVRegDef(OpDef
->getOperand(1).getReg()))
1406 return OpDef
->getOpcode() == TargetOpcode::G_CONSTANT
||
1407 OpDef
->getOpcode() == TargetOpcode::G_FCONSTANT
;
1410 // Return true if the virtual register represents a constant
1411 static bool isConstReg(MachineRegisterInfo
*MRI
, Register OpReg
) {
1412 if (SPIRVType
*OpDef
= MRI
->getVRegDef(OpReg
))
1413 return isConstReg(MRI
, OpDef
);
1417 bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg
,
1418 const SPIRVType
*ResType
,
1419 MachineInstr
&I
) const {
1421 if (ResType
->getOpcode() == SPIRV::OpTypeVector
)
1422 N
= GR
.getScalarOrVectorComponentCount(ResType
);
1423 else if (ResType
->getOpcode() == SPIRV::OpTypeArray
)
1424 N
= getArrayComponentCount(MRI
, ResType
);
1426 report_fatal_error("Cannot select G_SPLAT_VECTOR with a non-vector result");
1428 unsigned OpIdx
= I
.getNumExplicitDefs();
1429 if (!I
.getOperand(OpIdx
).isReg())
1430 report_fatal_error("Unexpected argument in G_SPLAT_VECTOR");
1432 // check if we may construct a constant vector
1433 Register OpReg
= I
.getOperand(OpIdx
).getReg();
1434 bool IsConst
= isConstReg(MRI
, OpReg
);
1436 if (!IsConst
&& N
< 2)
1438 "There must be at least two constituent operands in a vector");
1440 auto MIB
= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(),
1441 TII
.get(IsConst
? SPIRV::OpConstantComposite
1442 : SPIRV::OpCompositeConstruct
))
1444 .addUse(GR
.getSPIRVTypeID(ResType
));
1445 for (unsigned i
= 0; i
< N
; ++i
)
1447 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1450 bool SPIRVInstructionSelector::selectCmp(Register ResVReg
,
1451 const SPIRVType
*ResType
,
1453 MachineInstr
&I
) const {
1454 Register Cmp0
= I
.getOperand(2).getReg();
1455 Register Cmp1
= I
.getOperand(3).getReg();
1456 assert(GR
.getSPIRVTypeForVReg(Cmp0
)->getOpcode() ==
1457 GR
.getSPIRVTypeForVReg(Cmp1
)->getOpcode() &&
1458 "CMP operands should have the same type");
1459 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(CmpOpc
))
1461 .addUse(GR
.getSPIRVTypeID(ResType
))
1464 .constrainAllUses(TII
, TRI
, RBI
);
1467 bool SPIRVInstructionSelector::selectICmp(Register ResVReg
,
1468 const SPIRVType
*ResType
,
1469 MachineInstr
&I
) const {
1470 auto Pred
= I
.getOperand(1).getPredicate();
1473 Register CmpOperand
= I
.getOperand(2).getReg();
1474 if (GR
.isScalarOfType(CmpOperand
, SPIRV::OpTypePointer
))
1475 CmpOpc
= getPtrCmpOpcode(Pred
);
1476 else if (GR
.isScalarOrVectorOfType(CmpOperand
, SPIRV::OpTypeBool
))
1477 CmpOpc
= getBoolCmpOpcode(Pred
);
1479 CmpOpc
= getICmpOpcode(Pred
);
1480 return selectCmp(ResVReg
, ResType
, CmpOpc
, I
);
1483 void SPIRVInstructionSelector::renderFImm32(MachineInstrBuilder
&MIB
,
1484 const MachineInstr
&I
,
1486 assert(I
.getOpcode() == TargetOpcode::G_FCONSTANT
&& OpIdx
== -1 &&
1487 "Expected G_FCONSTANT");
1488 const ConstantFP
*FPImm
= I
.getOperand(1).getFPImm();
1489 addNumImm(FPImm
->getValueAPF().bitcastToAPInt(), MIB
);
1492 void SPIRVInstructionSelector::renderImm32(MachineInstrBuilder
&MIB
,
1493 const MachineInstr
&I
,
1495 assert(I
.getOpcode() == TargetOpcode::G_CONSTANT
&& OpIdx
== -1 &&
1496 "Expected G_CONSTANT");
1497 addNumImm(I
.getOperand(1).getCImm()->getValue(), MIB
);
1501 SPIRVInstructionSelector::buildI32Constant(uint32_t Val
, MachineInstr
&I
,
1502 const SPIRVType
*ResType
) const {
1503 Type
*LLVMTy
= IntegerType::get(GR
.CurMF
->getFunction().getContext(), 32);
1504 const SPIRVType
*SpvI32Ty
=
1505 ResType
? ResType
: GR
.getOrCreateSPIRVIntegerType(32, I
, TII
);
1506 // Find a constant in DT or build a new one.
1507 auto ConstInt
= ConstantInt::get(LLVMTy
, Val
);
1508 Register NewReg
= GR
.find(ConstInt
, GR
.CurMF
);
1509 if (!NewReg
.isValid()) {
1510 NewReg
= MRI
->createGenericVirtualRegister(LLT::scalar(32));
1511 GR
.add(ConstInt
, GR
.CurMF
, NewReg
);
1513 MachineBasicBlock
&BB
= *I
.getParent();
1515 MI
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpConstantNull
))
1517 .addUse(GR
.getSPIRVTypeID(SpvI32Ty
));
1519 MI
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpConstantI
))
1521 .addUse(GR
.getSPIRVTypeID(SpvI32Ty
))
1522 .addImm(APInt(32, Val
).getZExtValue());
1524 constrainSelectedInstRegOperands(*MI
, TII
, TRI
, RBI
);
1529 bool SPIRVInstructionSelector::selectFCmp(Register ResVReg
,
1530 const SPIRVType
*ResType
,
1531 MachineInstr
&I
) const {
1532 unsigned CmpOp
= getFCmpOpcode(I
.getOperand(1).getPredicate());
1533 return selectCmp(ResVReg
, ResType
, CmpOp
, I
);
1536 Register
SPIRVInstructionSelector::buildZerosVal(const SPIRVType
*ResType
,
1537 MachineInstr
&I
) const {
1538 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
1539 bool ZeroAsNull
= STI
.isOpenCLEnv();
1540 if (ResType
->getOpcode() == SPIRV::OpTypeVector
)
1541 return GR
.getOrCreateConstVector(0UL, I
, ResType
, TII
, ZeroAsNull
);
1542 return GR
.getOrCreateConstInt(0, I
, ResType
, TII
, ZeroAsNull
);
1545 static APFloat
getZeroFP(const Type
*LLVMFloatTy
) {
1547 return APFloat::getZero(APFloat::IEEEsingle());
1548 switch (LLVMFloatTy
->getScalarType()->getTypeID()) {
1549 case Type::HalfTyID
:
1550 return APFloat::getZero(APFloat::IEEEhalf());
1552 case Type::FloatTyID
:
1553 return APFloat::getZero(APFloat::IEEEsingle());
1554 case Type::DoubleTyID
:
1555 return APFloat::getZero(APFloat::IEEEdouble());
1559 Register
SPIRVInstructionSelector::buildZerosValF(const SPIRVType
*ResType
,
1560 MachineInstr
&I
) const {
1561 // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
1562 bool ZeroAsNull
= STI
.isOpenCLEnv();
1563 APFloat VZero
= getZeroFP(GR
.getTypeForSPIRVType(ResType
));
1564 if (ResType
->getOpcode() == SPIRV::OpTypeVector
)
1565 return GR
.getOrCreateConstVector(VZero
, I
, ResType
, TII
, ZeroAsNull
);
1566 return GR
.getOrCreateConstFP(VZero
, I
, ResType
, TII
, ZeroAsNull
);
1569 Register
SPIRVInstructionSelector::buildOnesVal(bool AllOnes
,
1570 const SPIRVType
*ResType
,
1571 MachineInstr
&I
) const {
1572 unsigned BitWidth
= GR
.getScalarOrVectorBitWidth(ResType
);
1574 AllOnes
? APInt::getAllOnes(BitWidth
) : APInt::getOneBitSet(BitWidth
, 0);
1575 if (ResType
->getOpcode() == SPIRV::OpTypeVector
)
1576 return GR
.getOrCreateConstVector(One
.getZExtValue(), I
, ResType
, TII
);
1577 return GR
.getOrCreateConstInt(One
.getZExtValue(), I
, ResType
, TII
);
1580 bool SPIRVInstructionSelector::selectSelect(Register ResVReg
,
1581 const SPIRVType
*ResType
,
1583 bool IsSigned
) const {
1584 // To extend a bool, we need to use OpSelect between constants.
1585 Register ZeroReg
= buildZerosVal(ResType
, I
);
1586 Register OneReg
= buildOnesVal(IsSigned
, ResType
, I
);
1588 GR
.isScalarOfType(I
.getOperand(1).getReg(), SPIRV::OpTypeBool
);
1590 IsScalarBool
? SPIRV::OpSelectSISCond
: SPIRV::OpSelectSIVCond
;
1591 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(Opcode
))
1593 .addUse(GR
.getSPIRVTypeID(ResType
))
1594 .addUse(I
.getOperand(1).getReg())
1597 .constrainAllUses(TII
, TRI
, RBI
);
1600 bool SPIRVInstructionSelector::selectIToF(Register ResVReg
,
1601 const SPIRVType
*ResType
,
1602 MachineInstr
&I
, bool IsSigned
,
1603 unsigned Opcode
) const {
1604 Register SrcReg
= I
.getOperand(1).getReg();
1605 // We can convert bool value directly to float type without OpConvert*ToF,
1606 // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
1607 if (GR
.isScalarOrVectorOfType(I
.getOperand(1).getReg(), SPIRV::OpTypeBool
)) {
1608 unsigned BitWidth
= GR
.getScalarOrVectorBitWidth(ResType
);
1609 SPIRVType
*TmpType
= GR
.getOrCreateSPIRVIntegerType(BitWidth
, I
, TII
);
1610 if (ResType
->getOpcode() == SPIRV::OpTypeVector
) {
1611 const unsigned NumElts
= ResType
->getOperand(2).getImm();
1612 TmpType
= GR
.getOrCreateSPIRVVectorType(TmpType
, NumElts
, I
, TII
);
1614 SrcReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1615 selectSelect(SrcReg
, TmpType
, I
, false);
1617 return selectUnOpWithSrc(ResVReg
, ResType
, I
, SrcReg
, Opcode
);
1620 bool SPIRVInstructionSelector::selectExt(Register ResVReg
,
1621 const SPIRVType
*ResType
,
1622 MachineInstr
&I
, bool IsSigned
) const {
1623 Register SrcReg
= I
.getOperand(1).getReg();
1624 if (GR
.isScalarOrVectorOfType(SrcReg
, SPIRV::OpTypeBool
))
1625 return selectSelect(ResVReg
, ResType
, I
, IsSigned
);
1627 SPIRVType
*SrcType
= GR
.getSPIRVTypeForVReg(SrcReg
);
1628 if (SrcType
== ResType
)
1629 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(),
1630 TII
.get(TargetOpcode::COPY
))
1633 .constrainAllUses(TII
, TRI
, RBI
);
1635 unsigned Opcode
= IsSigned
? SPIRV::OpSConvert
: SPIRV::OpUConvert
;
1636 return selectUnOp(ResVReg
, ResType
, I
, Opcode
);
1639 bool SPIRVInstructionSelector::selectIntToBool(Register IntReg
,
1642 const SPIRVType
*IntTy
,
1643 const SPIRVType
*BoolTy
) const {
1644 // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
1645 Register BitIntReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1646 bool IsVectorTy
= IntTy
->getOpcode() == SPIRV::OpTypeVector
;
1647 unsigned Opcode
= IsVectorTy
? SPIRV::OpBitwiseAndV
: SPIRV::OpBitwiseAndS
;
1648 Register Zero
= buildZerosVal(IntTy
, I
);
1649 Register One
= buildOnesVal(false, IntTy
, I
);
1650 MachineBasicBlock
&BB
= *I
.getParent();
1651 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(Opcode
))
1653 .addUse(GR
.getSPIRVTypeID(IntTy
))
1656 .constrainAllUses(TII
, TRI
, RBI
);
1657 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpINotEqual
))
1659 .addUse(GR
.getSPIRVTypeID(BoolTy
))
1662 .constrainAllUses(TII
, TRI
, RBI
);
1665 bool SPIRVInstructionSelector::selectTrunc(Register ResVReg
,
1666 const SPIRVType
*ResType
,
1667 MachineInstr
&I
) const {
1668 Register IntReg
= I
.getOperand(1).getReg();
1669 const SPIRVType
*ArgType
= GR
.getSPIRVTypeForVReg(IntReg
);
1670 if (GR
.isScalarOrVectorOfType(ResVReg
, SPIRV::OpTypeBool
))
1671 return selectIntToBool(IntReg
, ResVReg
, I
, ArgType
, ResType
);
1672 if (ArgType
== ResType
)
1673 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(),
1674 TII
.get(TargetOpcode::COPY
))
1677 .constrainAllUses(TII
, TRI
, RBI
);
1678 bool IsSigned
= GR
.isScalarOrVectorSigned(ResType
);
1679 unsigned Opcode
= IsSigned
? SPIRV::OpSConvert
: SPIRV::OpUConvert
;
1680 return selectUnOp(ResVReg
, ResType
, I
, Opcode
);
1683 bool SPIRVInstructionSelector::selectConst(Register ResVReg
,
1684 const SPIRVType
*ResType
,
1686 MachineInstr
&I
) const {
1687 unsigned TyOpcode
= ResType
->getOpcode();
1688 assert(TyOpcode
!= SPIRV::OpTypePointer
|| Imm
.isZero());
1689 MachineBasicBlock
&BB
= *I
.getParent();
1690 if ((TyOpcode
== SPIRV::OpTypePointer
|| TyOpcode
== SPIRV::OpTypeEvent
) &&
1692 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpConstantNull
))
1694 .addUse(GR
.getSPIRVTypeID(ResType
))
1695 .constrainAllUses(TII
, TRI
, RBI
);
1696 if (TyOpcode
== SPIRV::OpTypeInt
) {
1697 assert(Imm
.getBitWidth() <= 64 && "Unsupported integer width!");
1698 Register Reg
= GR
.getOrCreateConstInt(Imm
.getZExtValue(), I
, ResType
, TII
);
1701 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(TargetOpcode::COPY
))
1704 .constrainAllUses(TII
, TRI
, RBI
);
1706 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpConstantI
))
1708 .addUse(GR
.getSPIRVTypeID(ResType
));
1709 // <=32-bit integers should be caught by the sdag pattern.
1710 assert(Imm
.getBitWidth() > 32);
1711 addNumImm(Imm
, MIB
);
1712 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1715 bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg
,
1716 const SPIRVType
*ResType
,
1717 MachineInstr
&I
) const {
1718 return BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(SPIRV::OpUndef
))
1720 .addUse(GR
.getSPIRVTypeID(ResType
))
1721 .constrainAllUses(TII
, TRI
, RBI
);
1724 static bool isImm(const MachineOperand
&MO
, MachineRegisterInfo
*MRI
) {
1726 const SPIRVType
*TypeInst
= MRI
->getVRegDef(MO
.getReg());
1727 if (TypeInst
->getOpcode() != SPIRV::ASSIGN_TYPE
)
1729 assert(TypeInst
->getOperand(1).isReg());
1730 MachineInstr
*ImmInst
= MRI
->getVRegDef(TypeInst
->getOperand(1).getReg());
1731 return ImmInst
->getOpcode() == TargetOpcode::G_CONSTANT
;
1734 static int64_t foldImm(const MachineOperand
&MO
, MachineRegisterInfo
*MRI
) {
1735 const SPIRVType
*TypeInst
= MRI
->getVRegDef(MO
.getReg());
1736 MachineInstr
*ImmInst
= MRI
->getVRegDef(TypeInst
->getOperand(1).getReg());
1737 assert(ImmInst
->getOpcode() == TargetOpcode::G_CONSTANT
);
1738 return ImmInst
->getOperand(1).getCImm()->getZExtValue();
1741 bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg
,
1742 const SPIRVType
*ResType
,
1743 MachineInstr
&I
) const {
1744 MachineBasicBlock
&BB
= *I
.getParent();
1745 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpCompositeInsert
))
1747 .addUse(GR
.getSPIRVTypeID(ResType
))
1749 .addUse(I
.getOperand(3).getReg())
1750 // composite to insert into
1751 .addUse(I
.getOperand(2).getReg());
1752 for (unsigned i
= 4; i
< I
.getNumOperands(); i
++)
1753 MIB
.addImm(foldImm(I
.getOperand(i
), MRI
));
1754 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1757 bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg
,
1758 const SPIRVType
*ResType
,
1759 MachineInstr
&I
) const {
1760 MachineBasicBlock
&BB
= *I
.getParent();
1761 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpCompositeExtract
))
1763 .addUse(GR
.getSPIRVTypeID(ResType
))
1764 .addUse(I
.getOperand(2).getReg());
1765 for (unsigned i
= 3; i
< I
.getNumOperands(); i
++)
1766 MIB
.addImm(foldImm(I
.getOperand(i
), MRI
));
1767 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1770 bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg
,
1771 const SPIRVType
*ResType
,
1772 MachineInstr
&I
) const {
1773 if (isImm(I
.getOperand(4), MRI
))
1774 return selectInsertVal(ResVReg
, ResType
, I
);
1775 MachineBasicBlock
&BB
= *I
.getParent();
1776 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpVectorInsertDynamic
))
1778 .addUse(GR
.getSPIRVTypeID(ResType
))
1779 .addUse(I
.getOperand(2).getReg())
1780 .addUse(I
.getOperand(3).getReg())
1781 .addUse(I
.getOperand(4).getReg())
1782 .constrainAllUses(TII
, TRI
, RBI
);
1785 bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg
,
1786 const SPIRVType
*ResType
,
1787 MachineInstr
&I
) const {
1788 if (isImm(I
.getOperand(3), MRI
))
1789 return selectExtractVal(ResVReg
, ResType
, I
);
1790 MachineBasicBlock
&BB
= *I
.getParent();
1791 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpVectorExtractDynamic
))
1793 .addUse(GR
.getSPIRVTypeID(ResType
))
1794 .addUse(I
.getOperand(2).getReg())
1795 .addUse(I
.getOperand(3).getReg())
1796 .constrainAllUses(TII
, TRI
, RBI
);
1799 bool SPIRVInstructionSelector::selectGEP(Register ResVReg
,
1800 const SPIRVType
*ResType
,
1801 MachineInstr
&I
) const {
1802 const bool IsGEPInBounds
= I
.getOperand(2).getImm();
1804 // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator only
1805 // relies on PtrAccessChain, so we'll try not to deviate. For Vulkan however,
1806 // we have to use Op[InBounds]AccessChain.
1807 const unsigned Opcode
= STI
.isVulkanEnv()
1808 ? (IsGEPInBounds
? SPIRV::OpInBoundsAccessChain
1809 : SPIRV::OpAccessChain
)
1810 : (IsGEPInBounds
? SPIRV::OpInBoundsPtrAccessChain
1811 : SPIRV::OpPtrAccessChain
);
1813 auto Res
= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(Opcode
))
1815 .addUse(GR
.getSPIRVTypeID(ResType
))
1816 // Object to get a pointer to.
1817 .addUse(I
.getOperand(3).getReg());
1819 const unsigned StartingIndex
=
1820 (Opcode
== SPIRV::OpAccessChain
|| Opcode
== SPIRV::OpInBoundsAccessChain
)
1823 for (unsigned i
= StartingIndex
; i
< I
.getNumExplicitOperands(); ++i
)
1824 Res
.addUse(I
.getOperand(i
).getReg());
1825 return Res
.constrainAllUses(TII
, TRI
, RBI
);
1828 // Maybe wrap a value into OpSpecConstantOp
1829 bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
1830 MachineInstr
&I
, SmallVector
<Register
> &CompositeArgs
) const {
1832 unsigned Lim
= I
.getNumExplicitOperands();
1833 for (unsigned i
= I
.getNumExplicitDefs() + 1; i
< Lim
; ++i
) {
1834 Register OpReg
= I
.getOperand(i
).getReg();
1835 SPIRVType
*OpDefine
= MRI
->getVRegDef(OpReg
);
1836 SPIRVType
*OpType
= GR
.getSPIRVTypeForVReg(OpReg
);
1837 if (!OpDefine
|| !OpType
|| isConstReg(MRI
, OpDefine
) ||
1838 OpDefine
->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST
) {
1839 // The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed
1840 // by selectAddrSpaceCast()
1841 CompositeArgs
.push_back(OpReg
);
1844 MachineFunction
*MF
= I
.getMF();
1845 Register WrapReg
= GR
.find(OpDefine
, MF
);
1846 if (WrapReg
.isValid()) {
1847 CompositeArgs
.push_back(WrapReg
);
1850 // Create a new register for the wrapper
1851 WrapReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
1852 GR
.add(OpDefine
, MF
, WrapReg
);
1853 CompositeArgs
.push_back(WrapReg
);
1854 // Decorate the wrapper register and generate a new instruction
1855 MRI
->setType(WrapReg
, LLT::pointer(0, 32));
1856 GR
.assignSPIRVTypeToVReg(OpType
, WrapReg
, *MF
);
1857 MachineBasicBlock
&BB
= *I
.getParent();
1858 Result
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpSpecConstantOp
))
1860 .addUse(GR
.getSPIRVTypeID(OpType
))
1861 .addImm(static_cast<uint32_t>(SPIRV::Opcode::Bitcast
))
1863 .constrainAllUses(TII
, TRI
, RBI
);
1870 bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg
,
1871 const SPIRVType
*ResType
,
1872 MachineInstr
&I
) const {
1873 MachineBasicBlock
&BB
= *I
.getParent();
1874 Intrinsic::ID IID
= cast
<GIntrinsic
>(I
).getIntrinsicID();
1876 case Intrinsic::spv_load
:
1877 return selectLoad(ResVReg
, ResType
, I
);
1878 case Intrinsic::spv_store
:
1879 return selectStore(I
);
1880 case Intrinsic::spv_extractv
:
1881 return selectExtractVal(ResVReg
, ResType
, I
);
1882 case Intrinsic::spv_insertv
:
1883 return selectInsertVal(ResVReg
, ResType
, I
);
1884 case Intrinsic::spv_extractelt
:
1885 return selectExtractElt(ResVReg
, ResType
, I
);
1886 case Intrinsic::spv_insertelt
:
1887 return selectInsertElt(ResVReg
, ResType
, I
);
1888 case Intrinsic::spv_gep
:
1889 return selectGEP(ResVReg
, ResType
, I
);
1890 case Intrinsic::spv_unref_global
:
1891 case Intrinsic::spv_init_global
: {
1892 MachineInstr
*MI
= MRI
->getVRegDef(I
.getOperand(1).getReg());
1893 MachineInstr
*Init
= I
.getNumExplicitOperands() > 2
1894 ? MRI
->getVRegDef(I
.getOperand(2).getReg())
1897 return selectGlobalValue(MI
->getOperand(0).getReg(), *MI
, Init
);
1899 case Intrinsic::spv_undef
: {
1900 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpUndef
))
1902 .addUse(GR
.getSPIRVTypeID(ResType
));
1903 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1905 case Intrinsic::spv_const_composite
: {
1906 // If no values are attached, the composite is null constant.
1907 bool IsNull
= I
.getNumExplicitDefs() + 1 == I
.getNumExplicitOperands();
1908 // Select a proper instruction.
1909 unsigned Opcode
= SPIRV::OpConstantNull
;
1910 SmallVector
<Register
> CompositeArgs
;
1912 Opcode
= SPIRV::OpConstantComposite
;
1913 if (!wrapIntoSpecConstantOp(I
, CompositeArgs
))
1916 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(Opcode
))
1918 .addUse(GR
.getSPIRVTypeID(ResType
));
1919 // skip type MD node we already used when generated assign.type for this
1921 for (Register OpReg
: CompositeArgs
)
1924 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1926 case Intrinsic::spv_assign_name
: {
1927 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpName
));
1928 MIB
.addUse(I
.getOperand(I
.getNumExplicitDefs() + 1).getReg());
1929 for (unsigned i
= I
.getNumExplicitDefs() + 2;
1930 i
< I
.getNumExplicitOperands(); ++i
) {
1931 MIB
.addImm(I
.getOperand(i
).getImm());
1933 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1935 case Intrinsic::spv_switch
: {
1936 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpSwitch
));
1937 for (unsigned i
= 1; i
< I
.getNumExplicitOperands(); ++i
) {
1938 if (I
.getOperand(i
).isReg())
1939 MIB
.addReg(I
.getOperand(i
).getReg());
1940 else if (I
.getOperand(i
).isCImm())
1941 addNumImm(I
.getOperand(i
).getCImm()->getValue(), MIB
);
1942 else if (I
.getOperand(i
).isMBB())
1943 MIB
.addMBB(I
.getOperand(i
).getMBB());
1945 llvm_unreachable("Unexpected OpSwitch operand");
1947 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
1949 case Intrinsic::spv_cmpxchg
:
1950 return selectAtomicCmpXchg(ResVReg
, ResType
, I
);
1951 case Intrinsic::spv_unreachable
:
1952 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpUnreachable
));
1954 case Intrinsic::spv_alloca
:
1955 return selectFrameIndex(ResVReg
, ResType
, I
);
1956 case Intrinsic::spv_alloca_array
:
1957 return selectAllocaArray(ResVReg
, ResType
, I
);
1958 case Intrinsic::spv_assume
:
1959 if (STI
.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume
))
1960 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpAssumeTrueKHR
))
1961 .addUse(I
.getOperand(1).getReg());
1963 case Intrinsic::spv_expect
:
1964 if (STI
.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume
))
1965 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpExpectKHR
))
1967 .addUse(GR
.getSPIRVTypeID(ResType
))
1968 .addUse(I
.getOperand(2).getReg())
1969 .addUse(I
.getOperand(3).getReg());
1971 case Intrinsic::spv_thread_id
:
1972 return selectSpvThreadId(ResVReg
, ResType
, I
);
1973 case Intrinsic::spv_all
:
1974 return selectAll(ResVReg
, ResType
, I
);
1975 case Intrinsic::spv_any
:
1976 return selectAny(ResVReg
, ResType
, I
);
1977 case Intrinsic::spv_lerp
:
1978 return selectFmix(ResVReg
, ResType
, I
);
1979 case Intrinsic::spv_lifetime_start
:
1980 case Intrinsic::spv_lifetime_end
: {
1981 unsigned Op
= IID
== Intrinsic::spv_lifetime_start
? SPIRV::OpLifetimeStart
1982 : SPIRV::OpLifetimeStop
;
1983 int64_t Size
= I
.getOperand(I
.getNumExplicitDefs() + 1).getImm();
1984 Register PtrReg
= I
.getOperand(I
.getNumExplicitDefs() + 2).getReg();
1985 unsigned PonteeOpType
= GR
.getPointeeTypeOp(PtrReg
);
1986 bool IsNonvoidPtr
= PonteeOpType
!= 0 && PonteeOpType
!= SPIRV::OpTypeVoid
;
1987 if (Size
== -1 || IsNonvoidPtr
)
1989 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(Op
)).addUse(PtrReg
).addImm(Size
);
1992 std::string DiagMsg
;
1993 raw_string_ostream
OS(DiagMsg
);
1995 DiagMsg
= "Intrinsic selection not implemented: " + DiagMsg
;
1996 report_fatal_error(DiagMsg
.c_str(), false);
2002 bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg
,
2003 const SPIRVType
*ResType
,
2004 MachineInstr
&I
) const {
2005 // there was an allocation size parameter to the allocation instruction
2007 MachineBasicBlock
&BB
= *I
.getParent();
2008 return BuildMI(BB
, I
, I
.getDebugLoc(),
2009 TII
.get(SPIRV::OpVariableLengthArrayINTEL
))
2011 .addUse(GR
.getSPIRVTypeID(ResType
))
2012 .addUse(I
.getOperand(2).getReg())
2013 .constrainAllUses(TII
, TRI
, RBI
);
2016 bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg
,
2017 const SPIRVType
*ResType
,
2018 MachineInstr
&I
) const {
2019 // Change order of instructions if needed: all OpVariable instructions in a
2020 // function must be the first instructions in the first block
2021 MachineFunction
*MF
= I
.getParent()->getParent();
2022 MachineBasicBlock
*MBB
= &MF
->front();
2023 auto It
= MBB
->SkipPHIsAndLabels(MBB
->begin()), E
= MBB
->end();
2024 bool IsHeader
= false;
2026 for (; It
!= E
&& It
!= I
; ++It
) {
2027 Opcode
= It
->getOpcode();
2028 if (Opcode
== SPIRV::OpFunction
|| Opcode
== SPIRV::OpFunctionParameter
) {
2030 } else if (IsHeader
&&
2031 !(Opcode
== SPIRV::ASSIGN_TYPE
|| Opcode
== SPIRV::OpLabel
)) {
2036 return BuildMI(*MBB
, It
, It
->getDebugLoc(), TII
.get(SPIRV::OpVariable
))
2038 .addUse(GR
.getSPIRVTypeID(ResType
))
2039 .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function
))
2040 .constrainAllUses(TII
, TRI
, RBI
);
2043 bool SPIRVInstructionSelector::selectBranch(MachineInstr
&I
) const {
2044 // InstructionSelector walks backwards through the instructions. We can use
2045 // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
2046 // first, so can generate an OpBranchConditional here. If there is no
2047 // G_BRCOND, we just use OpBranch for a regular unconditional branch.
2048 const MachineInstr
*PrevI
= I
.getPrevNode();
2049 MachineBasicBlock
&MBB
= *I
.getParent();
2050 if (PrevI
!= nullptr && PrevI
->getOpcode() == TargetOpcode::G_BRCOND
) {
2051 return BuildMI(MBB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpBranchConditional
))
2052 .addUse(PrevI
->getOperand(0).getReg())
2053 .addMBB(PrevI
->getOperand(1).getMBB())
2054 .addMBB(I
.getOperand(0).getMBB())
2055 .constrainAllUses(TII
, TRI
, RBI
);
2057 return BuildMI(MBB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpBranch
))
2058 .addMBB(I
.getOperand(0).getMBB())
2059 .constrainAllUses(TII
, TRI
, RBI
);
2062 bool SPIRVInstructionSelector::selectBranchCond(MachineInstr
&I
) const {
2063 // InstructionSelector walks backwards through the instructions. For an
2064 // explicit conditional branch with no fallthrough, we use both a G_BR and a
2065 // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
2066 // generate the OpBranchConditional in selectBranch above.
2068 // If an OpBranchConditional has been generated, we simply return, as the work
2069 // is alread done. If there is no OpBranchConditional, LLVM must be relying on
2070 // implicit fallthrough to the next basic block, so we need to create an
2071 // OpBranchConditional with an explicit "false" argument pointing to the next
2072 // basic block that LLVM would fall through to.
2073 const MachineInstr
*NextI
= I
.getNextNode();
2074 // Check if this has already been successfully selected.
2075 if (NextI
!= nullptr && NextI
->getOpcode() == SPIRV::OpBranchConditional
)
2077 // Must be relying on implicit block fallthrough, so generate an
2078 // OpBranchConditional with the "next" basic block as the "false" target.
2079 MachineBasicBlock
&MBB
= *I
.getParent();
2080 unsigned NextMBBNum
= MBB
.getNextNode()->getNumber();
2081 MachineBasicBlock
*NextMBB
= I
.getMF()->getBlockNumbered(NextMBBNum
);
2082 return BuildMI(MBB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpBranchConditional
))
2083 .addUse(I
.getOperand(0).getReg())
2084 .addMBB(I
.getOperand(1).getMBB())
2086 .constrainAllUses(TII
, TRI
, RBI
);
2089 bool SPIRVInstructionSelector::selectPhi(Register ResVReg
,
2090 const SPIRVType
*ResType
,
2091 MachineInstr
&I
) const {
2092 auto MIB
= BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(SPIRV::OpPhi
))
2094 .addUse(GR
.getSPIRVTypeID(ResType
));
2095 const unsigned NumOps
= I
.getNumOperands();
2096 for (unsigned i
= 1; i
< NumOps
; i
+= 2) {
2097 MIB
.addUse(I
.getOperand(i
+ 0).getReg());
2098 MIB
.addMBB(I
.getOperand(i
+ 1).getMBB());
2100 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
2103 bool SPIRVInstructionSelector::selectGlobalValue(
2104 Register ResVReg
, MachineInstr
&I
, const MachineInstr
*Init
) const {
2105 // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
2106 MachineIRBuilder
MIRBuilder(I
);
2107 const GlobalValue
*GV
= I
.getOperand(1).getGlobal();
2108 Type
*GVType
= GR
.getDeducedGlobalValueType(GV
);
2109 SPIRVType
*PointerBaseType
;
2110 if (GVType
->isArrayTy()) {
2111 SPIRVType
*ArrayElementType
=
2112 GR
.getOrCreateSPIRVType(GVType
->getArrayElementType(), MIRBuilder
,
2113 SPIRV::AccessQualifier::ReadWrite
, false);
2114 PointerBaseType
= GR
.getOrCreateSPIRVArrayType(
2115 ArrayElementType
, GVType
->getArrayNumElements(), I
, TII
);
2117 PointerBaseType
= GR
.getOrCreateSPIRVType(
2118 GVType
, MIRBuilder
, SPIRV::AccessQualifier::ReadWrite
, false);
2120 SPIRVType
*ResType
= GR
.getOrCreateSPIRVPointerType(
2121 PointerBaseType
, I
, TII
,
2122 addressSpaceToStorageClass(GV
->getAddressSpace(), STI
));
2124 std::string GlobalIdent
;
2125 if (!GV
->hasName()) {
2126 unsigned &ID
= UnnamedGlobalIDs
[GV
];
2128 ID
= UnnamedGlobalIDs
.size();
2129 GlobalIdent
= "__unnamed_" + Twine(ID
).str();
2131 GlobalIdent
= GV
->getGlobalIdentifier();
2134 // Behaviour of functions as operands depends on availability of the
2135 // corresponding extension (SPV_INTEL_function_pointers):
2136 // - If there is an extension to operate with functions as operands:
2137 // We create a proper constant operand and evaluate a correct type for a
2138 // function pointer.
2139 // - Without the required extension:
2140 // We have functions as operands in tests with blocks of instruction e.g. in
2141 // transcoding/global_block.ll. These operands are not used and should be
2142 // substituted by zero constants. Their type is expected to be always
2143 // OpTypePointer Function %uchar.
2144 if (isa
<Function
>(GV
)) {
2145 const Constant
*ConstVal
= GV
;
2146 MachineBasicBlock
&BB
= *I
.getParent();
2147 Register NewReg
= GR
.find(ConstVal
, GR
.CurMF
);
2148 if (!NewReg
.isValid()) {
2149 Register NewReg
= ResVReg
;
2150 GR
.add(ConstVal
, GR
.CurMF
, NewReg
);
2151 const Function
*GVFun
=
2152 STI
.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers
)
2153 ? dyn_cast
<Function
>(GV
)
2156 // References to a function via function pointers generate virtual
2157 // registers without a definition. We will resolve it later, during
2158 // module analysis stage.
2159 MachineRegisterInfo
*MRI
= MIRBuilder
.getMRI();
2160 Register FuncVReg
= MRI
->createGenericVirtualRegister(LLT::scalar(32));
2161 MRI
->setRegClass(FuncVReg
, &SPIRV::IDRegClass
);
2162 MachineInstrBuilder MB
=
2163 BuildMI(BB
, I
, I
.getDebugLoc(),
2164 TII
.get(SPIRV::OpConstantFunctionPointerINTEL
))
2166 .addUse(GR
.getSPIRVTypeID(ResType
))
2168 // mapping the function pointer to the used Function
2169 GR
.recordFunctionPointer(&MB
.getInstr()->getOperand(2), GVFun
);
2170 return MB
.constrainAllUses(TII
, TRI
, RBI
);
2172 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpConstantNull
))
2174 .addUse(GR
.getSPIRVTypeID(ResType
))
2175 .constrainAllUses(TII
, TRI
, RBI
);
2177 assert(NewReg
!= ResVReg
);
2178 return BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(TargetOpcode::COPY
))
2181 .constrainAllUses(TII
, TRI
, RBI
);
2183 auto GlobalVar
= cast
<GlobalVariable
>(GV
);
2184 assert(GlobalVar
->getName() != "llvm.global.annotations");
2186 bool HasInit
= GlobalVar
->hasInitializer() &&
2187 !isa
<UndefValue
>(GlobalVar
->getInitializer());
2188 // Skip empty declaration for GVs with initilaizers till we get the decl with
2189 // passed initializer.
2190 if (HasInit
&& !Init
)
2193 unsigned AddrSpace
= GV
->getAddressSpace();
2194 SPIRV::StorageClass::StorageClass Storage
=
2195 addressSpaceToStorageClass(AddrSpace
, STI
);
2196 bool HasLnkTy
= GV
->getLinkage() != GlobalValue::InternalLinkage
&&
2197 Storage
!= SPIRV::StorageClass::Function
;
2198 SPIRV::LinkageType::LinkageType LnkType
=
2199 (GV
->isDeclaration() || GV
->hasAvailableExternallyLinkage())
2200 ? SPIRV::LinkageType::Import
2201 : (GV
->getLinkage() == GlobalValue::LinkOnceODRLinkage
&&
2202 STI
.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr
)
2203 ? SPIRV::LinkageType::LinkOnceODR
2204 : SPIRV::LinkageType::Export
);
2206 Register Reg
= GR
.buildGlobalVariable(ResVReg
, ResType
, GlobalIdent
, GV
,
2207 Storage
, Init
, GlobalVar
->isConstant(),
2208 HasLnkTy
, LnkType
, MIRBuilder
, true);
2209 return Reg
.isValid();
2212 bool SPIRVInstructionSelector::selectLog10(Register ResVReg
,
2213 const SPIRVType
*ResType
,
2214 MachineInstr
&I
) const {
2215 if (STI
.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std
)) {
2216 return selectExtInst(ResVReg
, ResType
, I
, CL::log10
);
2219 // There is no log10 instruction in the GLSL Extended Instruction set, so it
2220 // is implemented as:
2221 // log10(x) = log2(x) * (1 / log2(10))
2222 // = log2(x) * 0.30103
2224 MachineIRBuilder
MIRBuilder(I
);
2225 MachineBasicBlock
&BB
= *I
.getParent();
2228 Register VarReg
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
2230 BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpExtInst
))
2232 .addUse(GR
.getSPIRVTypeID(ResType
))
2233 .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450
))
2235 .add(I
.getOperand(1))
2236 .constrainAllUses(TII
, TRI
, RBI
);
2239 assert(ResType
->getOpcode() == SPIRV::OpTypeVector
||
2240 ResType
->getOpcode() == SPIRV::OpTypeFloat
);
2241 // TODO: Add matrix implementation once supported by the HLSL frontend.
2242 const SPIRVType
*SpirvScalarType
=
2243 ResType
->getOpcode() == SPIRV::OpTypeVector
2244 ? GR
.getSPIRVTypeForVReg(ResType
->getOperand(1).getReg())
2247 GR
.buildConstantFP(APFloat(0.30103f
), MIRBuilder
, SpirvScalarType
);
2249 // Multiply log2(x) by 0.30103 to get log10(x) result.
2250 auto Opcode
= ResType
->getOpcode() == SPIRV::OpTypeVector
2251 ? SPIRV::OpVectorTimesScalar
2253 Result
&= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(Opcode
))
2255 .addUse(GR
.getSPIRVTypeID(ResType
))
2258 .constrainAllUses(TII
, TRI
, RBI
);
2263 bool SPIRVInstructionSelector::selectSpvThreadId(Register ResVReg
,
2264 const SPIRVType
*ResType
,
2265 MachineInstr
&I
) const {
2266 // DX intrinsic: @llvm.dx.thread.id(i32)
2267 // ID Name Description
2268 // 93 ThreadId reads the thread ID
2270 MachineIRBuilder
MIRBuilder(I
);
2271 const SPIRVType
*U32Type
= GR
.getOrCreateSPIRVIntegerType(32, MIRBuilder
);
2272 const SPIRVType
*Vec3Ty
=
2273 GR
.getOrCreateSPIRVVectorType(U32Type
, 3, MIRBuilder
);
2274 const SPIRVType
*PtrType
= GR
.getOrCreateSPIRVPointerType(
2275 Vec3Ty
, MIRBuilder
, SPIRV::StorageClass::Input
);
2277 // Create new register for GlobalInvocationID builtin variable.
2278 Register NewRegister
=
2279 MIRBuilder
.getMRI()->createVirtualRegister(&SPIRV::IDRegClass
);
2280 MIRBuilder
.getMRI()->setType(NewRegister
, LLT::pointer(0, 32));
2281 GR
.assignSPIRVTypeToVReg(PtrType
, NewRegister
, MIRBuilder
.getMF());
2283 // Build GlobalInvocationID global variable with the necessary decorations.
2284 Register Variable
= GR
.buildGlobalVariable(
2285 NewRegister
, PtrType
,
2286 getLinkStringForBuiltIn(SPIRV::BuiltIn::GlobalInvocationId
), nullptr,
2287 SPIRV::StorageClass::Input
, nullptr, true, true,
2288 SPIRV::LinkageType::Import
, MIRBuilder
, false);
2290 // Create new register for loading value.
2291 MachineRegisterInfo
*MRI
= MIRBuilder
.getMRI();
2292 Register LoadedRegister
= MRI
->createVirtualRegister(&SPIRV::IDRegClass
);
2293 MIRBuilder
.getMRI()->setType(LoadedRegister
, LLT::pointer(0, 32));
2294 GR
.assignSPIRVTypeToVReg(Vec3Ty
, LoadedRegister
, MIRBuilder
.getMF());
2296 // Load v3uint value from the global variable.
2297 BuildMI(*I
.getParent(), I
, I
.getDebugLoc(), TII
.get(SPIRV::OpLoad
))
2298 .addDef(LoadedRegister
)
2299 .addUse(GR
.getSPIRVTypeID(Vec3Ty
))
2302 // Get Thread ID index. Expecting operand is a constant immediate value,
2303 // wrapped in a type assignment.
2304 assert(I
.getOperand(2).isReg());
2305 Register ThreadIdReg
= I
.getOperand(2).getReg();
2306 SPIRVType
*ConstTy
= this->MRI
->getVRegDef(ThreadIdReg
);
2307 assert(ConstTy
&& ConstTy
->getOpcode() == SPIRV::ASSIGN_TYPE
&&
2308 ConstTy
->getOperand(1).isReg());
2309 Register ConstReg
= ConstTy
->getOperand(1).getReg();
2310 const MachineInstr
*Const
= this->MRI
->getVRegDef(ConstReg
);
2311 assert(Const
&& Const
->getOpcode() == TargetOpcode::G_CONSTANT
);
2312 const llvm::APInt
&Val
= Const
->getOperand(1).getCImm()->getValue();
2313 const uint32_t ThreadId
= Val
.getZExtValue();
2315 // Extract the thread ID from the loaded vector value.
2316 MachineBasicBlock
&BB
= *I
.getParent();
2317 auto MIB
= BuildMI(BB
, I
, I
.getDebugLoc(), TII
.get(SPIRV::OpCompositeExtract
))
2319 .addUse(GR
.getSPIRVTypeID(ResType
))
2320 .addUse(LoadedRegister
)
2322 return MIB
.constrainAllUses(TII
, TRI
, RBI
);
2326 InstructionSelector
*
2327 createSPIRVInstructionSelector(const SPIRVTargetMachine
&TM
,
2328 const SPIRVSubtarget
&Subtarget
,
2329 const RegisterBankInfo
&RBI
) {
2330 return new SPIRVInstructionSelector(TM
, Subtarget
, RBI
);