xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===- SPIRVInstructionSelector.cpp ------------------------------*- C++ -*-==//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file implements the targeting of the InstructionSelector class for
1081ad6265SDimitry Andric // SPIRV.
1181ad6265SDimitry Andric // TODO: This should be generated by TableGen.
1281ad6265SDimitry Andric //
1381ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1481ad6265SDimitry Andric 
155f757f3fSDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h"
165f757f3fSDimitry Andric #include "MCTargetDesc/SPIRVMCTargetDesc.h"
1781ad6265SDimitry Andric #include "SPIRV.h"
1881ad6265SDimitry Andric #include "SPIRVGlobalRegistry.h"
1981ad6265SDimitry Andric #include "SPIRVInstrInfo.h"
2081ad6265SDimitry Andric #include "SPIRVRegisterBankInfo.h"
2181ad6265SDimitry Andric #include "SPIRVRegisterInfo.h"
2281ad6265SDimitry Andric #include "SPIRVTargetMachine.h"
2381ad6265SDimitry Andric #include "SPIRVUtils.h"
2481ad6265SDimitry Andric #include "llvm/ADT/APFloat.h"
2506c3fb27SDimitry Andric #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
265f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
2781ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
2881ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
29*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineModuleInfoImpls.h"
3081ad6265SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
31*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
3281ad6265SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h"
3381ad6265SDimitry Andric #include "llvm/Support/Debug.h"
3481ad6265SDimitry Andric 
35*0fca6ea1SDimitry Andric namespace llvm {
36*0fca6ea1SDimitry Andric 
37*0fca6ea1SDimitry Andric class SPIRVMachineModuleInfo : public MachineModuleInfoImpl {
38*0fca6ea1SDimitry Andric public:
39*0fca6ea1SDimitry Andric   SyncScope::ID Work_ItemSSID;
40*0fca6ea1SDimitry Andric   SyncScope::ID WorkGroupSSID;
41*0fca6ea1SDimitry Andric   SyncScope::ID DeviceSSID;
42*0fca6ea1SDimitry Andric   SyncScope::ID AllSVMDevicesSSID;
43*0fca6ea1SDimitry Andric   SyncScope::ID SubGroupSSID;
44*0fca6ea1SDimitry Andric 
45*0fca6ea1SDimitry Andric   SPIRVMachineModuleInfo(const MachineModuleInfo &MMI) {
46*0fca6ea1SDimitry Andric     LLVMContext &CTX = MMI.getModule()->getContext();
47*0fca6ea1SDimitry Andric     Work_ItemSSID = CTX.getOrInsertSyncScopeID("work_item");
48*0fca6ea1SDimitry Andric     WorkGroupSSID = CTX.getOrInsertSyncScopeID("workgroup");
49*0fca6ea1SDimitry Andric     DeviceSSID = CTX.getOrInsertSyncScopeID("device");
50*0fca6ea1SDimitry Andric     AllSVMDevicesSSID = CTX.getOrInsertSyncScopeID("all_svm_devices");
51*0fca6ea1SDimitry Andric     SubGroupSSID = CTX.getOrInsertSyncScopeID("sub_group");
52*0fca6ea1SDimitry Andric   }
53*0fca6ea1SDimitry Andric };
54*0fca6ea1SDimitry Andric 
55*0fca6ea1SDimitry Andric } // end namespace llvm
56*0fca6ea1SDimitry Andric 
5781ad6265SDimitry Andric #define DEBUG_TYPE "spirv-isel"
5881ad6265SDimitry Andric 
5981ad6265SDimitry Andric using namespace llvm;
60bdd1243dSDimitry Andric namespace CL = SPIRV::OpenCLExtInst;
61bdd1243dSDimitry Andric namespace GL = SPIRV::GLSLExtInst;
62bdd1243dSDimitry Andric 
63bdd1243dSDimitry Andric using ExtInstList =
64bdd1243dSDimitry Andric     std::vector<std::pair<SPIRV::InstructionSet::InstructionSet, uint32_t>>;
6581ad6265SDimitry Andric 
6681ad6265SDimitry Andric namespace {
6781ad6265SDimitry Andric 
6881ad6265SDimitry Andric #define GET_GLOBALISEL_PREDICATE_BITSET
6981ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
7081ad6265SDimitry Andric #undef GET_GLOBALISEL_PREDICATE_BITSET
7181ad6265SDimitry Andric 
7281ad6265SDimitry Andric class SPIRVInstructionSelector : public InstructionSelector {
7381ad6265SDimitry Andric   const SPIRVSubtarget &STI;
7481ad6265SDimitry Andric   const SPIRVInstrInfo &TII;
7581ad6265SDimitry Andric   const SPIRVRegisterInfo &TRI;
7681ad6265SDimitry Andric   const RegisterBankInfo &RBI;
7781ad6265SDimitry Andric   SPIRVGlobalRegistry &GR;
7881ad6265SDimitry Andric   MachineRegisterInfo *MRI;
79*0fca6ea1SDimitry Andric   SPIRVMachineModuleInfo *MMI = nullptr;
80*0fca6ea1SDimitry Andric 
81*0fca6ea1SDimitry Andric   /// We need to keep track of the number we give to anonymous global values to
82*0fca6ea1SDimitry Andric   /// generate the same name every time when this is needed.
83*0fca6ea1SDimitry Andric   mutable DenseMap<const GlobalValue *, unsigned> UnnamedGlobalIDs;
8481ad6265SDimitry Andric 
8581ad6265SDimitry Andric public:
8681ad6265SDimitry Andric   SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
8781ad6265SDimitry Andric                            const SPIRVSubtarget &ST,
8881ad6265SDimitry Andric                            const RegisterBankInfo &RBI);
8981ad6265SDimitry Andric   void setupMF(MachineFunction &MF, GISelKnownBits *KB,
9006c3fb27SDimitry Andric                CodeGenCoverage *CoverageInfo, ProfileSummaryInfo *PSI,
9181ad6265SDimitry Andric                BlockFrequencyInfo *BFI) override;
9281ad6265SDimitry Andric   // Common selection code. Instruction-specific selection occurs in spvSelect.
9381ad6265SDimitry Andric   bool select(MachineInstr &I) override;
9481ad6265SDimitry Andric   static const char *getName() { return DEBUG_TYPE; }
9581ad6265SDimitry Andric 
9681ad6265SDimitry Andric #define GET_GLOBALISEL_PREDICATES_DECL
9781ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
9881ad6265SDimitry Andric #undef GET_GLOBALISEL_PREDICATES_DECL
9981ad6265SDimitry Andric 
10081ad6265SDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_DECL
10181ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
10281ad6265SDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_DECL
10381ad6265SDimitry Andric 
10481ad6265SDimitry Andric private:
10581ad6265SDimitry Andric   // tblgen-erated 'select' implementation, used as the initial selector for
10681ad6265SDimitry Andric   // the patterns that don't require complex C++.
10781ad6265SDimitry Andric   bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
10881ad6265SDimitry Andric 
10981ad6265SDimitry Andric   // All instruction-specific selection that didn't happen in "select()".
11081ad6265SDimitry Andric   // Is basically a large Switch/Case delegating to all other select method.
11181ad6265SDimitry Andric   bool spvSelect(Register ResVReg, const SPIRVType *ResType,
11281ad6265SDimitry Andric                  MachineInstr &I) const;
11381ad6265SDimitry Andric 
11481ad6265SDimitry Andric   bool selectGlobalValue(Register ResVReg, MachineInstr &I,
11581ad6265SDimitry Andric                          const MachineInstr *Init = nullptr) const;
11681ad6265SDimitry Andric 
11781ad6265SDimitry Andric   bool selectUnOpWithSrc(Register ResVReg, const SPIRVType *ResType,
11881ad6265SDimitry Andric                          MachineInstr &I, Register SrcReg,
11981ad6265SDimitry Andric                          unsigned Opcode) const;
12081ad6265SDimitry Andric   bool selectUnOp(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
12181ad6265SDimitry Andric                   unsigned Opcode) const;
12281ad6265SDimitry Andric 
123*0fca6ea1SDimitry Andric   bool selectBitcast(Register ResVReg, const SPIRVType *ResType,
124*0fca6ea1SDimitry Andric                      MachineInstr &I) const;
125*0fca6ea1SDimitry Andric 
12681ad6265SDimitry Andric   bool selectLoad(Register ResVReg, const SPIRVType *ResType,
12781ad6265SDimitry Andric                   MachineInstr &I) const;
12881ad6265SDimitry Andric   bool selectStore(MachineInstr &I) const;
12981ad6265SDimitry Andric 
130*0fca6ea1SDimitry Andric   bool selectStackSave(Register ResVReg, const SPIRVType *ResType,
131*0fca6ea1SDimitry Andric                        MachineInstr &I) const;
132*0fca6ea1SDimitry Andric   bool selectStackRestore(MachineInstr &I) const;
133*0fca6ea1SDimitry Andric 
13481ad6265SDimitry Andric   bool selectMemOperation(Register ResVReg, MachineInstr &I) const;
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric   bool selectAtomicRMW(Register ResVReg, const SPIRVType *ResType,
137*0fca6ea1SDimitry Andric                        MachineInstr &I, unsigned NewOpcode,
138*0fca6ea1SDimitry Andric                        unsigned NegateOpcode = 0) const;
13981ad6265SDimitry Andric 
14081ad6265SDimitry Andric   bool selectAtomicCmpXchg(Register ResVReg, const SPIRVType *ResType,
14181ad6265SDimitry Andric                            MachineInstr &I) const;
14281ad6265SDimitry Andric 
14381ad6265SDimitry Andric   bool selectFence(MachineInstr &I) const;
14481ad6265SDimitry Andric 
14581ad6265SDimitry Andric   bool selectAddrSpaceCast(Register ResVReg, const SPIRVType *ResType,
14681ad6265SDimitry Andric                            MachineInstr &I) const;
14781ad6265SDimitry Andric 
148*0fca6ea1SDimitry Andric   bool selectAnyOrAll(Register ResVReg, const SPIRVType *ResType,
149*0fca6ea1SDimitry Andric                       MachineInstr &I, unsigned OpType) const;
150*0fca6ea1SDimitry Andric 
151*0fca6ea1SDimitry Andric   bool selectAll(Register ResVReg, const SPIRVType *ResType,
152*0fca6ea1SDimitry Andric                  MachineInstr &I) const;
153*0fca6ea1SDimitry Andric 
154*0fca6ea1SDimitry Andric   bool selectAny(Register ResVReg, const SPIRVType *ResType,
155*0fca6ea1SDimitry Andric                  MachineInstr &I) const;
156*0fca6ea1SDimitry Andric 
15781ad6265SDimitry Andric   bool selectBitreverse(Register ResVReg, const SPIRVType *ResType,
15881ad6265SDimitry Andric                         MachineInstr &I) const;
15981ad6265SDimitry Andric 
16081ad6265SDimitry Andric   bool selectConstVector(Register ResVReg, const SPIRVType *ResType,
16181ad6265SDimitry Andric                          MachineInstr &I) const;
162*0fca6ea1SDimitry Andric   bool selectSplatVector(Register ResVReg, const SPIRVType *ResType,
163*0fca6ea1SDimitry Andric                          MachineInstr &I) const;
16481ad6265SDimitry Andric 
16581ad6265SDimitry Andric   bool selectCmp(Register ResVReg, const SPIRVType *ResType,
16681ad6265SDimitry Andric                  unsigned comparisonOpcode, MachineInstr &I) const;
16781ad6265SDimitry Andric 
16881ad6265SDimitry Andric   bool selectICmp(Register ResVReg, const SPIRVType *ResType,
16981ad6265SDimitry Andric                   MachineInstr &I) const;
17081ad6265SDimitry Andric   bool selectFCmp(Register ResVReg, const SPIRVType *ResType,
17181ad6265SDimitry Andric                   MachineInstr &I) const;
17281ad6265SDimitry Andric 
173*0fca6ea1SDimitry Andric   bool selectFmix(Register ResVReg, const SPIRVType *ResType,
174*0fca6ea1SDimitry Andric                   MachineInstr &I) const;
175*0fca6ea1SDimitry Andric 
176*0fca6ea1SDimitry Andric   bool selectRsqrt(Register ResVReg, const SPIRVType *ResType,
177*0fca6ea1SDimitry Andric                    MachineInstr &I) const;
178*0fca6ea1SDimitry Andric 
17981ad6265SDimitry Andric   void renderImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
18081ad6265SDimitry Andric                    int OpIdx) const;
18181ad6265SDimitry Andric   void renderFImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
18281ad6265SDimitry Andric                     int OpIdx) const;
18381ad6265SDimitry Andric 
18481ad6265SDimitry Andric   bool selectConst(Register ResVReg, const SPIRVType *ResType, const APInt &Imm,
18581ad6265SDimitry Andric                    MachineInstr &I) const;
18681ad6265SDimitry Andric 
18781ad6265SDimitry Andric   bool selectSelect(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
18881ad6265SDimitry Andric                     bool IsSigned) const;
18981ad6265SDimitry Andric   bool selectIToF(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
19081ad6265SDimitry Andric                   bool IsSigned, unsigned Opcode) const;
19181ad6265SDimitry Andric   bool selectExt(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
19281ad6265SDimitry Andric                  bool IsSigned) const;
19381ad6265SDimitry Andric 
19481ad6265SDimitry Andric   bool selectTrunc(Register ResVReg, const SPIRVType *ResType,
19581ad6265SDimitry Andric                    MachineInstr &I) const;
19681ad6265SDimitry Andric 
197bdd1243dSDimitry Andric   bool selectIntToBool(Register IntReg, Register ResVReg, MachineInstr &I,
198bdd1243dSDimitry Andric                        const SPIRVType *intTy, const SPIRVType *boolTy) const;
19981ad6265SDimitry Andric 
20081ad6265SDimitry Andric   bool selectOpUndef(Register ResVReg, const SPIRVType *ResType,
20181ad6265SDimitry Andric                      MachineInstr &I) const;
202*0fca6ea1SDimitry Andric   bool selectFreeze(Register ResVReg, const SPIRVType *ResType,
203*0fca6ea1SDimitry Andric                     MachineInstr &I) const;
20481ad6265SDimitry Andric   bool selectIntrinsic(Register ResVReg, const SPIRVType *ResType,
20581ad6265SDimitry Andric                        MachineInstr &I) const;
20681ad6265SDimitry Andric   bool selectExtractVal(Register ResVReg, const SPIRVType *ResType,
20781ad6265SDimitry Andric                         MachineInstr &I) const;
20881ad6265SDimitry Andric   bool selectInsertVal(Register ResVReg, const SPIRVType *ResType,
20981ad6265SDimitry Andric                        MachineInstr &I) const;
21081ad6265SDimitry Andric   bool selectExtractElt(Register ResVReg, const SPIRVType *ResType,
21181ad6265SDimitry Andric                         MachineInstr &I) const;
21281ad6265SDimitry Andric   bool selectInsertElt(Register ResVReg, const SPIRVType *ResType,
21381ad6265SDimitry Andric                        MachineInstr &I) const;
21481ad6265SDimitry Andric   bool selectGEP(Register ResVReg, const SPIRVType *ResType,
21581ad6265SDimitry Andric                  MachineInstr &I) const;
21681ad6265SDimitry Andric 
21781ad6265SDimitry Andric   bool selectFrameIndex(Register ResVReg, const SPIRVType *ResType,
21881ad6265SDimitry Andric                         MachineInstr &I) const;
219*0fca6ea1SDimitry Andric   bool selectAllocaArray(Register ResVReg, const SPIRVType *ResType,
220*0fca6ea1SDimitry Andric                          MachineInstr &I) const;
22181ad6265SDimitry Andric 
22281ad6265SDimitry Andric   bool selectBranch(MachineInstr &I) const;
22381ad6265SDimitry Andric   bool selectBranchCond(MachineInstr &I) const;
22481ad6265SDimitry Andric 
22581ad6265SDimitry Andric   bool selectPhi(Register ResVReg, const SPIRVType *ResType,
22681ad6265SDimitry Andric                  MachineInstr &I) const;
22781ad6265SDimitry Andric 
228bdd1243dSDimitry Andric   bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
229bdd1243dSDimitry Andric                      MachineInstr &I, CL::OpenCLExtInst CLInst) const;
230bdd1243dSDimitry Andric   bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
231bdd1243dSDimitry Andric                      MachineInstr &I, CL::OpenCLExtInst CLInst,
232bdd1243dSDimitry Andric                      GL::GLSLExtInst GLInst) const;
233bdd1243dSDimitry Andric   bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
234bdd1243dSDimitry Andric                      MachineInstr &I, const ExtInstList &ExtInsts) const;
235bdd1243dSDimitry Andric 
2365f757f3fSDimitry Andric   bool selectLog10(Register ResVReg, const SPIRVType *ResType,
2375f757f3fSDimitry Andric                    MachineInstr &I) const;
2385f757f3fSDimitry Andric 
239*0fca6ea1SDimitry Andric   bool selectSpvThreadId(Register ResVReg, const SPIRVType *ResType,
240*0fca6ea1SDimitry Andric                          MachineInstr &I) const;
241*0fca6ea1SDimitry Andric 
242*0fca6ea1SDimitry Andric   bool selectUnmergeValues(MachineInstr &I) const;
243*0fca6ea1SDimitry Andric 
24481ad6265SDimitry Andric   Register buildI32Constant(uint32_t Val, MachineInstr &I,
24581ad6265SDimitry Andric                             const SPIRVType *ResType = nullptr) const;
24681ad6265SDimitry Andric 
24781ad6265SDimitry Andric   Register buildZerosVal(const SPIRVType *ResType, MachineInstr &I) const;
248*0fca6ea1SDimitry Andric   Register buildZerosValF(const SPIRVType *ResType, MachineInstr &I) const;
24981ad6265SDimitry Andric   Register buildOnesVal(bool AllOnes, const SPIRVType *ResType,
25081ad6265SDimitry Andric                         MachineInstr &I) const;
251*0fca6ea1SDimitry Andric 
252*0fca6ea1SDimitry Andric   bool wrapIntoSpecConstantOp(MachineInstr &I,
253*0fca6ea1SDimitry Andric                               SmallVector<Register> &CompositeArgs) const;
25481ad6265SDimitry Andric };
25581ad6265SDimitry Andric 
25681ad6265SDimitry Andric } // end anonymous namespace
25781ad6265SDimitry Andric 
25881ad6265SDimitry Andric #define GET_GLOBALISEL_IMPL
25981ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
26081ad6265SDimitry Andric #undef GET_GLOBALISEL_IMPL
26181ad6265SDimitry Andric 
26281ad6265SDimitry Andric SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
26381ad6265SDimitry Andric                                                    const SPIRVSubtarget &ST,
26481ad6265SDimitry Andric                                                    const RegisterBankInfo &RBI)
26581ad6265SDimitry Andric     : InstructionSelector(), STI(ST), TII(*ST.getInstrInfo()),
26681ad6265SDimitry Andric       TRI(*ST.getRegisterInfo()), RBI(RBI), GR(*ST.getSPIRVGlobalRegistry()),
26781ad6265SDimitry Andric #define GET_GLOBALISEL_PREDICATES_INIT
26881ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
26981ad6265SDimitry Andric #undef GET_GLOBALISEL_PREDICATES_INIT
27081ad6265SDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_INIT
27181ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
27281ad6265SDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_INIT
27381ad6265SDimitry Andric {
27481ad6265SDimitry Andric }
27581ad6265SDimitry Andric 
27681ad6265SDimitry Andric void SPIRVInstructionSelector::setupMF(MachineFunction &MF, GISelKnownBits *KB,
27706c3fb27SDimitry Andric                                        CodeGenCoverage *CoverageInfo,
27881ad6265SDimitry Andric                                        ProfileSummaryInfo *PSI,
27981ad6265SDimitry Andric                                        BlockFrequencyInfo *BFI) {
280*0fca6ea1SDimitry Andric   MMI = &MF.getMMI().getObjFileInfo<SPIRVMachineModuleInfo>();
28181ad6265SDimitry Andric   MRI = &MF.getRegInfo();
28281ad6265SDimitry Andric   GR.setCurrentFunc(MF);
28381ad6265SDimitry Andric   InstructionSelector::setupMF(MF, KB, CoverageInfo, PSI, BFI);
28481ad6265SDimitry Andric }
28581ad6265SDimitry Andric 
286fcaf7f86SDimitry Andric static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI);
287fcaf7f86SDimitry Andric 
28881ad6265SDimitry Andric // Defined in SPIRVLegalizerInfo.cpp.
28981ad6265SDimitry Andric extern bool isTypeFoldingSupported(unsigned Opcode);
29081ad6265SDimitry Andric 
29181ad6265SDimitry Andric bool SPIRVInstructionSelector::select(MachineInstr &I) {
29281ad6265SDimitry Andric   assert(I.getParent() && "Instruction should be in a basic block!");
29381ad6265SDimitry Andric   assert(I.getParent()->getParent() && "Instruction should be in a function!");
29481ad6265SDimitry Andric 
29581ad6265SDimitry Andric   Register Opcode = I.getOpcode();
29681ad6265SDimitry Andric   // If it's not a GMIR instruction, we've selected it already.
29781ad6265SDimitry Andric   if (!isPreISelGenericOpcode(Opcode)) {
29881ad6265SDimitry Andric     if (Opcode == SPIRV::ASSIGN_TYPE) { // These pseudos aren't needed any more.
299*0fca6ea1SDimitry Andric       Register DstReg = I.getOperand(0).getReg();
300*0fca6ea1SDimitry Andric       Register SrcReg = I.getOperand(1).getReg();
301*0fca6ea1SDimitry Andric       auto *Def = MRI->getVRegDef(SrcReg);
30281ad6265SDimitry Andric       if (isTypeFoldingSupported(Def->getOpcode())) {
303*0fca6ea1SDimitry Andric         if (MRI->getType(DstReg).isPointer())
304*0fca6ea1SDimitry Andric           MRI->setType(DstReg, LLT::scalar(32));
305*0fca6ea1SDimitry Andric         bool Res = selectImpl(I, *CoverageInfo);
30681ad6265SDimitry Andric         assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT);
30781ad6265SDimitry Andric         if (Res)
30881ad6265SDimitry Andric           return Res;
30981ad6265SDimitry Andric       }
310*0fca6ea1SDimitry Andric       MRI->replaceRegWith(SrcReg, DstReg);
31181ad6265SDimitry Andric       I.removeFromParent();
312bdd1243dSDimitry Andric       return true;
31381ad6265SDimitry Andric     } else if (I.getNumDefs() == 1) {
31481ad6265SDimitry Andric       // Make all vregs 32 bits (for SPIR-V IDs).
31581ad6265SDimitry Andric       MRI->setType(I.getOperand(0).getReg(), LLT::scalar(32));
31681ad6265SDimitry Andric     }
317bdd1243dSDimitry Andric     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
31881ad6265SDimitry Andric   }
31981ad6265SDimitry Andric 
32081ad6265SDimitry Andric   if (I.getNumOperands() != I.getNumExplicitOperands()) {
32181ad6265SDimitry Andric     LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
32281ad6265SDimitry Andric     return false;
32381ad6265SDimitry Andric   }
32481ad6265SDimitry Andric 
32581ad6265SDimitry Andric   // Common code for getting return reg+type, and removing selected instr
32681ad6265SDimitry Andric   // from parent occurs here. Instr-specific selection happens in spvSelect().
32781ad6265SDimitry Andric   bool HasDefs = I.getNumDefs() > 0;
32881ad6265SDimitry Andric   Register ResVReg = HasDefs ? I.getOperand(0).getReg() : Register(0);
32981ad6265SDimitry Andric   SPIRVType *ResType = HasDefs ? GR.getSPIRVTypeForVReg(ResVReg) : nullptr;
33081ad6265SDimitry Andric   assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
33181ad6265SDimitry Andric   if (spvSelect(ResVReg, ResType, I)) {
33281ad6265SDimitry Andric     if (HasDefs) // Make all vregs 32 bits (for SPIR-V IDs).
333*0fca6ea1SDimitry Andric       for (unsigned i = 0; i < I.getNumDefs(); ++i)
334*0fca6ea1SDimitry Andric         MRI->setType(I.getOperand(i).getReg(), LLT::scalar(32));
33581ad6265SDimitry Andric     I.removeFromParent();
33681ad6265SDimitry Andric     return true;
33781ad6265SDimitry Andric   }
33881ad6265SDimitry Andric   return false;
33981ad6265SDimitry Andric }
34081ad6265SDimitry Andric 
34181ad6265SDimitry Andric bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
34281ad6265SDimitry Andric                                          const SPIRVType *ResType,
34381ad6265SDimitry Andric                                          MachineInstr &I) const {
34481ad6265SDimitry Andric   const unsigned Opcode = I.getOpcode();
345*0fca6ea1SDimitry Andric   if (isTypeFoldingSupported(Opcode) && Opcode != TargetOpcode::G_CONSTANT)
346*0fca6ea1SDimitry Andric     return selectImpl(I, *CoverageInfo);
34781ad6265SDimitry Andric   switch (Opcode) {
34881ad6265SDimitry Andric   case TargetOpcode::G_CONSTANT:
34981ad6265SDimitry Andric     return selectConst(ResVReg, ResType, I.getOperand(1).getCImm()->getValue(),
35081ad6265SDimitry Andric                        I);
35181ad6265SDimitry Andric   case TargetOpcode::G_GLOBAL_VALUE:
35281ad6265SDimitry Andric     return selectGlobalValue(ResVReg, I);
35381ad6265SDimitry Andric   case TargetOpcode::G_IMPLICIT_DEF:
35481ad6265SDimitry Andric     return selectOpUndef(ResVReg, ResType, I);
355*0fca6ea1SDimitry Andric   case TargetOpcode::G_FREEZE:
356*0fca6ea1SDimitry Andric     return selectFreeze(ResVReg, ResType, I);
35781ad6265SDimitry Andric 
358*0fca6ea1SDimitry Andric   case TargetOpcode::G_INTRINSIC:
35981ad6265SDimitry Andric   case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3605f757f3fSDimitry Andric   case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
36181ad6265SDimitry Andric     return selectIntrinsic(ResVReg, ResType, I);
36281ad6265SDimitry Andric   case TargetOpcode::G_BITREVERSE:
36381ad6265SDimitry Andric     return selectBitreverse(ResVReg, ResType, I);
36481ad6265SDimitry Andric 
36581ad6265SDimitry Andric   case TargetOpcode::G_BUILD_VECTOR:
36681ad6265SDimitry Andric     return selectConstVector(ResVReg, ResType, I);
367*0fca6ea1SDimitry Andric   case TargetOpcode::G_SPLAT_VECTOR:
368*0fca6ea1SDimitry Andric     return selectSplatVector(ResVReg, ResType, I);
36981ad6265SDimitry Andric 
37081ad6265SDimitry Andric   case TargetOpcode::G_SHUFFLE_VECTOR: {
37181ad6265SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
37281ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle))
37381ad6265SDimitry Andric                    .addDef(ResVReg)
37481ad6265SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType))
37581ad6265SDimitry Andric                    .addUse(I.getOperand(1).getReg())
37681ad6265SDimitry Andric                    .addUse(I.getOperand(2).getReg());
37781ad6265SDimitry Andric     for (auto V : I.getOperand(3).getShuffleMask())
37881ad6265SDimitry Andric       MIB.addImm(V);
37981ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
38081ad6265SDimitry Andric   }
38181ad6265SDimitry Andric   case TargetOpcode::G_MEMMOVE:
38281ad6265SDimitry Andric   case TargetOpcode::G_MEMCPY:
383bdd1243dSDimitry Andric   case TargetOpcode::G_MEMSET:
38481ad6265SDimitry Andric     return selectMemOperation(ResVReg, I);
38581ad6265SDimitry Andric 
38681ad6265SDimitry Andric   case TargetOpcode::G_ICMP:
38781ad6265SDimitry Andric     return selectICmp(ResVReg, ResType, I);
38881ad6265SDimitry Andric   case TargetOpcode::G_FCMP:
38981ad6265SDimitry Andric     return selectFCmp(ResVReg, ResType, I);
39081ad6265SDimitry Andric 
39181ad6265SDimitry Andric   case TargetOpcode::G_FRAME_INDEX:
39281ad6265SDimitry Andric     return selectFrameIndex(ResVReg, ResType, I);
39381ad6265SDimitry Andric 
39481ad6265SDimitry Andric   case TargetOpcode::G_LOAD:
39581ad6265SDimitry Andric     return selectLoad(ResVReg, ResType, I);
39681ad6265SDimitry Andric   case TargetOpcode::G_STORE:
39781ad6265SDimitry Andric     return selectStore(I);
39881ad6265SDimitry Andric 
39981ad6265SDimitry Andric   case TargetOpcode::G_BR:
40081ad6265SDimitry Andric     return selectBranch(I);
40181ad6265SDimitry Andric   case TargetOpcode::G_BRCOND:
40281ad6265SDimitry Andric     return selectBranchCond(I);
40381ad6265SDimitry Andric 
40481ad6265SDimitry Andric   case TargetOpcode::G_PHI:
40581ad6265SDimitry Andric     return selectPhi(ResVReg, ResType, I);
40681ad6265SDimitry Andric 
40781ad6265SDimitry Andric   case TargetOpcode::G_FPTOSI:
40881ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
40981ad6265SDimitry Andric   case TargetOpcode::G_FPTOUI:
41081ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
41181ad6265SDimitry Andric 
41281ad6265SDimitry Andric   case TargetOpcode::G_SITOFP:
41381ad6265SDimitry Andric     return selectIToF(ResVReg, ResType, I, true, SPIRV::OpConvertSToF);
41481ad6265SDimitry Andric   case TargetOpcode::G_UITOFP:
41581ad6265SDimitry Andric     return selectIToF(ResVReg, ResType, I, false, SPIRV::OpConvertUToF);
41681ad6265SDimitry Andric 
41781ad6265SDimitry Andric   case TargetOpcode::G_CTPOP:
41881ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitCount);
419bdd1243dSDimitry Andric   case TargetOpcode::G_SMIN:
420bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::s_min, GL::SMin);
421bdd1243dSDimitry Andric   case TargetOpcode::G_UMIN:
422bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::u_min, GL::UMin);
423bdd1243dSDimitry Andric 
424bdd1243dSDimitry Andric   case TargetOpcode::G_SMAX:
425bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::s_max, GL::SMax);
426bdd1243dSDimitry Andric   case TargetOpcode::G_UMAX:
427bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::u_max, GL::UMax);
428bdd1243dSDimitry Andric 
429bdd1243dSDimitry Andric   case TargetOpcode::G_FMA:
430bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
431bdd1243dSDimitry Andric 
432bdd1243dSDimitry Andric   case TargetOpcode::G_FPOW:
433bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::pow, GL::Pow);
434bdd1243dSDimitry Andric   case TargetOpcode::G_FPOWI:
435bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::pown);
436bdd1243dSDimitry Andric 
437bdd1243dSDimitry Andric   case TargetOpcode::G_FEXP:
438bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::exp, GL::Exp);
439bdd1243dSDimitry Andric   case TargetOpcode::G_FEXP2:
440bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::exp2, GL::Exp2);
441bdd1243dSDimitry Andric 
442bdd1243dSDimitry Andric   case TargetOpcode::G_FLOG:
443bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::log, GL::Log);
444bdd1243dSDimitry Andric   case TargetOpcode::G_FLOG2:
445bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::log2, GL::Log2);
446bdd1243dSDimitry Andric   case TargetOpcode::G_FLOG10:
4475f757f3fSDimitry Andric     return selectLog10(ResVReg, ResType, I);
448bdd1243dSDimitry Andric 
449bdd1243dSDimitry Andric   case TargetOpcode::G_FABS:
450bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::fabs, GL::FAbs);
451bdd1243dSDimitry Andric   case TargetOpcode::G_ABS:
452bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::s_abs, GL::SAbs);
453bdd1243dSDimitry Andric 
454bdd1243dSDimitry Andric   case TargetOpcode::G_FMINNUM:
455bdd1243dSDimitry Andric   case TargetOpcode::G_FMINIMUM:
456*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::fmin, GL::NMin);
457bdd1243dSDimitry Andric   case TargetOpcode::G_FMAXNUM:
458bdd1243dSDimitry Andric   case TargetOpcode::G_FMAXIMUM:
459*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::fmax, GL::NMax);
460bdd1243dSDimitry Andric 
461bdd1243dSDimitry Andric   case TargetOpcode::G_FCOPYSIGN:
462bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::copysign);
463bdd1243dSDimitry Andric 
464bdd1243dSDimitry Andric   case TargetOpcode::G_FCEIL:
465bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::ceil, GL::Ceil);
466bdd1243dSDimitry Andric   case TargetOpcode::G_FFLOOR:
467bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::floor, GL::Floor);
468bdd1243dSDimitry Andric 
469bdd1243dSDimitry Andric   case TargetOpcode::G_FCOS:
470bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::cos, GL::Cos);
471bdd1243dSDimitry Andric   case TargetOpcode::G_FSIN:
472bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::sin, GL::Sin);
473*0fca6ea1SDimitry Andric   case TargetOpcode::G_FTAN:
474*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::tan, GL::Tan);
475*0fca6ea1SDimitry Andric   case TargetOpcode::G_FACOS:
476*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::acos, GL::Acos);
477*0fca6ea1SDimitry Andric   case TargetOpcode::G_FASIN:
478*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::asin, GL::Asin);
479*0fca6ea1SDimitry Andric   case TargetOpcode::G_FATAN:
480*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::atan, GL::Atan);
481*0fca6ea1SDimitry Andric   case TargetOpcode::G_FCOSH:
482*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::cosh, GL::Cosh);
483*0fca6ea1SDimitry Andric   case TargetOpcode::G_FSINH:
484*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::sinh, GL::Sinh);
485*0fca6ea1SDimitry Andric   case TargetOpcode::G_FTANH:
486*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::tanh, GL::Tanh);
487bdd1243dSDimitry Andric 
488bdd1243dSDimitry Andric   case TargetOpcode::G_FSQRT:
489bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::sqrt, GL::Sqrt);
490bdd1243dSDimitry Andric 
491bdd1243dSDimitry Andric   case TargetOpcode::G_CTTZ:
492bdd1243dSDimitry Andric   case TargetOpcode::G_CTTZ_ZERO_UNDEF:
493bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::ctz);
494bdd1243dSDimitry Andric   case TargetOpcode::G_CTLZ:
495bdd1243dSDimitry Andric   case TargetOpcode::G_CTLZ_ZERO_UNDEF:
496bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::clz);
497bdd1243dSDimitry Andric 
498bdd1243dSDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUND:
499bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::round, GL::Round);
500bdd1243dSDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
501bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven);
502bdd1243dSDimitry Andric   case TargetOpcode::G_INTRINSIC_TRUNC:
503bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::trunc, GL::Trunc);
504bdd1243dSDimitry Andric   case TargetOpcode::G_FRINT:
505bdd1243dSDimitry Andric   case TargetOpcode::G_FNEARBYINT:
506bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven);
507bdd1243dSDimitry Andric 
508bdd1243dSDimitry Andric   case TargetOpcode::G_SMULH:
509bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::s_mul_hi);
510bdd1243dSDimitry Andric   case TargetOpcode::G_UMULH:
511bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::u_mul_hi);
51281ad6265SDimitry Andric 
513*0fca6ea1SDimitry Andric   case TargetOpcode::G_SADDSAT:
514*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::s_add_sat);
515*0fca6ea1SDimitry Andric   case TargetOpcode::G_UADDSAT:
516*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::u_add_sat);
517*0fca6ea1SDimitry Andric   case TargetOpcode::G_SSUBSAT:
518*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::s_sub_sat);
519*0fca6ea1SDimitry Andric   case TargetOpcode::G_USUBSAT:
520*0fca6ea1SDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::u_sub_sat);
521*0fca6ea1SDimitry Andric 
52281ad6265SDimitry Andric   case TargetOpcode::G_SEXT:
52381ad6265SDimitry Andric     return selectExt(ResVReg, ResType, I, true);
52481ad6265SDimitry Andric   case TargetOpcode::G_ANYEXT:
52581ad6265SDimitry Andric   case TargetOpcode::G_ZEXT:
52681ad6265SDimitry Andric     return selectExt(ResVReg, ResType, I, false);
52781ad6265SDimitry Andric   case TargetOpcode::G_TRUNC:
52881ad6265SDimitry Andric     return selectTrunc(ResVReg, ResType, I);
52981ad6265SDimitry Andric   case TargetOpcode::G_FPTRUNC:
53081ad6265SDimitry Andric   case TargetOpcode::G_FPEXT:
53181ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpFConvert);
53281ad6265SDimitry Andric 
53381ad6265SDimitry Andric   case TargetOpcode::G_PTRTOINT:
53481ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertPtrToU);
53581ad6265SDimitry Andric   case TargetOpcode::G_INTTOPTR:
53681ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertUToPtr);
53781ad6265SDimitry Andric   case TargetOpcode::G_BITCAST:
538*0fca6ea1SDimitry Andric     return selectBitcast(ResVReg, ResType, I);
53981ad6265SDimitry Andric   case TargetOpcode::G_ADDRSPACE_CAST:
54081ad6265SDimitry Andric     return selectAddrSpaceCast(ResVReg, ResType, I);
541fcaf7f86SDimitry Andric   case TargetOpcode::G_PTR_ADD: {
542fcaf7f86SDimitry Andric     // Currently, we get G_PTR_ADD only as a result of translating
543fcaf7f86SDimitry Andric     // global variables, initialized with constant expressions like GV + Const
544fcaf7f86SDimitry Andric     // (see test opencl/basic/progvar_prog_scope_init.ll).
545fcaf7f86SDimitry Andric     // TODO: extend the handler once we have other cases.
546fcaf7f86SDimitry Andric     assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
547fcaf7f86SDimitry Andric     Register GV = I.getOperand(1).getReg();
548fcaf7f86SDimitry Andric     MachineRegisterInfo::def_instr_iterator II = MRI->def_instr_begin(GV);
549*0fca6ea1SDimitry Andric     (void)II;
550fcaf7f86SDimitry Andric     assert(((*II).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
551fcaf7f86SDimitry Andric             (*II).getOpcode() == TargetOpcode::COPY ||
552fcaf7f86SDimitry Andric             (*II).getOpcode() == SPIRV::OpVariable) &&
553fcaf7f86SDimitry Andric            isImm(I.getOperand(2), MRI));
554fcaf7f86SDimitry Andric     Register Idx = buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I);
555fcaf7f86SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
556fcaf7f86SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
557fcaf7f86SDimitry Andric                    .addDef(ResVReg)
558fcaf7f86SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType))
559fcaf7f86SDimitry Andric                    .addImm(static_cast<uint32_t>(
560fcaf7f86SDimitry Andric                        SPIRV::Opcode::InBoundsPtrAccessChain))
561fcaf7f86SDimitry Andric                    .addUse(GV)
562fcaf7f86SDimitry Andric                    .addUse(Idx)
563fcaf7f86SDimitry Andric                    .addUse(I.getOperand(2).getReg());
564fcaf7f86SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
565fcaf7f86SDimitry Andric   }
56681ad6265SDimitry Andric 
56781ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_OR:
56881ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicOr);
56981ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_ADD:
57081ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicIAdd);
57181ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_AND:
57281ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicAnd);
57381ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_MAX:
57481ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMax);
57581ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_MIN:
57681ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMin);
57781ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_SUB:
57881ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicISub);
57981ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XOR:
58081ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicXor);
58181ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_UMAX:
58281ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMax);
58381ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_UMIN:
58481ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMin);
58581ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XCHG:
58681ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicExchange);
58781ad6265SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG:
58881ad6265SDimitry Andric     return selectAtomicCmpXchg(ResVReg, ResType, I);
58981ad6265SDimitry Andric 
590*0fca6ea1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_FADD:
591*0fca6ea1SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFAddEXT);
592*0fca6ea1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_FSUB:
593*0fca6ea1SDimitry Andric     // Translate G_ATOMICRMW_FSUB to OpAtomicFAddEXT with negative value operand
594*0fca6ea1SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFAddEXT,
595*0fca6ea1SDimitry Andric                            SPIRV::OpFNegate);
596*0fca6ea1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_FMIN:
597*0fca6ea1SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFMinEXT);
598*0fca6ea1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_FMAX:
599*0fca6ea1SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFMaxEXT);
600*0fca6ea1SDimitry Andric 
60181ad6265SDimitry Andric   case TargetOpcode::G_FENCE:
60281ad6265SDimitry Andric     return selectFence(I);
60381ad6265SDimitry Andric 
604*0fca6ea1SDimitry Andric   case TargetOpcode::G_STACKSAVE:
605*0fca6ea1SDimitry Andric     return selectStackSave(ResVReg, ResType, I);
606*0fca6ea1SDimitry Andric   case TargetOpcode::G_STACKRESTORE:
607*0fca6ea1SDimitry Andric     return selectStackRestore(I);
608*0fca6ea1SDimitry Andric 
609*0fca6ea1SDimitry Andric   case TargetOpcode::G_UNMERGE_VALUES:
610*0fca6ea1SDimitry Andric     return selectUnmergeValues(I);
611*0fca6ea1SDimitry Andric 
61281ad6265SDimitry Andric   default:
61381ad6265SDimitry Andric     return false;
61481ad6265SDimitry Andric   }
61581ad6265SDimitry Andric }
61681ad6265SDimitry Andric 
617bdd1243dSDimitry Andric bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
618bdd1243dSDimitry Andric                                              const SPIRVType *ResType,
619bdd1243dSDimitry Andric                                              MachineInstr &I,
620bdd1243dSDimitry Andric                                              CL::OpenCLExtInst CLInst) const {
621bdd1243dSDimitry Andric   return selectExtInst(ResVReg, ResType, I,
622bdd1243dSDimitry Andric                        {{SPIRV::InstructionSet::OpenCL_std, CLInst}});
623bdd1243dSDimitry Andric }
624bdd1243dSDimitry Andric 
625bdd1243dSDimitry Andric bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
626bdd1243dSDimitry Andric                                              const SPIRVType *ResType,
627bdd1243dSDimitry Andric                                              MachineInstr &I,
628bdd1243dSDimitry Andric                                              CL::OpenCLExtInst CLInst,
629bdd1243dSDimitry Andric                                              GL::GLSLExtInst GLInst) const {
630bdd1243dSDimitry Andric   ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst},
631bdd1243dSDimitry Andric                           {SPIRV::InstructionSet::GLSL_std_450, GLInst}};
632bdd1243dSDimitry Andric   return selectExtInst(ResVReg, ResType, I, ExtInsts);
633bdd1243dSDimitry Andric }
634bdd1243dSDimitry Andric 
635bdd1243dSDimitry Andric bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
636bdd1243dSDimitry Andric                                              const SPIRVType *ResType,
637bdd1243dSDimitry Andric                                              MachineInstr &I,
638bdd1243dSDimitry Andric                                              const ExtInstList &Insts) const {
639bdd1243dSDimitry Andric 
640bdd1243dSDimitry Andric   for (const auto &Ex : Insts) {
641bdd1243dSDimitry Andric     SPIRV::InstructionSet::InstructionSet Set = Ex.first;
642bdd1243dSDimitry Andric     uint32_t Opcode = Ex.second;
643bdd1243dSDimitry Andric     if (STI.canUseExtInstSet(Set)) {
644bdd1243dSDimitry Andric       MachineBasicBlock &BB = *I.getParent();
645bdd1243dSDimitry Andric       auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
646bdd1243dSDimitry Andric                      .addDef(ResVReg)
647bdd1243dSDimitry Andric                      .addUse(GR.getSPIRVTypeID(ResType))
648bdd1243dSDimitry Andric                      .addImm(static_cast<uint32_t>(Set))
649bdd1243dSDimitry Andric                      .addImm(Opcode);
650bdd1243dSDimitry Andric       const unsigned NumOps = I.getNumOperands();
651bdd1243dSDimitry Andric       for (unsigned i = 1; i < NumOps; ++i)
652bdd1243dSDimitry Andric         MIB.add(I.getOperand(i));
653bdd1243dSDimitry Andric       return MIB.constrainAllUses(TII, TRI, RBI);
654bdd1243dSDimitry Andric     }
655bdd1243dSDimitry Andric   }
656bdd1243dSDimitry Andric   return false;
657bdd1243dSDimitry Andric }
658bdd1243dSDimitry Andric 
65981ad6265SDimitry Andric bool SPIRVInstructionSelector::selectUnOpWithSrc(Register ResVReg,
66081ad6265SDimitry Andric                                                  const SPIRVType *ResType,
66181ad6265SDimitry Andric                                                  MachineInstr &I,
66281ad6265SDimitry Andric                                                  Register SrcReg,
66381ad6265SDimitry Andric                                                  unsigned Opcode) const {
66481ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
66581ad6265SDimitry Andric       .addDef(ResVReg)
66681ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
66781ad6265SDimitry Andric       .addUse(SrcReg)
66881ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
66981ad6265SDimitry Andric }
67081ad6265SDimitry Andric 
67181ad6265SDimitry Andric bool SPIRVInstructionSelector::selectUnOp(Register ResVReg,
67281ad6265SDimitry Andric                                           const SPIRVType *ResType,
67381ad6265SDimitry Andric                                           MachineInstr &I,
67481ad6265SDimitry Andric                                           unsigned Opcode) const {
675*0fca6ea1SDimitry Andric   if (STI.isOpenCLEnv() && I.getOperand(1).isReg()) {
676*0fca6ea1SDimitry Andric     Register SrcReg = I.getOperand(1).getReg();
677*0fca6ea1SDimitry Andric     bool IsGV = false;
678*0fca6ea1SDimitry Andric     for (MachineRegisterInfo::def_instr_iterator DefIt =
679*0fca6ea1SDimitry Andric              MRI->def_instr_begin(SrcReg);
680*0fca6ea1SDimitry Andric          DefIt != MRI->def_instr_end(); DefIt = std::next(DefIt)) {
681*0fca6ea1SDimitry Andric       if ((*DefIt).getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
682*0fca6ea1SDimitry Andric         IsGV = true;
683*0fca6ea1SDimitry Andric         break;
684*0fca6ea1SDimitry Andric       }
685*0fca6ea1SDimitry Andric     }
686*0fca6ea1SDimitry Andric     if (IsGV) {
687*0fca6ea1SDimitry Andric       uint32_t SpecOpcode = 0;
688*0fca6ea1SDimitry Andric       switch (Opcode) {
689*0fca6ea1SDimitry Andric       case SPIRV::OpConvertPtrToU:
690*0fca6ea1SDimitry Andric         SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertPtrToU);
691*0fca6ea1SDimitry Andric         break;
692*0fca6ea1SDimitry Andric       case SPIRV::OpConvertUToPtr:
693*0fca6ea1SDimitry Andric         SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertUToPtr);
694*0fca6ea1SDimitry Andric         break;
695*0fca6ea1SDimitry Andric       }
696*0fca6ea1SDimitry Andric       if (SpecOpcode)
697*0fca6ea1SDimitry Andric         return BuildMI(*I.getParent(), I, I.getDebugLoc(),
698*0fca6ea1SDimitry Andric                        TII.get(SPIRV::OpSpecConstantOp))
699*0fca6ea1SDimitry Andric             .addDef(ResVReg)
700*0fca6ea1SDimitry Andric             .addUse(GR.getSPIRVTypeID(ResType))
701*0fca6ea1SDimitry Andric             .addImm(SpecOpcode)
702*0fca6ea1SDimitry Andric             .addUse(SrcReg)
703*0fca6ea1SDimitry Andric             .constrainAllUses(TII, TRI, RBI);
704*0fca6ea1SDimitry Andric     }
705*0fca6ea1SDimitry Andric   }
70681ad6265SDimitry Andric   return selectUnOpWithSrc(ResVReg, ResType, I, I.getOperand(1).getReg(),
70781ad6265SDimitry Andric                            Opcode);
70881ad6265SDimitry Andric }
70981ad6265SDimitry Andric 
710*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectBitcast(Register ResVReg,
711*0fca6ea1SDimitry Andric                                              const SPIRVType *ResType,
712*0fca6ea1SDimitry Andric                                              MachineInstr &I) const {
713*0fca6ea1SDimitry Andric   Register OpReg = I.getOperand(1).getReg();
714*0fca6ea1SDimitry Andric   SPIRVType *OpType = OpReg.isValid() ? GR.getSPIRVTypeForVReg(OpReg) : nullptr;
715*0fca6ea1SDimitry Andric   if (!GR.isBitcastCompatible(ResType, OpType))
716*0fca6ea1SDimitry Andric     report_fatal_error("incompatible result and operand types in a bitcast");
717*0fca6ea1SDimitry Andric   return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast);
71881ad6265SDimitry Andric }
719*0fca6ea1SDimitry Andric 
720*0fca6ea1SDimitry Andric static SPIRV::Scope::Scope getScope(SyncScope::ID Ord,
721*0fca6ea1SDimitry Andric                                     SPIRVMachineModuleInfo *MMI) {
722*0fca6ea1SDimitry Andric   if (Ord == SyncScope::SingleThread || Ord == MMI->Work_ItemSSID)
723*0fca6ea1SDimitry Andric     return SPIRV::Scope::Invocation;
724*0fca6ea1SDimitry Andric   else if (Ord == SyncScope::System || Ord == MMI->DeviceSSID)
725*0fca6ea1SDimitry Andric     return SPIRV::Scope::Device;
726*0fca6ea1SDimitry Andric   else if (Ord == MMI->WorkGroupSSID)
727*0fca6ea1SDimitry Andric     return SPIRV::Scope::Workgroup;
728*0fca6ea1SDimitry Andric   else if (Ord == MMI->AllSVMDevicesSSID)
729*0fca6ea1SDimitry Andric     return SPIRV::Scope::CrossDevice;
730*0fca6ea1SDimitry Andric   else if (Ord == MMI->SubGroupSSID)
731*0fca6ea1SDimitry Andric     return SPIRV::Scope::Subgroup;
732*0fca6ea1SDimitry Andric   else
733*0fca6ea1SDimitry Andric     // OpenCL approach is: "The functions that do not have memory_scope argument
734*0fca6ea1SDimitry Andric     // have the same semantics as the corresponding functions with the
735*0fca6ea1SDimitry Andric     // memory_scope argument set to memory_scope_device." See ref.: //
736*0fca6ea1SDimitry Andric     // https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_C.html#atomic-functions
737*0fca6ea1SDimitry Andric     // In our case if the scope is unknown, assuming that SPIR-V code is to be
738*0fca6ea1SDimitry Andric     // consumed in an OpenCL environment, we use the same approach and set the
739*0fca6ea1SDimitry Andric     // scope to memory_scope_device.
740*0fca6ea1SDimitry Andric     return SPIRV::Scope::Device;
74181ad6265SDimitry Andric }
74281ad6265SDimitry Andric 
74381ad6265SDimitry Andric static void addMemoryOperands(MachineMemOperand *MemOp,
74481ad6265SDimitry Andric                               MachineInstrBuilder &MIB) {
74581ad6265SDimitry Andric   uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
74681ad6265SDimitry Andric   if (MemOp->isVolatile())
74781ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
74881ad6265SDimitry Andric   if (MemOp->isNonTemporal())
74981ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
75081ad6265SDimitry Andric   if (MemOp->getAlign().value())
75181ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned);
75281ad6265SDimitry Andric 
75381ad6265SDimitry Andric   if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) {
75481ad6265SDimitry Andric     MIB.addImm(SpvMemOp);
75581ad6265SDimitry Andric     if (SpvMemOp & static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned))
75681ad6265SDimitry Andric       MIB.addImm(MemOp->getAlign().value());
75781ad6265SDimitry Andric   }
75881ad6265SDimitry Andric }
75981ad6265SDimitry Andric 
76081ad6265SDimitry Andric static void addMemoryOperands(uint64_t Flags, MachineInstrBuilder &MIB) {
76181ad6265SDimitry Andric   uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
76281ad6265SDimitry Andric   if (Flags & MachineMemOperand::Flags::MOVolatile)
76381ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
76481ad6265SDimitry Andric   if (Flags & MachineMemOperand::Flags::MONonTemporal)
76581ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
76681ad6265SDimitry Andric 
76781ad6265SDimitry Andric   if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None))
76881ad6265SDimitry Andric     MIB.addImm(SpvMemOp);
76981ad6265SDimitry Andric }
77081ad6265SDimitry Andric 
77181ad6265SDimitry Andric bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
77281ad6265SDimitry Andric                                           const SPIRVType *ResType,
77381ad6265SDimitry Andric                                           MachineInstr &I) const {
7745f757f3fSDimitry Andric   unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0;
77581ad6265SDimitry Andric   Register Ptr = I.getOperand(1 + OpOffset).getReg();
77681ad6265SDimitry Andric   auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
77781ad6265SDimitry Andric                  .addDef(ResVReg)
77881ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
77981ad6265SDimitry Andric                  .addUse(Ptr);
78081ad6265SDimitry Andric   if (!I.getNumMemOperands()) {
7815f757f3fSDimitry Andric     assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
7825f757f3fSDimitry Andric            I.getOpcode() ==
7835f757f3fSDimitry Andric                TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
78481ad6265SDimitry Andric     addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
78581ad6265SDimitry Andric   } else {
78681ad6265SDimitry Andric     addMemoryOperands(*I.memoperands_begin(), MIB);
78781ad6265SDimitry Andric   }
78881ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
78981ad6265SDimitry Andric }
79081ad6265SDimitry Andric 
79181ad6265SDimitry Andric bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
7925f757f3fSDimitry Andric   unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0;
79381ad6265SDimitry Andric   Register StoreVal = I.getOperand(0 + OpOffset).getReg();
79481ad6265SDimitry Andric   Register Ptr = I.getOperand(1 + OpOffset).getReg();
79581ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
79681ad6265SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpStore))
79781ad6265SDimitry Andric                  .addUse(Ptr)
79881ad6265SDimitry Andric                  .addUse(StoreVal);
79981ad6265SDimitry Andric   if (!I.getNumMemOperands()) {
8005f757f3fSDimitry Andric     assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
8015f757f3fSDimitry Andric            I.getOpcode() ==
8025f757f3fSDimitry Andric                TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
80381ad6265SDimitry Andric     addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
80481ad6265SDimitry Andric   } else {
80581ad6265SDimitry Andric     addMemoryOperands(*I.memoperands_begin(), MIB);
80681ad6265SDimitry Andric   }
80781ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
80881ad6265SDimitry Andric }
80981ad6265SDimitry Andric 
810*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectStackSave(Register ResVReg,
811*0fca6ea1SDimitry Andric                                                const SPIRVType *ResType,
812*0fca6ea1SDimitry Andric                                                MachineInstr &I) const {
813*0fca6ea1SDimitry Andric   if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array))
814*0fca6ea1SDimitry Andric     report_fatal_error(
815*0fca6ea1SDimitry Andric         "llvm.stacksave intrinsic: this instruction requires the following "
816*0fca6ea1SDimitry Andric         "SPIR-V extension: SPV_INTEL_variable_length_array",
817*0fca6ea1SDimitry Andric         false);
818*0fca6ea1SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
819*0fca6ea1SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSaveMemoryINTEL))
820*0fca6ea1SDimitry Andric       .addDef(ResVReg)
821*0fca6ea1SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
822*0fca6ea1SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
823*0fca6ea1SDimitry Andric }
824*0fca6ea1SDimitry Andric 
825*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectStackRestore(MachineInstr &I) const {
826*0fca6ea1SDimitry Andric   if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array))
827*0fca6ea1SDimitry Andric     report_fatal_error(
828*0fca6ea1SDimitry Andric         "llvm.stackrestore intrinsic: this instruction requires the following "
829*0fca6ea1SDimitry Andric         "SPIR-V extension: SPV_INTEL_variable_length_array",
830*0fca6ea1SDimitry Andric         false);
831*0fca6ea1SDimitry Andric   if (!I.getOperand(0).isReg())
832*0fca6ea1SDimitry Andric     return false;
833*0fca6ea1SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
834*0fca6ea1SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpRestoreMemoryINTEL))
835*0fca6ea1SDimitry Andric       .addUse(I.getOperand(0).getReg())
836*0fca6ea1SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
837*0fca6ea1SDimitry Andric }
838*0fca6ea1SDimitry Andric 
83981ad6265SDimitry Andric bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg,
84081ad6265SDimitry Andric                                                   MachineInstr &I) const {
84181ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
842bdd1243dSDimitry Andric   Register SrcReg = I.getOperand(1).getReg();
843bdd1243dSDimitry Andric   if (I.getOpcode() == TargetOpcode::G_MEMSET) {
844bdd1243dSDimitry Andric     assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
845bdd1243dSDimitry Andric     unsigned Val = getIConstVal(I.getOperand(1).getReg(), MRI);
846bdd1243dSDimitry Andric     unsigned Num = getIConstVal(I.getOperand(2).getReg(), MRI);
847bdd1243dSDimitry Andric     SPIRVType *ValTy = GR.getOrCreateSPIRVIntegerType(8, I, TII);
848bdd1243dSDimitry Andric     SPIRVType *ArrTy = GR.getOrCreateSPIRVArrayType(ValTy, Num, I, TII);
849*0fca6ea1SDimitry Andric     Register Const = GR.getOrCreateConstIntArray(Val, Num, I, ArrTy, TII);
850bdd1243dSDimitry Andric     SPIRVType *VarTy = GR.getOrCreateSPIRVPointerType(
851bdd1243dSDimitry Andric         ArrTy, I, TII, SPIRV::StorageClass::UniformConstant);
852bdd1243dSDimitry Andric     // TODO: check if we have such GV, add init, use buildGlobalVariable.
853*0fca6ea1SDimitry Andric     Function &CurFunction = GR.CurMF->getFunction();
854*0fca6ea1SDimitry Andric     Type *LLVMArrTy =
855*0fca6ea1SDimitry Andric         ArrayType::get(IntegerType::get(CurFunction.getContext(), 8), Num);
856*0fca6ea1SDimitry Andric     // Module takes ownership of the global var.
857*0fca6ea1SDimitry Andric     GlobalVariable *GV = new GlobalVariable(*CurFunction.getParent(), LLVMArrTy,
858*0fca6ea1SDimitry Andric                                             true, GlobalValue::InternalLinkage,
859*0fca6ea1SDimitry Andric                                             Constant::getNullValue(LLVMArrTy));
860bdd1243dSDimitry Andric     Register VarReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
861bdd1243dSDimitry Andric     GR.add(GV, GR.CurMF, VarReg);
862bdd1243dSDimitry Andric 
863bdd1243dSDimitry Andric     buildOpDecorate(VarReg, I, TII, SPIRV::Decoration::Constant, {});
864bdd1243dSDimitry Andric     BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
865bdd1243dSDimitry Andric         .addDef(VarReg)
866bdd1243dSDimitry Andric         .addUse(GR.getSPIRVTypeID(VarTy))
867bdd1243dSDimitry Andric         .addImm(SPIRV::StorageClass::UniformConstant)
868bdd1243dSDimitry Andric         .addUse(Const)
869bdd1243dSDimitry Andric         .constrainAllUses(TII, TRI, RBI);
870bdd1243dSDimitry Andric     SPIRVType *SourceTy = GR.getOrCreateSPIRVPointerType(
871bdd1243dSDimitry Andric         ValTy, I, TII, SPIRV::StorageClass::UniformConstant);
872bdd1243dSDimitry Andric     SrcReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
873bdd1243dSDimitry Andric     selectUnOpWithSrc(SrcReg, SourceTy, I, VarReg, SPIRV::OpBitcast);
874bdd1243dSDimitry Andric   }
87581ad6265SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemorySized))
876fcaf7f86SDimitry Andric                  .addUse(I.getOperand(0).getReg())
877bdd1243dSDimitry Andric                  .addUse(SrcReg)
87881ad6265SDimitry Andric                  .addUse(I.getOperand(2).getReg());
87981ad6265SDimitry Andric   if (I.getNumMemOperands())
88081ad6265SDimitry Andric     addMemoryOperands(*I.memoperands_begin(), MIB);
88181ad6265SDimitry Andric   bool Result = MIB.constrainAllUses(TII, TRI, RBI);
882fcaf7f86SDimitry Andric   if (ResVReg.isValid() && ResVReg != MIB->getOperand(0).getReg())
88381ad6265SDimitry Andric     BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), ResVReg)
88481ad6265SDimitry Andric         .addUse(MIB->getOperand(0).getReg());
88581ad6265SDimitry Andric   return Result;
88681ad6265SDimitry Andric }
88781ad6265SDimitry Andric 
88881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg,
88981ad6265SDimitry Andric                                                const SPIRVType *ResType,
89081ad6265SDimitry Andric                                                MachineInstr &I,
891*0fca6ea1SDimitry Andric                                                unsigned NewOpcode,
892*0fca6ea1SDimitry Andric                                                unsigned NegateOpcode) const {
89381ad6265SDimitry Andric   assert(I.hasOneMemOperand());
89481ad6265SDimitry Andric   const MachineMemOperand *MemOp = *I.memoperands_begin();
895*0fca6ea1SDimitry Andric   uint32_t Scope =
896*0fca6ea1SDimitry Andric       static_cast<uint32_t>(getScope(MemOp->getSyncScopeID(), MMI));
89781ad6265SDimitry Andric   Register ScopeReg = buildI32Constant(Scope, I);
89881ad6265SDimitry Andric 
89981ad6265SDimitry Andric   Register Ptr = I.getOperand(1).getReg();
90081ad6265SDimitry Andric   // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll
90181ad6265SDimitry Andric   // auto ScSem =
90281ad6265SDimitry Andric   // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr));
90381ad6265SDimitry Andric   AtomicOrdering AO = MemOp->getSuccessOrdering();
90481ad6265SDimitry Andric   uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
90581ad6265SDimitry Andric   Register MemSemReg = buildI32Constant(MemSem /*| ScSem*/, I);
90681ad6265SDimitry Andric 
907*0fca6ea1SDimitry Andric   bool Result = false;
908*0fca6ea1SDimitry Andric   Register ValueReg = I.getOperand(2).getReg();
909*0fca6ea1SDimitry Andric   if (NegateOpcode != 0) {
910*0fca6ea1SDimitry Andric     // Translation with negative value operand is requested
911*0fca6ea1SDimitry Andric     Register TmpReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
912*0fca6ea1SDimitry Andric     Result |= selectUnOpWithSrc(TmpReg, ResType, I, ValueReg, NegateOpcode);
913*0fca6ea1SDimitry Andric     ValueReg = TmpReg;
914*0fca6ea1SDimitry Andric   }
915*0fca6ea1SDimitry Andric 
916*0fca6ea1SDimitry Andric   Result |= BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode))
91781ad6265SDimitry Andric                 .addDef(ResVReg)
91881ad6265SDimitry Andric                 .addUse(GR.getSPIRVTypeID(ResType))
91981ad6265SDimitry Andric                 .addUse(Ptr)
92081ad6265SDimitry Andric                 .addUse(ScopeReg)
92181ad6265SDimitry Andric                 .addUse(MemSemReg)
922*0fca6ea1SDimitry Andric                 .addUse(ValueReg)
92381ad6265SDimitry Andric                 .constrainAllUses(TII, TRI, RBI);
924*0fca6ea1SDimitry Andric   return Result;
925*0fca6ea1SDimitry Andric }
926*0fca6ea1SDimitry Andric 
927*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectUnmergeValues(MachineInstr &I) const {
928*0fca6ea1SDimitry Andric   unsigned ArgI = I.getNumOperands() - 1;
929*0fca6ea1SDimitry Andric   Register SrcReg =
930*0fca6ea1SDimitry Andric       I.getOperand(ArgI).isReg() ? I.getOperand(ArgI).getReg() : Register(0);
931*0fca6ea1SDimitry Andric   SPIRVType *DefType =
932*0fca6ea1SDimitry Andric       SrcReg.isValid() ? GR.getSPIRVTypeForVReg(SrcReg) : nullptr;
933*0fca6ea1SDimitry Andric   if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector)
934*0fca6ea1SDimitry Andric     report_fatal_error(
935*0fca6ea1SDimitry Andric         "cannot select G_UNMERGE_VALUES with a non-vector argument");
936*0fca6ea1SDimitry Andric 
937*0fca6ea1SDimitry Andric   SPIRVType *ScalarType =
938*0fca6ea1SDimitry Andric       GR.getSPIRVTypeForVReg(DefType->getOperand(1).getReg());
939*0fca6ea1SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
940*0fca6ea1SDimitry Andric   bool Res = false;
941*0fca6ea1SDimitry Andric   for (unsigned i = 0; i < I.getNumDefs(); ++i) {
942*0fca6ea1SDimitry Andric     Register ResVReg = I.getOperand(i).getReg();
943*0fca6ea1SDimitry Andric     SPIRVType *ResType = GR.getSPIRVTypeForVReg(ResVReg);
944*0fca6ea1SDimitry Andric     if (!ResType) {
945*0fca6ea1SDimitry Andric       // There was no "assign type" actions, let's fix this now
946*0fca6ea1SDimitry Andric       ResType = ScalarType;
947*0fca6ea1SDimitry Andric       MRI->setRegClass(ResVReg, &SPIRV::IDRegClass);
948*0fca6ea1SDimitry Andric       MRI->setType(ResVReg, LLT::scalar(GR.getScalarOrVectorBitWidth(ResType)));
949*0fca6ea1SDimitry Andric       GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF);
950*0fca6ea1SDimitry Andric     }
951*0fca6ea1SDimitry Andric     auto MIB =
952*0fca6ea1SDimitry Andric         BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
953*0fca6ea1SDimitry Andric             .addDef(ResVReg)
954*0fca6ea1SDimitry Andric             .addUse(GR.getSPIRVTypeID(ResType))
955*0fca6ea1SDimitry Andric             .addUse(SrcReg)
956*0fca6ea1SDimitry Andric             .addImm(static_cast<int64_t>(i));
957*0fca6ea1SDimitry Andric     Res |= MIB.constrainAllUses(TII, TRI, RBI);
958*0fca6ea1SDimitry Andric   }
959*0fca6ea1SDimitry Andric   return Res;
96081ad6265SDimitry Andric }
96181ad6265SDimitry Andric 
96281ad6265SDimitry Andric bool SPIRVInstructionSelector::selectFence(MachineInstr &I) const {
96381ad6265SDimitry Andric   AtomicOrdering AO = AtomicOrdering(I.getOperand(0).getImm());
96481ad6265SDimitry Andric   uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
96581ad6265SDimitry Andric   Register MemSemReg = buildI32Constant(MemSem, I);
96681ad6265SDimitry Andric   SyncScope::ID Ord = SyncScope::ID(I.getOperand(1).getImm());
967*0fca6ea1SDimitry Andric   uint32_t Scope = static_cast<uint32_t>(getScope(Ord, MMI));
96881ad6265SDimitry Andric   Register ScopeReg = buildI32Constant(Scope, I);
96981ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
97081ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMemoryBarrier))
97181ad6265SDimitry Andric       .addUse(ScopeReg)
97281ad6265SDimitry Andric       .addUse(MemSemReg)
97381ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
97481ad6265SDimitry Andric }
97581ad6265SDimitry Andric 
97681ad6265SDimitry Andric bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg,
97781ad6265SDimitry Andric                                                    const SPIRVType *ResType,
97881ad6265SDimitry Andric                                                    MachineInstr &I) const {
979fcaf7f86SDimitry Andric   Register ScopeReg;
980fcaf7f86SDimitry Andric   Register MemSemEqReg;
981fcaf7f86SDimitry Andric   Register MemSemNeqReg;
982fcaf7f86SDimitry Andric   Register Ptr = I.getOperand(2).getReg();
9835f757f3fSDimitry Andric   if (!isa<GIntrinsic>(I)) {
98481ad6265SDimitry Andric     assert(I.hasOneMemOperand());
98581ad6265SDimitry Andric     const MachineMemOperand *MemOp = *I.memoperands_begin();
986*0fca6ea1SDimitry Andric     unsigned Scope =
987*0fca6ea1SDimitry Andric         static_cast<uint32_t>(getScope(MemOp->getSyncScopeID(), MMI));
988fcaf7f86SDimitry Andric     ScopeReg = buildI32Constant(Scope, I);
98981ad6265SDimitry Andric 
990fcaf7f86SDimitry Andric     unsigned ScSem = static_cast<uint32_t>(
991fcaf7f86SDimitry Andric         getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr)));
992fcaf7f86SDimitry Andric     AtomicOrdering AO = MemOp->getSuccessOrdering();
993fcaf7f86SDimitry Andric     unsigned MemSemEq = static_cast<uint32_t>(getMemSemantics(AO)) | ScSem;
994fcaf7f86SDimitry Andric     MemSemEqReg = buildI32Constant(MemSemEq, I);
995fcaf7f86SDimitry Andric     AtomicOrdering FO = MemOp->getFailureOrdering();
996fcaf7f86SDimitry Andric     unsigned MemSemNeq = static_cast<uint32_t>(getMemSemantics(FO)) | ScSem;
997fcaf7f86SDimitry Andric     MemSemNeqReg =
998fcaf7f86SDimitry Andric         MemSemEq == MemSemNeq ? MemSemEqReg : buildI32Constant(MemSemNeq, I);
999fcaf7f86SDimitry Andric   } else {
1000fcaf7f86SDimitry Andric     ScopeReg = I.getOperand(5).getReg();
1001fcaf7f86SDimitry Andric     MemSemEqReg = I.getOperand(6).getReg();
1002fcaf7f86SDimitry Andric     MemSemNeqReg = I.getOperand(7).getReg();
1003fcaf7f86SDimitry Andric   }
1004fcaf7f86SDimitry Andric 
100581ad6265SDimitry Andric   Register Cmp = I.getOperand(3).getReg();
100681ad6265SDimitry Andric   Register Val = I.getOperand(4).getReg();
100781ad6265SDimitry Andric   SPIRVType *SpvValTy = GR.getSPIRVTypeForVReg(Val);
1008fcaf7f86SDimitry Andric   Register ACmpRes = MRI->createVirtualRegister(&SPIRV::IDRegClass);
100981ad6265SDimitry Andric   const DebugLoc &DL = I.getDebugLoc();
1010fcaf7f86SDimitry Andric   bool Result =
1011fcaf7f86SDimitry Andric       BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpAtomicCompareExchange))
1012fcaf7f86SDimitry Andric           .addDef(ACmpRes)
101381ad6265SDimitry Andric           .addUse(GR.getSPIRVTypeID(SpvValTy))
101481ad6265SDimitry Andric           .addUse(Ptr)
101581ad6265SDimitry Andric           .addUse(ScopeReg)
101681ad6265SDimitry Andric           .addUse(MemSemEqReg)
101781ad6265SDimitry Andric           .addUse(MemSemNeqReg)
101881ad6265SDimitry Andric           .addUse(Val)
101981ad6265SDimitry Andric           .addUse(Cmp)
102081ad6265SDimitry Andric           .constrainAllUses(TII, TRI, RBI);
1021fcaf7f86SDimitry Andric   Register CmpSuccReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
1022fcaf7f86SDimitry Andric   SPIRVType *BoolTy = GR.getOrCreateSPIRVBoolType(I, TII);
1023fcaf7f86SDimitry Andric   Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpIEqual))
1024fcaf7f86SDimitry Andric                 .addDef(CmpSuccReg)
1025fcaf7f86SDimitry Andric                 .addUse(GR.getSPIRVTypeID(BoolTy))
1026fcaf7f86SDimitry Andric                 .addUse(ACmpRes)
1027fcaf7f86SDimitry Andric                 .addUse(Cmp)
1028fcaf7f86SDimitry Andric                 .constrainAllUses(TII, TRI, RBI);
1029fcaf7f86SDimitry Andric   Register TmpReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
1030fcaf7f86SDimitry Andric   Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
1031fcaf7f86SDimitry Andric                 .addDef(TmpReg)
1032fcaf7f86SDimitry Andric                 .addUse(GR.getSPIRVTypeID(ResType))
1033fcaf7f86SDimitry Andric                 .addUse(ACmpRes)
1034fcaf7f86SDimitry Andric                 .addUse(GR.getOrCreateUndef(I, ResType, TII))
1035fcaf7f86SDimitry Andric                 .addImm(0)
1036fcaf7f86SDimitry Andric                 .constrainAllUses(TII, TRI, RBI);
1037fcaf7f86SDimitry Andric   Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
1038fcaf7f86SDimitry Andric                 .addDef(ResVReg)
1039fcaf7f86SDimitry Andric                 .addUse(GR.getSPIRVTypeID(ResType))
1040fcaf7f86SDimitry Andric                 .addUse(CmpSuccReg)
1041fcaf7f86SDimitry Andric                 .addUse(TmpReg)
1042fcaf7f86SDimitry Andric                 .addImm(1)
1043fcaf7f86SDimitry Andric                 .constrainAllUses(TII, TRI, RBI);
1044fcaf7f86SDimitry Andric   return Result;
104581ad6265SDimitry Andric }
104681ad6265SDimitry Andric 
1047bdd1243dSDimitry Andric static bool isGenericCastablePtr(SPIRV::StorageClass::StorageClass SC) {
104881ad6265SDimitry Andric   switch (SC) {
104981ad6265SDimitry Andric   case SPIRV::StorageClass::Workgroup:
105081ad6265SDimitry Andric   case SPIRV::StorageClass::CrossWorkgroup:
105181ad6265SDimitry Andric   case SPIRV::StorageClass::Function:
105281ad6265SDimitry Andric     return true;
105381ad6265SDimitry Andric   default:
105481ad6265SDimitry Andric     return false;
105581ad6265SDimitry Andric   }
105681ad6265SDimitry Andric }
105781ad6265SDimitry Andric 
1058*0fca6ea1SDimitry Andric static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) {
1059*0fca6ea1SDimitry Andric   switch (SC) {
1060*0fca6ea1SDimitry Andric   case SPIRV::StorageClass::DeviceOnlyINTEL:
1061*0fca6ea1SDimitry Andric   case SPIRV::StorageClass::HostOnlyINTEL:
1062*0fca6ea1SDimitry Andric     return true;
1063*0fca6ea1SDimitry Andric   default:
1064*0fca6ea1SDimitry Andric     return false;
1065*0fca6ea1SDimitry Andric   }
1066*0fca6ea1SDimitry Andric }
1067*0fca6ea1SDimitry Andric 
106881ad6265SDimitry Andric // In SPIR-V address space casting can only happen to and from the Generic
1069*0fca6ea1SDimitry Andric // storage class. We can also only cast Workgroup, CrossWorkgroup, or Function
107081ad6265SDimitry Andric // pointers to and from Generic pointers. As such, we can convert e.g. from
107181ad6265SDimitry Andric // Workgroup to Function by going via a Generic pointer as an intermediary. All
107281ad6265SDimitry Andric // other combinations can only be done by a bitcast, and are probably not safe.
107381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
107481ad6265SDimitry Andric                                                    const SPIRVType *ResType,
107581ad6265SDimitry Andric                                                    MachineInstr &I) const {
1076fcaf7f86SDimitry Andric   // If the AddrSpaceCast user is single and in OpConstantComposite or
1077fcaf7f86SDimitry Andric   // OpVariable, we should select OpSpecConstantOp.
1078fcaf7f86SDimitry Andric   auto UIs = MRI->use_instructions(ResVReg);
1079fcaf7f86SDimitry Andric   if (!UIs.empty() && ++UIs.begin() == UIs.end() &&
1080fcaf7f86SDimitry Andric       (UIs.begin()->getOpcode() == SPIRV::OpConstantComposite ||
1081fcaf7f86SDimitry Andric        UIs.begin()->getOpcode() == SPIRV::OpVariable ||
1082fcaf7f86SDimitry Andric        isSpvIntrinsic(*UIs.begin(), Intrinsic::spv_init_global))) {
1083fcaf7f86SDimitry Andric     Register NewReg = I.getOperand(1).getReg();
1084fcaf7f86SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
1085fcaf7f86SDimitry Andric     SPIRVType *SpvBaseTy = GR.getOrCreateSPIRVIntegerType(8, I, TII);
1086fcaf7f86SDimitry Andric     ResType = GR.getOrCreateSPIRVPointerType(SpvBaseTy, I, TII,
1087fcaf7f86SDimitry Andric                                              SPIRV::StorageClass::Generic);
1088fcaf7f86SDimitry Andric     bool Result =
1089fcaf7f86SDimitry Andric         BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
1090fcaf7f86SDimitry Andric             .addDef(ResVReg)
1091fcaf7f86SDimitry Andric             .addUse(GR.getSPIRVTypeID(ResType))
1092fcaf7f86SDimitry Andric             .addImm(static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric))
1093fcaf7f86SDimitry Andric             .addUse(NewReg)
1094fcaf7f86SDimitry Andric             .constrainAllUses(TII, TRI, RBI);
1095fcaf7f86SDimitry Andric     return Result;
1096fcaf7f86SDimitry Andric   }
109781ad6265SDimitry Andric   Register SrcPtr = I.getOperand(1).getReg();
109881ad6265SDimitry Andric   SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
1099bdd1243dSDimitry Andric   SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtr);
1100bdd1243dSDimitry Andric   SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResVReg);
110181ad6265SDimitry Andric 
1102*0fca6ea1SDimitry Andric   // don't generate a cast between identical storage classes
1103*0fca6ea1SDimitry Andric   if (SrcSC == DstSC)
1104*0fca6ea1SDimitry Andric     return BuildMI(*I.getParent(), I, I.getDebugLoc(),
1105*0fca6ea1SDimitry Andric                    TII.get(TargetOpcode::COPY))
1106*0fca6ea1SDimitry Andric         .addDef(ResVReg)
1107*0fca6ea1SDimitry Andric         .addUse(SrcPtr)
1108*0fca6ea1SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
1109*0fca6ea1SDimitry Andric 
1110*0fca6ea1SDimitry Andric   // Casting from an eligible pointer to Generic.
111181ad6265SDimitry Andric   if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC))
111281ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
1113*0fca6ea1SDimitry Andric   // Casting from Generic to an eligible pointer.
111481ad6265SDimitry Andric   if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC))
111581ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
1116*0fca6ea1SDimitry Andric   // Casting between 2 eligible pointers using Generic as an intermediary.
111781ad6265SDimitry Andric   if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
111881ad6265SDimitry Andric     Register Tmp = MRI->createVirtualRegister(&SPIRV::IDRegClass);
111981ad6265SDimitry Andric     SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
1120*0fca6ea1SDimitry Andric         GR.getPointeeType(SrcPtrTy), I, TII, SPIRV::StorageClass::Generic);
112181ad6265SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
112281ad6265SDimitry Andric     const DebugLoc &DL = I.getDebugLoc();
112381ad6265SDimitry Andric     bool Success = BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric))
112481ad6265SDimitry Andric                        .addDef(Tmp)
112581ad6265SDimitry Andric                        .addUse(GR.getSPIRVTypeID(GenericPtrTy))
112681ad6265SDimitry Andric                        .addUse(SrcPtr)
112781ad6265SDimitry Andric                        .constrainAllUses(TII, TRI, RBI);
112881ad6265SDimitry Andric     return Success && BuildMI(BB, I, DL, TII.get(SPIRV::OpGenericCastToPtr))
112981ad6265SDimitry Andric                           .addDef(ResVReg)
113081ad6265SDimitry Andric                           .addUse(GR.getSPIRVTypeID(ResType))
113181ad6265SDimitry Andric                           .addUse(Tmp)
113281ad6265SDimitry Andric                           .constrainAllUses(TII, TRI, RBI);
113381ad6265SDimitry Andric   }
1134*0fca6ea1SDimitry Andric 
1135*0fca6ea1SDimitry Andric   // Check if instructions from the SPV_INTEL_usm_storage_classes extension may
1136*0fca6ea1SDimitry Andric   // be applied
1137*0fca6ea1SDimitry Andric   if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::CrossWorkgroup)
1138*0fca6ea1SDimitry Andric     return selectUnOp(ResVReg, ResType, I,
1139*0fca6ea1SDimitry Andric                       SPIRV::OpPtrCastToCrossWorkgroupINTEL);
1140*0fca6ea1SDimitry Andric   if (SrcSC == SPIRV::StorageClass::CrossWorkgroup && isUSMStorageClass(DstSC))
1141*0fca6ea1SDimitry Andric     return selectUnOp(ResVReg, ResType, I,
1142*0fca6ea1SDimitry Andric                       SPIRV::OpCrossWorkgroupCastToPtrINTEL);
1143*0fca6ea1SDimitry Andric   if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::Generic)
1144*0fca6ea1SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
1145*0fca6ea1SDimitry Andric   if (SrcSC == SPIRV::StorageClass::Generic && isUSMStorageClass(DstSC))
1146*0fca6ea1SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
1147*0fca6ea1SDimitry Andric 
1148*0fca6ea1SDimitry Andric   // Bitcast for pointers requires that the address spaces must match
1149*0fca6ea1SDimitry Andric   return false;
115081ad6265SDimitry Andric }
115181ad6265SDimitry Andric 
115281ad6265SDimitry Andric static unsigned getFCmpOpcode(unsigned PredNum) {
115381ad6265SDimitry Andric   auto Pred = static_cast<CmpInst::Predicate>(PredNum);
115481ad6265SDimitry Andric   switch (Pred) {
115581ad6265SDimitry Andric   case CmpInst::FCMP_OEQ:
115681ad6265SDimitry Andric     return SPIRV::OpFOrdEqual;
115781ad6265SDimitry Andric   case CmpInst::FCMP_OGE:
115881ad6265SDimitry Andric     return SPIRV::OpFOrdGreaterThanEqual;
115981ad6265SDimitry Andric   case CmpInst::FCMP_OGT:
116081ad6265SDimitry Andric     return SPIRV::OpFOrdGreaterThan;
116181ad6265SDimitry Andric   case CmpInst::FCMP_OLE:
116281ad6265SDimitry Andric     return SPIRV::OpFOrdLessThanEqual;
116381ad6265SDimitry Andric   case CmpInst::FCMP_OLT:
116481ad6265SDimitry Andric     return SPIRV::OpFOrdLessThan;
116581ad6265SDimitry Andric   case CmpInst::FCMP_ONE:
116681ad6265SDimitry Andric     return SPIRV::OpFOrdNotEqual;
116781ad6265SDimitry Andric   case CmpInst::FCMP_ORD:
116881ad6265SDimitry Andric     return SPIRV::OpOrdered;
116981ad6265SDimitry Andric   case CmpInst::FCMP_UEQ:
117081ad6265SDimitry Andric     return SPIRV::OpFUnordEqual;
117181ad6265SDimitry Andric   case CmpInst::FCMP_UGE:
117281ad6265SDimitry Andric     return SPIRV::OpFUnordGreaterThanEqual;
117381ad6265SDimitry Andric   case CmpInst::FCMP_UGT:
117481ad6265SDimitry Andric     return SPIRV::OpFUnordGreaterThan;
117581ad6265SDimitry Andric   case CmpInst::FCMP_ULE:
117681ad6265SDimitry Andric     return SPIRV::OpFUnordLessThanEqual;
117781ad6265SDimitry Andric   case CmpInst::FCMP_ULT:
117881ad6265SDimitry Andric     return SPIRV::OpFUnordLessThan;
117981ad6265SDimitry Andric   case CmpInst::FCMP_UNE:
118081ad6265SDimitry Andric     return SPIRV::OpFUnordNotEqual;
118181ad6265SDimitry Andric   case CmpInst::FCMP_UNO:
118281ad6265SDimitry Andric     return SPIRV::OpUnordered;
118381ad6265SDimitry Andric   default:
118481ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for FCmp");
118581ad6265SDimitry Andric   }
118681ad6265SDimitry Andric }
118781ad6265SDimitry Andric 
118881ad6265SDimitry Andric static unsigned getICmpOpcode(unsigned PredNum) {
118981ad6265SDimitry Andric   auto Pred = static_cast<CmpInst::Predicate>(PredNum);
119081ad6265SDimitry Andric   switch (Pred) {
119181ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
119281ad6265SDimitry Andric     return SPIRV::OpIEqual;
119381ad6265SDimitry Andric   case CmpInst::ICMP_NE:
119481ad6265SDimitry Andric     return SPIRV::OpINotEqual;
119581ad6265SDimitry Andric   case CmpInst::ICMP_SGE:
119681ad6265SDimitry Andric     return SPIRV::OpSGreaterThanEqual;
119781ad6265SDimitry Andric   case CmpInst::ICMP_SGT:
119881ad6265SDimitry Andric     return SPIRV::OpSGreaterThan;
119981ad6265SDimitry Andric   case CmpInst::ICMP_SLE:
120081ad6265SDimitry Andric     return SPIRV::OpSLessThanEqual;
120181ad6265SDimitry Andric   case CmpInst::ICMP_SLT:
120281ad6265SDimitry Andric     return SPIRV::OpSLessThan;
120381ad6265SDimitry Andric   case CmpInst::ICMP_UGE:
120481ad6265SDimitry Andric     return SPIRV::OpUGreaterThanEqual;
120581ad6265SDimitry Andric   case CmpInst::ICMP_UGT:
120681ad6265SDimitry Andric     return SPIRV::OpUGreaterThan;
120781ad6265SDimitry Andric   case CmpInst::ICMP_ULE:
120881ad6265SDimitry Andric     return SPIRV::OpULessThanEqual;
120981ad6265SDimitry Andric   case CmpInst::ICMP_ULT:
121081ad6265SDimitry Andric     return SPIRV::OpULessThan;
121181ad6265SDimitry Andric   default:
121281ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for ICmp");
121381ad6265SDimitry Andric   }
121481ad6265SDimitry Andric }
121581ad6265SDimitry Andric 
121681ad6265SDimitry Andric static unsigned getPtrCmpOpcode(unsigned Pred) {
121781ad6265SDimitry Andric   switch (static_cast<CmpInst::Predicate>(Pred)) {
121881ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
121981ad6265SDimitry Andric     return SPIRV::OpPtrEqual;
122081ad6265SDimitry Andric   case CmpInst::ICMP_NE:
122181ad6265SDimitry Andric     return SPIRV::OpPtrNotEqual;
122281ad6265SDimitry Andric   default:
122381ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for pointer comparison");
122481ad6265SDimitry Andric   }
122581ad6265SDimitry Andric }
122681ad6265SDimitry Andric 
122781ad6265SDimitry Andric // Return the logical operation, or abort if none exists.
122881ad6265SDimitry Andric static unsigned getBoolCmpOpcode(unsigned PredNum) {
122981ad6265SDimitry Andric   auto Pred = static_cast<CmpInst::Predicate>(PredNum);
123081ad6265SDimitry Andric   switch (Pred) {
123181ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
123281ad6265SDimitry Andric     return SPIRV::OpLogicalEqual;
123381ad6265SDimitry Andric   case CmpInst::ICMP_NE:
123481ad6265SDimitry Andric     return SPIRV::OpLogicalNotEqual;
123581ad6265SDimitry Andric   default:
123681ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for Bool comparison");
123781ad6265SDimitry Andric   }
123881ad6265SDimitry Andric }
123981ad6265SDimitry Andric 
1240*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectAnyOrAll(Register ResVReg,
1241*0fca6ea1SDimitry Andric                                               const SPIRVType *ResType,
1242*0fca6ea1SDimitry Andric                                               MachineInstr &I,
1243*0fca6ea1SDimitry Andric                                               unsigned OpAnyOrAll) const {
1244*0fca6ea1SDimitry Andric   assert(I.getNumOperands() == 3);
1245*0fca6ea1SDimitry Andric   assert(I.getOperand(2).isReg());
1246*0fca6ea1SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
1247*0fca6ea1SDimitry Andric   Register InputRegister = I.getOperand(2).getReg();
1248*0fca6ea1SDimitry Andric   SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister);
1249*0fca6ea1SDimitry Andric 
1250*0fca6ea1SDimitry Andric   if (!InputType)
1251*0fca6ea1SDimitry Andric     report_fatal_error("Input Type could not be determined.");
1252*0fca6ea1SDimitry Andric 
1253*0fca6ea1SDimitry Andric   bool IsBoolTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeBool);
1254*0fca6ea1SDimitry Andric   bool IsVectorTy = InputType->getOpcode() == SPIRV::OpTypeVector;
1255*0fca6ea1SDimitry Andric   if (IsBoolTy && !IsVectorTy) {
1256*0fca6ea1SDimitry Andric     assert(ResVReg == I.getOperand(0).getReg());
1257*0fca6ea1SDimitry Andric     return BuildMI(*I.getParent(), I, I.getDebugLoc(),
1258*0fca6ea1SDimitry Andric                    TII.get(TargetOpcode::COPY))
1259*0fca6ea1SDimitry Andric         .addDef(ResVReg)
1260*0fca6ea1SDimitry Andric         .addUse(InputRegister)
1261*0fca6ea1SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
1262*0fca6ea1SDimitry Andric   }
1263*0fca6ea1SDimitry Andric 
1264*0fca6ea1SDimitry Andric   bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
1265*0fca6ea1SDimitry Andric   unsigned SpirvNotEqualId =
1266*0fca6ea1SDimitry Andric       IsFloatTy ? SPIRV::OpFOrdNotEqual : SPIRV::OpINotEqual;
1267*0fca6ea1SDimitry Andric   SPIRVType *SpvBoolScalarTy = GR.getOrCreateSPIRVBoolType(I, TII);
1268*0fca6ea1SDimitry Andric   SPIRVType *SpvBoolTy = SpvBoolScalarTy;
1269*0fca6ea1SDimitry Andric   Register NotEqualReg = ResVReg;
1270*0fca6ea1SDimitry Andric 
1271*0fca6ea1SDimitry Andric   if (IsVectorTy) {
1272*0fca6ea1SDimitry Andric     NotEqualReg = IsBoolTy ? InputRegister
1273*0fca6ea1SDimitry Andric                            : MRI->createVirtualRegister(&SPIRV::IDRegClass);
1274*0fca6ea1SDimitry Andric     const unsigned NumElts = InputType->getOperand(2).getImm();
1275*0fca6ea1SDimitry Andric     SpvBoolTy = GR.getOrCreateSPIRVVectorType(SpvBoolTy, NumElts, I, TII);
1276*0fca6ea1SDimitry Andric   }
1277*0fca6ea1SDimitry Andric 
1278*0fca6ea1SDimitry Andric   if (!IsBoolTy) {
1279*0fca6ea1SDimitry Andric     Register ConstZeroReg =
1280*0fca6ea1SDimitry Andric         IsFloatTy ? buildZerosValF(InputType, I) : buildZerosVal(InputType, I);
1281*0fca6ea1SDimitry Andric 
1282*0fca6ea1SDimitry Andric     BuildMI(BB, I, I.getDebugLoc(), TII.get(SpirvNotEqualId))
1283*0fca6ea1SDimitry Andric         .addDef(NotEqualReg)
1284*0fca6ea1SDimitry Andric         .addUse(GR.getSPIRVTypeID(SpvBoolTy))
1285*0fca6ea1SDimitry Andric         .addUse(InputRegister)
1286*0fca6ea1SDimitry Andric         .addUse(ConstZeroReg)
1287*0fca6ea1SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
1288*0fca6ea1SDimitry Andric   }
1289*0fca6ea1SDimitry Andric 
1290*0fca6ea1SDimitry Andric   if (!IsVectorTy)
1291*0fca6ea1SDimitry Andric     return true;
1292*0fca6ea1SDimitry Andric 
1293*0fca6ea1SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(OpAnyOrAll))
1294*0fca6ea1SDimitry Andric       .addDef(ResVReg)
1295*0fca6ea1SDimitry Andric       .addUse(GR.getSPIRVTypeID(SpvBoolScalarTy))
1296*0fca6ea1SDimitry Andric       .addUse(NotEqualReg)
1297*0fca6ea1SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
1298*0fca6ea1SDimitry Andric }
1299*0fca6ea1SDimitry Andric 
1300*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectAll(Register ResVReg,
1301*0fca6ea1SDimitry Andric                                          const SPIRVType *ResType,
1302*0fca6ea1SDimitry Andric                                          MachineInstr &I) const {
1303*0fca6ea1SDimitry Andric   return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAll);
1304*0fca6ea1SDimitry Andric }
1305*0fca6ea1SDimitry Andric 
1306*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectAny(Register ResVReg,
1307*0fca6ea1SDimitry Andric                                          const SPIRVType *ResType,
1308*0fca6ea1SDimitry Andric                                          MachineInstr &I) const {
1309*0fca6ea1SDimitry Andric   return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAny);
1310*0fca6ea1SDimitry Andric }
1311*0fca6ea1SDimitry Andric 
1312*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectFmix(Register ResVReg,
1313*0fca6ea1SDimitry Andric                                           const SPIRVType *ResType,
1314*0fca6ea1SDimitry Andric                                           MachineInstr &I) const {
1315*0fca6ea1SDimitry Andric 
1316*0fca6ea1SDimitry Andric   assert(I.getNumOperands() == 5);
1317*0fca6ea1SDimitry Andric   assert(I.getOperand(2).isReg());
1318*0fca6ea1SDimitry Andric   assert(I.getOperand(3).isReg());
1319*0fca6ea1SDimitry Andric   assert(I.getOperand(4).isReg());
1320*0fca6ea1SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
1321*0fca6ea1SDimitry Andric 
1322*0fca6ea1SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1323*0fca6ea1SDimitry Andric       .addDef(ResVReg)
1324*0fca6ea1SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
1325*0fca6ea1SDimitry Andric       .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1326*0fca6ea1SDimitry Andric       .addImm(GL::FMix)
1327*0fca6ea1SDimitry Andric       .addUse(I.getOperand(2).getReg())
1328*0fca6ea1SDimitry Andric       .addUse(I.getOperand(3).getReg())
1329*0fca6ea1SDimitry Andric       .addUse(I.getOperand(4).getReg())
1330*0fca6ea1SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
1331*0fca6ea1SDimitry Andric }
1332*0fca6ea1SDimitry Andric 
1333*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectRsqrt(Register ResVReg,
1334*0fca6ea1SDimitry Andric                                            const SPIRVType *ResType,
1335*0fca6ea1SDimitry Andric                                            MachineInstr &I) const {
1336*0fca6ea1SDimitry Andric 
1337*0fca6ea1SDimitry Andric   assert(I.getNumOperands() == 3);
1338*0fca6ea1SDimitry Andric   assert(I.getOperand(2).isReg());
1339*0fca6ea1SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
1340*0fca6ea1SDimitry Andric 
1341*0fca6ea1SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
1342*0fca6ea1SDimitry Andric       .addDef(ResVReg)
1343*0fca6ea1SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
1344*0fca6ea1SDimitry Andric       .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1345*0fca6ea1SDimitry Andric       .addImm(GL::InverseSqrt)
1346*0fca6ea1SDimitry Andric       .addUse(I.getOperand(2).getReg())
1347*0fca6ea1SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
1348*0fca6ea1SDimitry Andric }
1349*0fca6ea1SDimitry Andric 
135081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
135181ad6265SDimitry Andric                                                 const SPIRVType *ResType,
135281ad6265SDimitry Andric                                                 MachineInstr &I) const {
135381ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
135481ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse))
135581ad6265SDimitry Andric       .addDef(ResVReg)
135681ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
135781ad6265SDimitry Andric       .addUse(I.getOperand(1).getReg())
135881ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
135981ad6265SDimitry Andric }
136081ad6265SDimitry Andric 
1361*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectFreeze(Register ResVReg,
1362*0fca6ea1SDimitry Andric                                             const SPIRVType *ResType,
1363*0fca6ea1SDimitry Andric                                             MachineInstr &I) const {
1364*0fca6ea1SDimitry Andric   // There is no way to implement `freeze` correctly without support on SPIR-V
1365*0fca6ea1SDimitry Andric   // standard side, but we may at least address a simple (static) case when
1366*0fca6ea1SDimitry Andric   // undef/poison value presence is obvious. The main benefit of even
1367*0fca6ea1SDimitry Andric   // incomplete `freeze` support is preventing of translation from crashing due
1368*0fca6ea1SDimitry Andric   // to lack of support on legalization and instruction selection steps.
1369*0fca6ea1SDimitry Andric   if (!I.getOperand(0).isReg() || !I.getOperand(1).isReg())
1370*0fca6ea1SDimitry Andric     return false;
1371*0fca6ea1SDimitry Andric   Register OpReg = I.getOperand(1).getReg();
1372*0fca6ea1SDimitry Andric   if (MachineInstr *Def = MRI->getVRegDef(OpReg)) {
1373*0fca6ea1SDimitry Andric     Register Reg;
1374*0fca6ea1SDimitry Andric     switch (Def->getOpcode()) {
1375*0fca6ea1SDimitry Andric     case SPIRV::ASSIGN_TYPE:
1376*0fca6ea1SDimitry Andric       if (MachineInstr *AssignToDef =
1377*0fca6ea1SDimitry Andric               MRI->getVRegDef(Def->getOperand(1).getReg())) {
1378*0fca6ea1SDimitry Andric         if (AssignToDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
1379*0fca6ea1SDimitry Andric           Reg = Def->getOperand(2).getReg();
1380*0fca6ea1SDimitry Andric       }
1381*0fca6ea1SDimitry Andric       break;
1382*0fca6ea1SDimitry Andric     case SPIRV::OpUndef:
1383*0fca6ea1SDimitry Andric       Reg = Def->getOperand(1).getReg();
1384*0fca6ea1SDimitry Andric       break;
1385*0fca6ea1SDimitry Andric     }
1386*0fca6ea1SDimitry Andric     unsigned DestOpCode;
1387*0fca6ea1SDimitry Andric     if (Reg.isValid()) {
1388*0fca6ea1SDimitry Andric       DestOpCode = SPIRV::OpConstantNull;
1389*0fca6ea1SDimitry Andric     } else {
1390*0fca6ea1SDimitry Andric       DestOpCode = TargetOpcode::COPY;
1391*0fca6ea1SDimitry Andric       Reg = OpReg;
1392*0fca6ea1SDimitry Andric     }
1393*0fca6ea1SDimitry Andric     return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DestOpCode))
1394*0fca6ea1SDimitry Andric         .addDef(I.getOperand(0).getReg())
1395*0fca6ea1SDimitry Andric         .addUse(Reg)
1396*0fca6ea1SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
1397*0fca6ea1SDimitry Andric   }
1398*0fca6ea1SDimitry Andric   return false;
1399*0fca6ea1SDimitry Andric }
1400*0fca6ea1SDimitry Andric 
140181ad6265SDimitry Andric bool SPIRVInstructionSelector::selectConstVector(Register ResVReg,
140281ad6265SDimitry Andric                                                  const SPIRVType *ResType,
140381ad6265SDimitry Andric                                                  MachineInstr &I) const {
140481ad6265SDimitry Andric   // TODO: only const case is supported for now.
140581ad6265SDimitry Andric   assert(std::all_of(
140681ad6265SDimitry Andric       I.operands_begin(), I.operands_end(), [this](const MachineOperand &MO) {
140781ad6265SDimitry Andric         if (MO.isDef())
140881ad6265SDimitry Andric           return true;
140981ad6265SDimitry Andric         if (!MO.isReg())
141081ad6265SDimitry Andric           return false;
141181ad6265SDimitry Andric         SPIRVType *ConstTy = this->MRI->getVRegDef(MO.getReg());
141281ad6265SDimitry Andric         assert(ConstTy && ConstTy->getOpcode() == SPIRV::ASSIGN_TYPE &&
141381ad6265SDimitry Andric                ConstTy->getOperand(1).isReg());
141481ad6265SDimitry Andric         Register ConstReg = ConstTy->getOperand(1).getReg();
141581ad6265SDimitry Andric         const MachineInstr *Const = this->MRI->getVRegDef(ConstReg);
141681ad6265SDimitry Andric         assert(Const);
141781ad6265SDimitry Andric         return (Const->getOpcode() == TargetOpcode::G_CONSTANT ||
141881ad6265SDimitry Andric                 Const->getOpcode() == TargetOpcode::G_FCONSTANT);
141981ad6265SDimitry Andric       }));
142081ad6265SDimitry Andric 
142181ad6265SDimitry Andric   auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
142281ad6265SDimitry Andric                      TII.get(SPIRV::OpConstantComposite))
142381ad6265SDimitry Andric                  .addDef(ResVReg)
142481ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType));
142581ad6265SDimitry Andric   for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i)
142681ad6265SDimitry Andric     MIB.addUse(I.getOperand(i).getReg());
142781ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
142881ad6265SDimitry Andric }
142981ad6265SDimitry Andric 
1430*0fca6ea1SDimitry Andric static unsigned getArrayComponentCount(MachineRegisterInfo *MRI,
1431*0fca6ea1SDimitry Andric                                        const SPIRVType *ResType) {
1432*0fca6ea1SDimitry Andric   Register OpReg = ResType->getOperand(2).getReg();
1433*0fca6ea1SDimitry Andric   SPIRVType *OpDef = MRI->getVRegDef(OpReg);
1434*0fca6ea1SDimitry Andric   if (!OpDef)
1435*0fca6ea1SDimitry Andric     return 0;
1436*0fca6ea1SDimitry Andric   if (OpDef->getOpcode() == SPIRV::ASSIGN_TYPE &&
1437*0fca6ea1SDimitry Andric       OpDef->getOperand(1).isReg()) {
1438*0fca6ea1SDimitry Andric     if (SPIRVType *RefDef = MRI->getVRegDef(OpDef->getOperand(1).getReg()))
1439*0fca6ea1SDimitry Andric       OpDef = RefDef;
1440*0fca6ea1SDimitry Andric   }
1441*0fca6ea1SDimitry Andric   unsigned N = OpDef->getOpcode() == TargetOpcode::G_CONSTANT
1442*0fca6ea1SDimitry Andric                    ? OpDef->getOperand(1).getCImm()->getValue().getZExtValue()
1443*0fca6ea1SDimitry Andric                    : 0;
1444*0fca6ea1SDimitry Andric   return N;
1445*0fca6ea1SDimitry Andric }
1446*0fca6ea1SDimitry Andric 
1447*0fca6ea1SDimitry Andric // Return true if the type represents a constant register
1448*0fca6ea1SDimitry Andric static bool isConstReg(MachineRegisterInfo *MRI, SPIRVType *OpDef,
1449*0fca6ea1SDimitry Andric                        SmallPtrSet<SPIRVType *, 4> &Visited) {
1450*0fca6ea1SDimitry Andric   if (OpDef->getOpcode() == SPIRV::ASSIGN_TYPE &&
1451*0fca6ea1SDimitry Andric       OpDef->getOperand(1).isReg()) {
1452*0fca6ea1SDimitry Andric     if (SPIRVType *RefDef = MRI->getVRegDef(OpDef->getOperand(1).getReg()))
1453*0fca6ea1SDimitry Andric       OpDef = RefDef;
1454*0fca6ea1SDimitry Andric   }
1455*0fca6ea1SDimitry Andric 
1456*0fca6ea1SDimitry Andric   if (Visited.contains(OpDef))
1457*0fca6ea1SDimitry Andric     return true;
1458*0fca6ea1SDimitry Andric   Visited.insert(OpDef);
1459*0fca6ea1SDimitry Andric 
1460*0fca6ea1SDimitry Andric   unsigned Opcode = OpDef->getOpcode();
1461*0fca6ea1SDimitry Andric   switch (Opcode) {
1462*0fca6ea1SDimitry Andric   case TargetOpcode::G_CONSTANT:
1463*0fca6ea1SDimitry Andric   case TargetOpcode::G_FCONSTANT:
1464*0fca6ea1SDimitry Andric     return true;
1465*0fca6ea1SDimitry Andric   case TargetOpcode::G_INTRINSIC:
1466*0fca6ea1SDimitry Andric   case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
1467*0fca6ea1SDimitry Andric   case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
1468*0fca6ea1SDimitry Andric     return cast<GIntrinsic>(*OpDef).getIntrinsicID() ==
1469*0fca6ea1SDimitry Andric            Intrinsic::spv_const_composite;
1470*0fca6ea1SDimitry Andric   case TargetOpcode::G_BUILD_VECTOR:
1471*0fca6ea1SDimitry Andric   case TargetOpcode::G_SPLAT_VECTOR: {
1472*0fca6ea1SDimitry Andric     for (unsigned i = OpDef->getNumExplicitDefs(); i < OpDef->getNumOperands();
1473*0fca6ea1SDimitry Andric          i++) {
1474*0fca6ea1SDimitry Andric       SPIRVType *OpNestedDef =
1475*0fca6ea1SDimitry Andric           OpDef->getOperand(i).isReg()
1476*0fca6ea1SDimitry Andric               ? MRI->getVRegDef(OpDef->getOperand(i).getReg())
1477*0fca6ea1SDimitry Andric               : nullptr;
1478*0fca6ea1SDimitry Andric       if (OpNestedDef && !isConstReg(MRI, OpNestedDef, Visited))
1479*0fca6ea1SDimitry Andric         return false;
1480*0fca6ea1SDimitry Andric     }
1481*0fca6ea1SDimitry Andric     return true;
1482*0fca6ea1SDimitry Andric   }
1483*0fca6ea1SDimitry Andric   }
1484*0fca6ea1SDimitry Andric   return false;
1485*0fca6ea1SDimitry Andric }
1486*0fca6ea1SDimitry Andric 
1487*0fca6ea1SDimitry Andric // Return true if the virtual register represents a constant
1488*0fca6ea1SDimitry Andric static bool isConstReg(MachineRegisterInfo *MRI, Register OpReg) {
1489*0fca6ea1SDimitry Andric   SmallPtrSet<SPIRVType *, 4> Visited;
1490*0fca6ea1SDimitry Andric   if (SPIRVType *OpDef = MRI->getVRegDef(OpReg))
1491*0fca6ea1SDimitry Andric     return isConstReg(MRI, OpDef, Visited);
1492*0fca6ea1SDimitry Andric   return false;
1493*0fca6ea1SDimitry Andric }
1494*0fca6ea1SDimitry Andric 
1495*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg,
1496*0fca6ea1SDimitry Andric                                                  const SPIRVType *ResType,
1497*0fca6ea1SDimitry Andric                                                  MachineInstr &I) const {
1498*0fca6ea1SDimitry Andric   unsigned N = 0;
1499*0fca6ea1SDimitry Andric   if (ResType->getOpcode() == SPIRV::OpTypeVector)
1500*0fca6ea1SDimitry Andric     N = GR.getScalarOrVectorComponentCount(ResType);
1501*0fca6ea1SDimitry Andric   else if (ResType->getOpcode() == SPIRV::OpTypeArray)
1502*0fca6ea1SDimitry Andric     N = getArrayComponentCount(MRI, ResType);
1503*0fca6ea1SDimitry Andric   else
1504*0fca6ea1SDimitry Andric     report_fatal_error("Cannot select G_SPLAT_VECTOR with a non-vector result");
1505*0fca6ea1SDimitry Andric 
1506*0fca6ea1SDimitry Andric   unsigned OpIdx = I.getNumExplicitDefs();
1507*0fca6ea1SDimitry Andric   if (!I.getOperand(OpIdx).isReg())
1508*0fca6ea1SDimitry Andric     report_fatal_error("Unexpected argument in G_SPLAT_VECTOR");
1509*0fca6ea1SDimitry Andric 
1510*0fca6ea1SDimitry Andric   // check if we may construct a constant vector
1511*0fca6ea1SDimitry Andric   Register OpReg = I.getOperand(OpIdx).getReg();
1512*0fca6ea1SDimitry Andric   bool IsConst = isConstReg(MRI, OpReg);
1513*0fca6ea1SDimitry Andric 
1514*0fca6ea1SDimitry Andric   if (!IsConst && N < 2)
1515*0fca6ea1SDimitry Andric     report_fatal_error(
1516*0fca6ea1SDimitry Andric         "There must be at least two constituent operands in a vector");
1517*0fca6ea1SDimitry Andric 
1518*0fca6ea1SDimitry Andric   auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
1519*0fca6ea1SDimitry Andric                      TII.get(IsConst ? SPIRV::OpConstantComposite
1520*0fca6ea1SDimitry Andric                                      : SPIRV::OpCompositeConstruct))
1521*0fca6ea1SDimitry Andric                  .addDef(ResVReg)
1522*0fca6ea1SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType));
1523*0fca6ea1SDimitry Andric   for (unsigned i = 0; i < N; ++i)
1524*0fca6ea1SDimitry Andric     MIB.addUse(OpReg);
1525*0fca6ea1SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
1526*0fca6ea1SDimitry Andric }
1527*0fca6ea1SDimitry Andric 
152881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectCmp(Register ResVReg,
152981ad6265SDimitry Andric                                          const SPIRVType *ResType,
153081ad6265SDimitry Andric                                          unsigned CmpOpc,
153181ad6265SDimitry Andric                                          MachineInstr &I) const {
153281ad6265SDimitry Andric   Register Cmp0 = I.getOperand(2).getReg();
153381ad6265SDimitry Andric   Register Cmp1 = I.getOperand(3).getReg();
153481ad6265SDimitry Andric   assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() ==
153581ad6265SDimitry Andric              GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() &&
153681ad6265SDimitry Andric          "CMP operands should have the same type");
153781ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(CmpOpc))
153881ad6265SDimitry Andric       .addDef(ResVReg)
153981ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
154081ad6265SDimitry Andric       .addUse(Cmp0)
154181ad6265SDimitry Andric       .addUse(Cmp1)
154281ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
154381ad6265SDimitry Andric }
154481ad6265SDimitry Andric 
154581ad6265SDimitry Andric bool SPIRVInstructionSelector::selectICmp(Register ResVReg,
154681ad6265SDimitry Andric                                           const SPIRVType *ResType,
154781ad6265SDimitry Andric                                           MachineInstr &I) const {
154881ad6265SDimitry Andric   auto Pred = I.getOperand(1).getPredicate();
154981ad6265SDimitry Andric   unsigned CmpOpc;
155081ad6265SDimitry Andric 
155181ad6265SDimitry Andric   Register CmpOperand = I.getOperand(2).getReg();
155281ad6265SDimitry Andric   if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer))
155381ad6265SDimitry Andric     CmpOpc = getPtrCmpOpcode(Pred);
155481ad6265SDimitry Andric   else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool))
155581ad6265SDimitry Andric     CmpOpc = getBoolCmpOpcode(Pred);
155681ad6265SDimitry Andric   else
155781ad6265SDimitry Andric     CmpOpc = getICmpOpcode(Pred);
155881ad6265SDimitry Andric   return selectCmp(ResVReg, ResType, CmpOpc, I);
155981ad6265SDimitry Andric }
156081ad6265SDimitry Andric 
156181ad6265SDimitry Andric void SPIRVInstructionSelector::renderFImm32(MachineInstrBuilder &MIB,
156281ad6265SDimitry Andric                                             const MachineInstr &I,
156381ad6265SDimitry Andric                                             int OpIdx) const {
156481ad6265SDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
156581ad6265SDimitry Andric          "Expected G_FCONSTANT");
156681ad6265SDimitry Andric   const ConstantFP *FPImm = I.getOperand(1).getFPImm();
156781ad6265SDimitry Andric   addNumImm(FPImm->getValueAPF().bitcastToAPInt(), MIB);
156881ad6265SDimitry Andric }
156981ad6265SDimitry Andric 
157081ad6265SDimitry Andric void SPIRVInstructionSelector::renderImm32(MachineInstrBuilder &MIB,
157181ad6265SDimitry Andric                                            const MachineInstr &I,
157281ad6265SDimitry Andric                                            int OpIdx) const {
157381ad6265SDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
157481ad6265SDimitry Andric          "Expected G_CONSTANT");
157581ad6265SDimitry Andric   addNumImm(I.getOperand(1).getCImm()->getValue(), MIB);
157681ad6265SDimitry Andric }
157781ad6265SDimitry Andric 
157881ad6265SDimitry Andric Register
157981ad6265SDimitry Andric SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I,
158081ad6265SDimitry Andric                                            const SPIRVType *ResType) const {
1581753f127fSDimitry Andric   Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32);
158281ad6265SDimitry Andric   const SPIRVType *SpvI32Ty =
158381ad6265SDimitry Andric       ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII);
1584753f127fSDimitry Andric   // Find a constant in DT or build a new one.
1585753f127fSDimitry Andric   auto ConstInt = ConstantInt::get(LLVMTy, Val);
1586753f127fSDimitry Andric   Register NewReg = GR.find(ConstInt, GR.CurMF);
1587753f127fSDimitry Andric   if (!NewReg.isValid()) {
158881ad6265SDimitry Andric     NewReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
1589753f127fSDimitry Andric     GR.add(ConstInt, GR.CurMF, NewReg);
159081ad6265SDimitry Andric     MachineInstr *MI;
159181ad6265SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
159281ad6265SDimitry Andric     if (Val == 0) {
159381ad6265SDimitry Andric       MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
159481ad6265SDimitry Andric                .addDef(NewReg)
159581ad6265SDimitry Andric                .addUse(GR.getSPIRVTypeID(SpvI32Ty));
159681ad6265SDimitry Andric     } else {
159781ad6265SDimitry Andric       MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
159881ad6265SDimitry Andric                .addDef(NewReg)
159981ad6265SDimitry Andric                .addUse(GR.getSPIRVTypeID(SpvI32Ty))
160081ad6265SDimitry Andric                .addImm(APInt(32, Val).getZExtValue());
160181ad6265SDimitry Andric     }
160281ad6265SDimitry Andric     constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
1603753f127fSDimitry Andric   }
160481ad6265SDimitry Andric   return NewReg;
160581ad6265SDimitry Andric }
160681ad6265SDimitry Andric 
160781ad6265SDimitry Andric bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
160881ad6265SDimitry Andric                                           const SPIRVType *ResType,
160981ad6265SDimitry Andric                                           MachineInstr &I) const {
161081ad6265SDimitry Andric   unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate());
161181ad6265SDimitry Andric   return selectCmp(ResVReg, ResType, CmpOp, I);
161281ad6265SDimitry Andric }
161381ad6265SDimitry Andric 
161481ad6265SDimitry Andric Register SPIRVInstructionSelector::buildZerosVal(const SPIRVType *ResType,
161581ad6265SDimitry Andric                                                  MachineInstr &I) const {
1616*0fca6ea1SDimitry Andric   // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
1617*0fca6ea1SDimitry Andric   bool ZeroAsNull = STI.isOpenCLEnv();
1618fcaf7f86SDimitry Andric   if (ResType->getOpcode() == SPIRV::OpTypeVector)
1619*0fca6ea1SDimitry Andric     return GR.getOrCreateConstVector(0UL, I, ResType, TII, ZeroAsNull);
1620*0fca6ea1SDimitry Andric   return GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
1621*0fca6ea1SDimitry Andric }
1622*0fca6ea1SDimitry Andric 
1623*0fca6ea1SDimitry Andric static APFloat getZeroFP(const Type *LLVMFloatTy) {
1624*0fca6ea1SDimitry Andric   if (!LLVMFloatTy)
1625*0fca6ea1SDimitry Andric     return APFloat::getZero(APFloat::IEEEsingle());
1626*0fca6ea1SDimitry Andric   switch (LLVMFloatTy->getScalarType()->getTypeID()) {
1627*0fca6ea1SDimitry Andric   case Type::HalfTyID:
1628*0fca6ea1SDimitry Andric     return APFloat::getZero(APFloat::IEEEhalf());
1629*0fca6ea1SDimitry Andric   default:
1630*0fca6ea1SDimitry Andric   case Type::FloatTyID:
1631*0fca6ea1SDimitry Andric     return APFloat::getZero(APFloat::IEEEsingle());
1632*0fca6ea1SDimitry Andric   case Type::DoubleTyID:
1633*0fca6ea1SDimitry Andric     return APFloat::getZero(APFloat::IEEEdouble());
1634*0fca6ea1SDimitry Andric   }
1635*0fca6ea1SDimitry Andric }
1636*0fca6ea1SDimitry Andric 
1637*0fca6ea1SDimitry Andric Register SPIRVInstructionSelector::buildZerosValF(const SPIRVType *ResType,
1638*0fca6ea1SDimitry Andric                                                   MachineInstr &I) const {
1639*0fca6ea1SDimitry Andric   // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
1640*0fca6ea1SDimitry Andric   bool ZeroAsNull = STI.isOpenCLEnv();
1641*0fca6ea1SDimitry Andric   APFloat VZero = getZeroFP(GR.getTypeForSPIRVType(ResType));
1642*0fca6ea1SDimitry Andric   if (ResType->getOpcode() == SPIRV::OpTypeVector)
1643*0fca6ea1SDimitry Andric     return GR.getOrCreateConstVector(VZero, I, ResType, TII, ZeroAsNull);
1644*0fca6ea1SDimitry Andric   return GR.getOrCreateConstFP(VZero, I, ResType, TII, ZeroAsNull);
164581ad6265SDimitry Andric }
164681ad6265SDimitry Andric 
164781ad6265SDimitry Andric Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
164881ad6265SDimitry Andric                                                 const SPIRVType *ResType,
164981ad6265SDimitry Andric                                                 MachineInstr &I) const {
165081ad6265SDimitry Andric   unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
165106c3fb27SDimitry Andric   APInt One =
165206c3fb27SDimitry Andric       AllOnes ? APInt::getAllOnes(BitWidth) : APInt::getOneBitSet(BitWidth, 0);
1653fcaf7f86SDimitry Andric   if (ResType->getOpcode() == SPIRV::OpTypeVector)
1654*0fca6ea1SDimitry Andric     return GR.getOrCreateConstVector(One.getZExtValue(), I, ResType, TII);
1655fcaf7f86SDimitry Andric   return GR.getOrCreateConstInt(One.getZExtValue(), I, ResType, TII);
165681ad6265SDimitry Andric }
165781ad6265SDimitry Andric 
165881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectSelect(Register ResVReg,
165981ad6265SDimitry Andric                                             const SPIRVType *ResType,
166081ad6265SDimitry Andric                                             MachineInstr &I,
166181ad6265SDimitry Andric                                             bool IsSigned) const {
166281ad6265SDimitry Andric   // To extend a bool, we need to use OpSelect between constants.
166381ad6265SDimitry Andric   Register ZeroReg = buildZerosVal(ResType, I);
166481ad6265SDimitry Andric   Register OneReg = buildOnesVal(IsSigned, ResType, I);
166581ad6265SDimitry Andric   bool IsScalarBool =
166681ad6265SDimitry Andric       GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool);
166781ad6265SDimitry Andric   unsigned Opcode =
166881ad6265SDimitry Andric       IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectSIVCond;
166981ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
167081ad6265SDimitry Andric       .addDef(ResVReg)
167181ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
167281ad6265SDimitry Andric       .addUse(I.getOperand(1).getReg())
167381ad6265SDimitry Andric       .addUse(OneReg)
167481ad6265SDimitry Andric       .addUse(ZeroReg)
167581ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
167681ad6265SDimitry Andric }
167781ad6265SDimitry Andric 
167881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectIToF(Register ResVReg,
167981ad6265SDimitry Andric                                           const SPIRVType *ResType,
168081ad6265SDimitry Andric                                           MachineInstr &I, bool IsSigned,
168181ad6265SDimitry Andric                                           unsigned Opcode) const {
168281ad6265SDimitry Andric   Register SrcReg = I.getOperand(1).getReg();
168381ad6265SDimitry Andric   // We can convert bool value directly to float type without OpConvert*ToF,
168481ad6265SDimitry Andric   // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
168581ad6265SDimitry Andric   if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) {
168681ad6265SDimitry Andric     unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
168781ad6265SDimitry Andric     SPIRVType *TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII);
168881ad6265SDimitry Andric     if (ResType->getOpcode() == SPIRV::OpTypeVector) {
168981ad6265SDimitry Andric       const unsigned NumElts = ResType->getOperand(2).getImm();
169081ad6265SDimitry Andric       TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII);
169181ad6265SDimitry Andric     }
169281ad6265SDimitry Andric     SrcReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
169381ad6265SDimitry Andric     selectSelect(SrcReg, TmpType, I, false);
169481ad6265SDimitry Andric   }
169581ad6265SDimitry Andric   return selectUnOpWithSrc(ResVReg, ResType, I, SrcReg, Opcode);
169681ad6265SDimitry Andric }
169781ad6265SDimitry Andric 
169881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectExt(Register ResVReg,
169981ad6265SDimitry Andric                                          const SPIRVType *ResType,
170081ad6265SDimitry Andric                                          MachineInstr &I, bool IsSigned) const {
1701*0fca6ea1SDimitry Andric   Register SrcReg = I.getOperand(1).getReg();
1702*0fca6ea1SDimitry Andric   if (GR.isScalarOrVectorOfType(SrcReg, SPIRV::OpTypeBool))
170381ad6265SDimitry Andric     return selectSelect(ResVReg, ResType, I, IsSigned);
1704*0fca6ea1SDimitry Andric 
1705*0fca6ea1SDimitry Andric   SPIRVType *SrcType = GR.getSPIRVTypeForVReg(SrcReg);
1706*0fca6ea1SDimitry Andric   if (SrcType == ResType)
1707*0fca6ea1SDimitry Andric     return BuildMI(*I.getParent(), I, I.getDebugLoc(),
1708*0fca6ea1SDimitry Andric                    TII.get(TargetOpcode::COPY))
1709*0fca6ea1SDimitry Andric         .addDef(ResVReg)
1710*0fca6ea1SDimitry Andric         .addUse(SrcReg)
1711*0fca6ea1SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
1712*0fca6ea1SDimitry Andric 
171381ad6265SDimitry Andric   unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
171481ad6265SDimitry Andric   return selectUnOp(ResVReg, ResType, I, Opcode);
171581ad6265SDimitry Andric }
171681ad6265SDimitry Andric 
171781ad6265SDimitry Andric bool SPIRVInstructionSelector::selectIntToBool(Register IntReg,
171881ad6265SDimitry Andric                                                Register ResVReg,
1719bdd1243dSDimitry Andric                                                MachineInstr &I,
172081ad6265SDimitry Andric                                                const SPIRVType *IntTy,
1721bdd1243dSDimitry Andric                                                const SPIRVType *BoolTy) const {
172281ad6265SDimitry Andric   // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
172381ad6265SDimitry Andric   Register BitIntReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
172481ad6265SDimitry Andric   bool IsVectorTy = IntTy->getOpcode() == SPIRV::OpTypeVector;
172581ad6265SDimitry Andric   unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
172681ad6265SDimitry Andric   Register Zero = buildZerosVal(IntTy, I);
172781ad6265SDimitry Andric   Register One = buildOnesVal(false, IntTy, I);
172881ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
172981ad6265SDimitry Andric   BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
173081ad6265SDimitry Andric       .addDef(BitIntReg)
173181ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(IntTy))
173281ad6265SDimitry Andric       .addUse(IntReg)
173381ad6265SDimitry Andric       .addUse(One)
173481ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
173581ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
173681ad6265SDimitry Andric       .addDef(ResVReg)
173781ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(BoolTy))
173881ad6265SDimitry Andric       .addUse(BitIntReg)
173981ad6265SDimitry Andric       .addUse(Zero)
174081ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
174181ad6265SDimitry Andric }
174281ad6265SDimitry Andric 
174381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectTrunc(Register ResVReg,
174481ad6265SDimitry Andric                                            const SPIRVType *ResType,
174581ad6265SDimitry Andric                                            MachineInstr &I) const {
174681ad6265SDimitry Andric   Register IntReg = I.getOperand(1).getReg();
174781ad6265SDimitry Andric   const SPIRVType *ArgType = GR.getSPIRVTypeForVReg(IntReg);
1748*0fca6ea1SDimitry Andric   if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool))
1749bdd1243dSDimitry Andric     return selectIntToBool(IntReg, ResVReg, I, ArgType, ResType);
1750*0fca6ea1SDimitry Andric   if (ArgType == ResType)
1751*0fca6ea1SDimitry Andric     return BuildMI(*I.getParent(), I, I.getDebugLoc(),
1752*0fca6ea1SDimitry Andric                    TII.get(TargetOpcode::COPY))
1753*0fca6ea1SDimitry Andric         .addDef(ResVReg)
1754*0fca6ea1SDimitry Andric         .addUse(IntReg)
1755*0fca6ea1SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
175681ad6265SDimitry Andric   bool IsSigned = GR.isScalarOrVectorSigned(ResType);
175781ad6265SDimitry Andric   unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
175881ad6265SDimitry Andric   return selectUnOp(ResVReg, ResType, I, Opcode);
175981ad6265SDimitry Andric }
176081ad6265SDimitry Andric 
176181ad6265SDimitry Andric bool SPIRVInstructionSelector::selectConst(Register ResVReg,
176281ad6265SDimitry Andric                                            const SPIRVType *ResType,
176381ad6265SDimitry Andric                                            const APInt &Imm,
176481ad6265SDimitry Andric                                            MachineInstr &I) const {
1765fcaf7f86SDimitry Andric   unsigned TyOpcode = ResType->getOpcode();
176606c3fb27SDimitry Andric   assert(TyOpcode != SPIRV::OpTypePointer || Imm.isZero());
176781ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
1768fcaf7f86SDimitry Andric   if ((TyOpcode == SPIRV::OpTypePointer || TyOpcode == SPIRV::OpTypeEvent) &&
176906c3fb27SDimitry Andric       Imm.isZero())
177081ad6265SDimitry Andric     return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
177181ad6265SDimitry Andric         .addDef(ResVReg)
177281ad6265SDimitry Andric         .addUse(GR.getSPIRVTypeID(ResType))
177381ad6265SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
1774fcaf7f86SDimitry Andric   if (TyOpcode == SPIRV::OpTypeInt) {
177506c3fb27SDimitry Andric     assert(Imm.getBitWidth() <= 64 && "Unsupported integer width!");
1776fcaf7f86SDimitry Andric     Register Reg = GR.getOrCreateConstInt(Imm.getZExtValue(), I, ResType, TII);
1777fcaf7f86SDimitry Andric     if (Reg == ResVReg)
1778fcaf7f86SDimitry Andric       return true;
1779fcaf7f86SDimitry Andric     return BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY))
1780fcaf7f86SDimitry Andric         .addDef(ResVReg)
1781fcaf7f86SDimitry Andric         .addUse(Reg)
1782fcaf7f86SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
178381ad6265SDimitry Andric   }
178481ad6265SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
178581ad6265SDimitry Andric                  .addDef(ResVReg)
178681ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType));
178781ad6265SDimitry Andric   // <=32-bit integers should be caught by the sdag pattern.
178881ad6265SDimitry Andric   assert(Imm.getBitWidth() > 32);
178981ad6265SDimitry Andric   addNumImm(Imm, MIB);
179081ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
179181ad6265SDimitry Andric }
179281ad6265SDimitry Andric 
179381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg,
179481ad6265SDimitry Andric                                              const SPIRVType *ResType,
179581ad6265SDimitry Andric                                              MachineInstr &I) const {
179681ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
179781ad6265SDimitry Andric       .addDef(ResVReg)
179881ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
179981ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
180081ad6265SDimitry Andric }
180181ad6265SDimitry Andric 
180281ad6265SDimitry Andric static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI) {
180381ad6265SDimitry Andric   assert(MO.isReg());
180481ad6265SDimitry Andric   const SPIRVType *TypeInst = MRI->getVRegDef(MO.getReg());
1805*0fca6ea1SDimitry Andric   if (TypeInst->getOpcode() == SPIRV::ASSIGN_TYPE) {
180681ad6265SDimitry Andric     assert(TypeInst->getOperand(1).isReg());
180781ad6265SDimitry Andric     MachineInstr *ImmInst = MRI->getVRegDef(TypeInst->getOperand(1).getReg());
180881ad6265SDimitry Andric     return ImmInst->getOpcode() == TargetOpcode::G_CONSTANT;
180981ad6265SDimitry Andric   }
1810*0fca6ea1SDimitry Andric   return TypeInst->getOpcode() == SPIRV::OpConstantI;
1811*0fca6ea1SDimitry Andric }
181281ad6265SDimitry Andric 
181381ad6265SDimitry Andric static int64_t foldImm(const MachineOperand &MO, MachineRegisterInfo *MRI) {
181481ad6265SDimitry Andric   const SPIRVType *TypeInst = MRI->getVRegDef(MO.getReg());
1815*0fca6ea1SDimitry Andric   if (TypeInst->getOpcode() == SPIRV::OpConstantI)
1816*0fca6ea1SDimitry Andric     return TypeInst->getOperand(2).getImm();
181781ad6265SDimitry Andric   MachineInstr *ImmInst = MRI->getVRegDef(TypeInst->getOperand(1).getReg());
181881ad6265SDimitry Andric   assert(ImmInst->getOpcode() == TargetOpcode::G_CONSTANT);
181981ad6265SDimitry Andric   return ImmInst->getOperand(1).getCImm()->getZExtValue();
182081ad6265SDimitry Andric }
182181ad6265SDimitry Andric 
182281ad6265SDimitry Andric bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg,
182381ad6265SDimitry Andric                                                const SPIRVType *ResType,
182481ad6265SDimitry Andric                                                MachineInstr &I) const {
182581ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
1826fcaf7f86SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeInsert))
182781ad6265SDimitry Andric                  .addDef(ResVReg)
182881ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
182981ad6265SDimitry Andric                  // object to insert
183081ad6265SDimitry Andric                  .addUse(I.getOperand(3).getReg())
183181ad6265SDimitry Andric                  // composite to insert into
1832fcaf7f86SDimitry Andric                  .addUse(I.getOperand(2).getReg());
1833fcaf7f86SDimitry Andric   for (unsigned i = 4; i < I.getNumOperands(); i++)
1834fcaf7f86SDimitry Andric     MIB.addImm(foldImm(I.getOperand(i), MRI));
1835fcaf7f86SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
183681ad6265SDimitry Andric }
183781ad6265SDimitry Andric 
183881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg,
183981ad6265SDimitry Andric                                                 const SPIRVType *ResType,
184081ad6265SDimitry Andric                                                 MachineInstr &I) const {
184181ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
1842fcaf7f86SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
184381ad6265SDimitry Andric                  .addDef(ResVReg)
184481ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
1845fcaf7f86SDimitry Andric                  .addUse(I.getOperand(2).getReg());
1846fcaf7f86SDimitry Andric   for (unsigned i = 3; i < I.getNumOperands(); i++)
1847fcaf7f86SDimitry Andric     MIB.addImm(foldImm(I.getOperand(i), MRI));
1848fcaf7f86SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
184981ad6265SDimitry Andric }
185081ad6265SDimitry Andric 
185181ad6265SDimitry Andric bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg,
185281ad6265SDimitry Andric                                                const SPIRVType *ResType,
185381ad6265SDimitry Andric                                                MachineInstr &I) const {
185481ad6265SDimitry Andric   if (isImm(I.getOperand(4), MRI))
185581ad6265SDimitry Andric     return selectInsertVal(ResVReg, ResType, I);
185681ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
185781ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorInsertDynamic))
185881ad6265SDimitry Andric       .addDef(ResVReg)
185981ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
186081ad6265SDimitry Andric       .addUse(I.getOperand(2).getReg())
186181ad6265SDimitry Andric       .addUse(I.getOperand(3).getReg())
186281ad6265SDimitry Andric       .addUse(I.getOperand(4).getReg())
186381ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
186481ad6265SDimitry Andric }
186581ad6265SDimitry Andric 
186681ad6265SDimitry Andric bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg,
186781ad6265SDimitry Andric                                                 const SPIRVType *ResType,
186881ad6265SDimitry Andric                                                 MachineInstr &I) const {
186981ad6265SDimitry Andric   if (isImm(I.getOperand(3), MRI))
187081ad6265SDimitry Andric     return selectExtractVal(ResVReg, ResType, I);
187181ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
187281ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorExtractDynamic))
187381ad6265SDimitry Andric       .addDef(ResVReg)
187481ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
187581ad6265SDimitry Andric       .addUse(I.getOperand(2).getReg())
187681ad6265SDimitry Andric       .addUse(I.getOperand(3).getReg())
187781ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
187881ad6265SDimitry Andric }
187981ad6265SDimitry Andric 
188081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
188181ad6265SDimitry Andric                                          const SPIRVType *ResType,
188281ad6265SDimitry Andric                                          MachineInstr &I) const {
18835f757f3fSDimitry Andric   const bool IsGEPInBounds = I.getOperand(2).getImm();
18845f757f3fSDimitry Andric 
18855f757f3fSDimitry Andric   // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator only
18865f757f3fSDimitry Andric   // relies on PtrAccessChain, so we'll try not to deviate. For Vulkan however,
18875f757f3fSDimitry Andric   // we have to use Op[InBounds]AccessChain.
18885f757f3fSDimitry Andric   const unsigned Opcode = STI.isVulkanEnv()
18895f757f3fSDimitry Andric                               ? (IsGEPInBounds ? SPIRV::OpInBoundsAccessChain
18905f757f3fSDimitry Andric                                                : SPIRV::OpAccessChain)
18915f757f3fSDimitry Andric                               : (IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
18925f757f3fSDimitry Andric                                                : SPIRV::OpPtrAccessChain);
18935f757f3fSDimitry Andric 
189481ad6265SDimitry Andric   auto Res = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
189581ad6265SDimitry Andric                  .addDef(ResVReg)
189681ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
189781ad6265SDimitry Andric                  // Object to get a pointer to.
189881ad6265SDimitry Andric                  .addUse(I.getOperand(3).getReg());
189981ad6265SDimitry Andric   // Adding indices.
19005f757f3fSDimitry Andric   const unsigned StartingIndex =
19015f757f3fSDimitry Andric       (Opcode == SPIRV::OpAccessChain || Opcode == SPIRV::OpInBoundsAccessChain)
19025f757f3fSDimitry Andric           ? 5
19035f757f3fSDimitry Andric           : 4;
19045f757f3fSDimitry Andric   for (unsigned i = StartingIndex; i < I.getNumExplicitOperands(); ++i)
190581ad6265SDimitry Andric     Res.addUse(I.getOperand(i).getReg());
190681ad6265SDimitry Andric   return Res.constrainAllUses(TII, TRI, RBI);
190781ad6265SDimitry Andric }
190881ad6265SDimitry Andric 
1909*0fca6ea1SDimitry Andric // Maybe wrap a value into OpSpecConstantOp
1910*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
1911*0fca6ea1SDimitry Andric     MachineInstr &I, SmallVector<Register> &CompositeArgs) const {
1912*0fca6ea1SDimitry Andric   bool Result = true;
1913*0fca6ea1SDimitry Andric   unsigned Lim = I.getNumExplicitOperands();
1914*0fca6ea1SDimitry Andric   for (unsigned i = I.getNumExplicitDefs() + 1; i < Lim; ++i) {
1915*0fca6ea1SDimitry Andric     Register OpReg = I.getOperand(i).getReg();
1916*0fca6ea1SDimitry Andric     SPIRVType *OpDefine = MRI->getVRegDef(OpReg);
1917*0fca6ea1SDimitry Andric     SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpReg);
1918*0fca6ea1SDimitry Andric     SmallPtrSet<SPIRVType *, 4> Visited;
1919*0fca6ea1SDimitry Andric     if (!OpDefine || !OpType || isConstReg(MRI, OpDefine, Visited) ||
1920*0fca6ea1SDimitry Andric         OpDefine->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
1921*0fca6ea1SDimitry Andric         GR.isAggregateType(OpType)) {
1922*0fca6ea1SDimitry Andric       // The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed
1923*0fca6ea1SDimitry Andric       // by selectAddrSpaceCast()
1924*0fca6ea1SDimitry Andric       CompositeArgs.push_back(OpReg);
1925*0fca6ea1SDimitry Andric       continue;
1926*0fca6ea1SDimitry Andric     }
1927*0fca6ea1SDimitry Andric     MachineFunction *MF = I.getMF();
1928*0fca6ea1SDimitry Andric     Register WrapReg = GR.find(OpDefine, MF);
1929*0fca6ea1SDimitry Andric     if (WrapReg.isValid()) {
1930*0fca6ea1SDimitry Andric       CompositeArgs.push_back(WrapReg);
1931*0fca6ea1SDimitry Andric       continue;
1932*0fca6ea1SDimitry Andric     }
1933*0fca6ea1SDimitry Andric     // Create a new register for the wrapper
1934*0fca6ea1SDimitry Andric     WrapReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
1935*0fca6ea1SDimitry Andric     GR.add(OpDefine, MF, WrapReg);
1936*0fca6ea1SDimitry Andric     CompositeArgs.push_back(WrapReg);
1937*0fca6ea1SDimitry Andric     // Decorate the wrapper register and generate a new instruction
1938*0fca6ea1SDimitry Andric     MRI->setType(WrapReg, LLT::pointer(0, 32));
1939*0fca6ea1SDimitry Andric     GR.assignSPIRVTypeToVReg(OpType, WrapReg, *MF);
1940*0fca6ea1SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
1941*0fca6ea1SDimitry Andric     Result = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
1942*0fca6ea1SDimitry Andric                  .addDef(WrapReg)
1943*0fca6ea1SDimitry Andric                  .addUse(GR.getSPIRVTypeID(OpType))
1944*0fca6ea1SDimitry Andric                  .addImm(static_cast<uint32_t>(SPIRV::Opcode::Bitcast))
1945*0fca6ea1SDimitry Andric                  .addUse(OpReg)
1946*0fca6ea1SDimitry Andric                  .constrainAllUses(TII, TRI, RBI);
1947*0fca6ea1SDimitry Andric     if (!Result)
1948*0fca6ea1SDimitry Andric       break;
1949*0fca6ea1SDimitry Andric   }
1950*0fca6ea1SDimitry Andric   return Result;
1951*0fca6ea1SDimitry Andric }
1952*0fca6ea1SDimitry Andric 
195381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
195481ad6265SDimitry Andric                                                const SPIRVType *ResType,
195581ad6265SDimitry Andric                                                MachineInstr &I) const {
195681ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
1957*0fca6ea1SDimitry Andric   Intrinsic::ID IID = cast<GIntrinsic>(I).getIntrinsicID();
1958*0fca6ea1SDimitry Andric   switch (IID) {
195981ad6265SDimitry Andric   case Intrinsic::spv_load:
196081ad6265SDimitry Andric     return selectLoad(ResVReg, ResType, I);
196181ad6265SDimitry Andric   case Intrinsic::spv_store:
196281ad6265SDimitry Andric     return selectStore(I);
196381ad6265SDimitry Andric   case Intrinsic::spv_extractv:
196481ad6265SDimitry Andric     return selectExtractVal(ResVReg, ResType, I);
196581ad6265SDimitry Andric   case Intrinsic::spv_insertv:
196681ad6265SDimitry Andric     return selectInsertVal(ResVReg, ResType, I);
196781ad6265SDimitry Andric   case Intrinsic::spv_extractelt:
196881ad6265SDimitry Andric     return selectExtractElt(ResVReg, ResType, I);
196981ad6265SDimitry Andric   case Intrinsic::spv_insertelt:
197081ad6265SDimitry Andric     return selectInsertElt(ResVReg, ResType, I);
197181ad6265SDimitry Andric   case Intrinsic::spv_gep:
197281ad6265SDimitry Andric     return selectGEP(ResVReg, ResType, I);
197381ad6265SDimitry Andric   case Intrinsic::spv_unref_global:
197481ad6265SDimitry Andric   case Intrinsic::spv_init_global: {
197581ad6265SDimitry Andric     MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());
197681ad6265SDimitry Andric     MachineInstr *Init = I.getNumExplicitOperands() > 2
197781ad6265SDimitry Andric                              ? MRI->getVRegDef(I.getOperand(2).getReg())
197881ad6265SDimitry Andric                              : nullptr;
197981ad6265SDimitry Andric     assert(MI);
198081ad6265SDimitry Andric     return selectGlobalValue(MI->getOperand(0).getReg(), *MI, Init);
198106c3fb27SDimitry Andric   }
198206c3fb27SDimitry Andric   case Intrinsic::spv_undef: {
198306c3fb27SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
198406c3fb27SDimitry Andric                    .addDef(ResVReg)
198506c3fb27SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType));
198606c3fb27SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
198706c3fb27SDimitry Andric   }
198881ad6265SDimitry Andric   case Intrinsic::spv_const_composite: {
198981ad6265SDimitry Andric     // If no values are attached, the composite is null constant.
199081ad6265SDimitry Andric     bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
1991*0fca6ea1SDimitry Andric     // Select a proper instruction.
1992*0fca6ea1SDimitry Andric     unsigned Opcode = SPIRV::OpConstantNull;
1993*0fca6ea1SDimitry Andric     SmallVector<Register> CompositeArgs;
1994*0fca6ea1SDimitry Andric     if (!IsNull) {
1995*0fca6ea1SDimitry Andric       Opcode = SPIRV::OpConstantComposite;
1996*0fca6ea1SDimitry Andric       if (!wrapIntoSpecConstantOp(I, CompositeArgs))
1997*0fca6ea1SDimitry Andric         return false;
1998*0fca6ea1SDimitry Andric     }
199981ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
200081ad6265SDimitry Andric                    .addDef(ResVReg)
200181ad6265SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType));
200281ad6265SDimitry Andric     // skip type MD node we already used when generated assign.type for this
200381ad6265SDimitry Andric     if (!IsNull) {
2004*0fca6ea1SDimitry Andric       for (Register OpReg : CompositeArgs)
2005*0fca6ea1SDimitry Andric         MIB.addUse(OpReg);
200681ad6265SDimitry Andric     }
200781ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
200806c3fb27SDimitry Andric   }
200981ad6265SDimitry Andric   case Intrinsic::spv_assign_name: {
201081ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName));
201181ad6265SDimitry Andric     MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg());
201281ad6265SDimitry Andric     for (unsigned i = I.getNumExplicitDefs() + 2;
201381ad6265SDimitry Andric          i < I.getNumExplicitOperands(); ++i) {
201481ad6265SDimitry Andric       MIB.addImm(I.getOperand(i).getImm());
201581ad6265SDimitry Andric     }
201681ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
201706c3fb27SDimitry Andric   }
201881ad6265SDimitry Andric   case Intrinsic::spv_switch: {
201981ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch));
202081ad6265SDimitry Andric     for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
202181ad6265SDimitry Andric       if (I.getOperand(i).isReg())
202281ad6265SDimitry Andric         MIB.addReg(I.getOperand(i).getReg());
202381ad6265SDimitry Andric       else if (I.getOperand(i).isCImm())
202481ad6265SDimitry Andric         addNumImm(I.getOperand(i).getCImm()->getValue(), MIB);
202581ad6265SDimitry Andric       else if (I.getOperand(i).isMBB())
202681ad6265SDimitry Andric         MIB.addMBB(I.getOperand(i).getMBB());
202781ad6265SDimitry Andric       else
202881ad6265SDimitry Andric         llvm_unreachable("Unexpected OpSwitch operand");
202981ad6265SDimitry Andric     }
203081ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
203106c3fb27SDimitry Andric   }
2032fcaf7f86SDimitry Andric   case Intrinsic::spv_cmpxchg:
2033fcaf7f86SDimitry Andric     return selectAtomicCmpXchg(ResVReg, ResType, I);
2034bdd1243dSDimitry Andric   case Intrinsic::spv_unreachable:
2035bdd1243dSDimitry Andric     BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUnreachable));
2036bdd1243dSDimitry Andric     break;
2037bdd1243dSDimitry Andric   case Intrinsic::spv_alloca:
2038bdd1243dSDimitry Andric     return selectFrameIndex(ResVReg, ResType, I);
2039*0fca6ea1SDimitry Andric   case Intrinsic::spv_alloca_array:
2040*0fca6ea1SDimitry Andric     return selectAllocaArray(ResVReg, ResType, I);
20415f757f3fSDimitry Andric   case Intrinsic::spv_assume:
20425f757f3fSDimitry Andric     if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))
20435f757f3fSDimitry Andric       BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAssumeTrueKHR))
20445f757f3fSDimitry Andric           .addUse(I.getOperand(1).getReg());
20455f757f3fSDimitry Andric     break;
20465f757f3fSDimitry Andric   case Intrinsic::spv_expect:
20475f757f3fSDimitry Andric     if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))
20485f757f3fSDimitry Andric       BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExpectKHR))
20495f757f3fSDimitry Andric           .addDef(ResVReg)
20505f757f3fSDimitry Andric           .addUse(GR.getSPIRVTypeID(ResType))
20515f757f3fSDimitry Andric           .addUse(I.getOperand(2).getReg())
20525f757f3fSDimitry Andric           .addUse(I.getOperand(3).getReg());
20535f757f3fSDimitry Andric     break;
2054*0fca6ea1SDimitry Andric   case Intrinsic::spv_thread_id:
2055*0fca6ea1SDimitry Andric     return selectSpvThreadId(ResVReg, ResType, I);
2056*0fca6ea1SDimitry Andric   case Intrinsic::spv_all:
2057*0fca6ea1SDimitry Andric     return selectAll(ResVReg, ResType, I);
2058*0fca6ea1SDimitry Andric   case Intrinsic::spv_any:
2059*0fca6ea1SDimitry Andric     return selectAny(ResVReg, ResType, I);
2060*0fca6ea1SDimitry Andric   case Intrinsic::spv_lerp:
2061*0fca6ea1SDimitry Andric     return selectFmix(ResVReg, ResType, I);
2062*0fca6ea1SDimitry Andric   case Intrinsic::spv_rsqrt:
2063*0fca6ea1SDimitry Andric     return selectRsqrt(ResVReg, ResType, I);
2064*0fca6ea1SDimitry Andric   case Intrinsic::spv_lifetime_start:
2065*0fca6ea1SDimitry Andric   case Intrinsic::spv_lifetime_end: {
2066*0fca6ea1SDimitry Andric     unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
2067*0fca6ea1SDimitry Andric                                                        : SPIRV::OpLifetimeStop;
2068*0fca6ea1SDimitry Andric     int64_t Size = I.getOperand(I.getNumExplicitDefs() + 1).getImm();
2069*0fca6ea1SDimitry Andric     Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 2).getReg();
2070*0fca6ea1SDimitry Andric     unsigned PonteeOpType = GR.getPointeeTypeOp(PtrReg);
2071*0fca6ea1SDimitry Andric     bool IsNonvoidPtr = PonteeOpType != 0 && PonteeOpType != SPIRV::OpTypeVoid;
2072*0fca6ea1SDimitry Andric     if (Size == -1 || IsNonvoidPtr)
2073*0fca6ea1SDimitry Andric       Size = 0;
2074*0fca6ea1SDimitry Andric     BuildMI(BB, I, I.getDebugLoc(), TII.get(Op)).addUse(PtrReg).addImm(Size);
2075*0fca6ea1SDimitry Andric   } break;
2076*0fca6ea1SDimitry Andric   default: {
2077*0fca6ea1SDimitry Andric     std::string DiagMsg;
2078*0fca6ea1SDimitry Andric     raw_string_ostream OS(DiagMsg);
2079*0fca6ea1SDimitry Andric     I.print(OS);
2080*0fca6ea1SDimitry Andric     DiagMsg = "Intrinsic selection not implemented: " + DiagMsg;
2081*0fca6ea1SDimitry Andric     report_fatal_error(DiagMsg.c_str(), false);
2082*0fca6ea1SDimitry Andric   }
208381ad6265SDimitry Andric   }
208481ad6265SDimitry Andric   return true;
208581ad6265SDimitry Andric }
208681ad6265SDimitry Andric 
2087*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg,
2088*0fca6ea1SDimitry Andric                                                  const SPIRVType *ResType,
2089*0fca6ea1SDimitry Andric                                                  MachineInstr &I) const {
2090*0fca6ea1SDimitry Andric   // there was an allocation size parameter to the allocation instruction
2091*0fca6ea1SDimitry Andric   // that is not 1
2092*0fca6ea1SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
2093*0fca6ea1SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(),
2094*0fca6ea1SDimitry Andric                  TII.get(SPIRV::OpVariableLengthArrayINTEL))
2095*0fca6ea1SDimitry Andric       .addDef(ResVReg)
2096*0fca6ea1SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
2097*0fca6ea1SDimitry Andric       .addUse(I.getOperand(2).getReg())
2098*0fca6ea1SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
2099*0fca6ea1SDimitry Andric }
2100*0fca6ea1SDimitry Andric 
210181ad6265SDimitry Andric bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg,
210281ad6265SDimitry Andric                                                 const SPIRVType *ResType,
210381ad6265SDimitry Andric                                                 MachineInstr &I) const {
2104*0fca6ea1SDimitry Andric   // Change order of instructions if needed: all OpVariable instructions in a
2105*0fca6ea1SDimitry Andric   // function must be the first instructions in the first block
2106*0fca6ea1SDimitry Andric   MachineFunction *MF = I.getParent()->getParent();
2107*0fca6ea1SDimitry Andric   MachineBasicBlock *MBB = &MF->front();
2108*0fca6ea1SDimitry Andric   auto It = MBB->SkipPHIsAndLabels(MBB->begin()), E = MBB->end();
2109*0fca6ea1SDimitry Andric   bool IsHeader = false;
2110*0fca6ea1SDimitry Andric   unsigned Opcode;
2111*0fca6ea1SDimitry Andric   for (; It != E && It != I; ++It) {
2112*0fca6ea1SDimitry Andric     Opcode = It->getOpcode();
2113*0fca6ea1SDimitry Andric     if (Opcode == SPIRV::OpFunction || Opcode == SPIRV::OpFunctionParameter) {
2114*0fca6ea1SDimitry Andric       IsHeader = true;
2115*0fca6ea1SDimitry Andric     } else if (IsHeader &&
2116*0fca6ea1SDimitry Andric                !(Opcode == SPIRV::ASSIGN_TYPE || Opcode == SPIRV::OpLabel)) {
2117*0fca6ea1SDimitry Andric       ++It;
2118*0fca6ea1SDimitry Andric       break;
2119*0fca6ea1SDimitry Andric     }
2120*0fca6ea1SDimitry Andric   }
2121*0fca6ea1SDimitry Andric   return BuildMI(*MBB, It, It->getDebugLoc(), TII.get(SPIRV::OpVariable))
212281ad6265SDimitry Andric       .addDef(ResVReg)
212381ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
212481ad6265SDimitry Andric       .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
212581ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
212681ad6265SDimitry Andric }
212781ad6265SDimitry Andric 
212881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const {
212981ad6265SDimitry Andric   // InstructionSelector walks backwards through the instructions. We can use
213081ad6265SDimitry Andric   // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
213181ad6265SDimitry Andric   // first, so can generate an OpBranchConditional here. If there is no
213281ad6265SDimitry Andric   // G_BRCOND, we just use OpBranch for a regular unconditional branch.
213381ad6265SDimitry Andric   const MachineInstr *PrevI = I.getPrevNode();
213481ad6265SDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
213581ad6265SDimitry Andric   if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) {
213681ad6265SDimitry Andric     return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
213781ad6265SDimitry Andric         .addUse(PrevI->getOperand(0).getReg())
213881ad6265SDimitry Andric         .addMBB(PrevI->getOperand(1).getMBB())
213981ad6265SDimitry Andric         .addMBB(I.getOperand(0).getMBB())
214081ad6265SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
214181ad6265SDimitry Andric   }
214281ad6265SDimitry Andric   return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch))
214381ad6265SDimitry Andric       .addMBB(I.getOperand(0).getMBB())
214481ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
214581ad6265SDimitry Andric }
214681ad6265SDimitry Andric 
214781ad6265SDimitry Andric bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const {
214881ad6265SDimitry Andric   // InstructionSelector walks backwards through the instructions. For an
214981ad6265SDimitry Andric   // explicit conditional branch with no fallthrough, we use both a G_BR and a
215081ad6265SDimitry Andric   // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
215181ad6265SDimitry Andric   // generate the OpBranchConditional in selectBranch above.
215281ad6265SDimitry Andric   //
215381ad6265SDimitry Andric   // If an OpBranchConditional has been generated, we simply return, as the work
215481ad6265SDimitry Andric   // is alread done. If there is no OpBranchConditional, LLVM must be relying on
215581ad6265SDimitry Andric   // implicit fallthrough to the next basic block, so we need to create an
215681ad6265SDimitry Andric   // OpBranchConditional with an explicit "false" argument pointing to the next
215781ad6265SDimitry Andric   // basic block that LLVM would fall through to.
215881ad6265SDimitry Andric   const MachineInstr *NextI = I.getNextNode();
215981ad6265SDimitry Andric   // Check if this has already been successfully selected.
216081ad6265SDimitry Andric   if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional)
216181ad6265SDimitry Andric     return true;
216281ad6265SDimitry Andric   // Must be relying on implicit block fallthrough, so generate an
216381ad6265SDimitry Andric   // OpBranchConditional with the "next" basic block as the "false" target.
216481ad6265SDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
216581ad6265SDimitry Andric   unsigned NextMBBNum = MBB.getNextNode()->getNumber();
216681ad6265SDimitry Andric   MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum);
216781ad6265SDimitry Andric   return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
216881ad6265SDimitry Andric       .addUse(I.getOperand(0).getReg())
216981ad6265SDimitry Andric       .addMBB(I.getOperand(1).getMBB())
217081ad6265SDimitry Andric       .addMBB(NextMBB)
217181ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
217281ad6265SDimitry Andric }
217381ad6265SDimitry Andric 
217481ad6265SDimitry Andric bool SPIRVInstructionSelector::selectPhi(Register ResVReg,
217581ad6265SDimitry Andric                                          const SPIRVType *ResType,
217681ad6265SDimitry Andric                                          MachineInstr &I) const {
217781ad6265SDimitry Andric   auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpPhi))
217881ad6265SDimitry Andric                  .addDef(ResVReg)
217981ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType));
218081ad6265SDimitry Andric   const unsigned NumOps = I.getNumOperands();
218181ad6265SDimitry Andric   for (unsigned i = 1; i < NumOps; i += 2) {
218281ad6265SDimitry Andric     MIB.addUse(I.getOperand(i + 0).getReg());
218381ad6265SDimitry Andric     MIB.addMBB(I.getOperand(i + 1).getMBB());
218481ad6265SDimitry Andric   }
218581ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
218681ad6265SDimitry Andric }
218781ad6265SDimitry Andric 
218881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectGlobalValue(
218981ad6265SDimitry Andric     Register ResVReg, MachineInstr &I, const MachineInstr *Init) const {
219081ad6265SDimitry Andric   // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
219181ad6265SDimitry Andric   MachineIRBuilder MIRBuilder(I);
219281ad6265SDimitry Andric   const GlobalValue *GV = I.getOperand(1).getGlobal();
2193*0fca6ea1SDimitry Andric   Type *GVType = toTypedPointer(GR.getDeducedGlobalValueType(GV));
21945f757f3fSDimitry Andric   SPIRVType *PointerBaseType;
21955f757f3fSDimitry Andric   if (GVType->isArrayTy()) {
21965f757f3fSDimitry Andric     SPIRVType *ArrayElementType =
21975f757f3fSDimitry Andric         GR.getOrCreateSPIRVType(GVType->getArrayElementType(), MIRBuilder,
21985f757f3fSDimitry Andric                                 SPIRV::AccessQualifier::ReadWrite, false);
21995f757f3fSDimitry Andric     PointerBaseType = GR.getOrCreateSPIRVArrayType(
22005f757f3fSDimitry Andric         ArrayElementType, GVType->getArrayNumElements(), I, TII);
22015f757f3fSDimitry Andric   } else {
22025f757f3fSDimitry Andric     PointerBaseType = GR.getOrCreateSPIRVType(
22035f757f3fSDimitry Andric         GVType, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false);
22045f757f3fSDimitry Andric   }
22055f757f3fSDimitry Andric   SPIRVType *ResType = GR.getOrCreateSPIRVPointerType(
22065f757f3fSDimitry Andric       PointerBaseType, I, TII,
2207*0fca6ea1SDimitry Andric       addressSpaceToStorageClass(GV->getAddressSpace(), STI));
2208*0fca6ea1SDimitry Andric 
2209*0fca6ea1SDimitry Andric   std::string GlobalIdent;
2210*0fca6ea1SDimitry Andric   if (!GV->hasName()) {
2211*0fca6ea1SDimitry Andric     unsigned &ID = UnnamedGlobalIDs[GV];
2212*0fca6ea1SDimitry Andric     if (ID == 0)
2213*0fca6ea1SDimitry Andric       ID = UnnamedGlobalIDs.size();
2214*0fca6ea1SDimitry Andric     GlobalIdent = "__unnamed_" + Twine(ID).str();
2215*0fca6ea1SDimitry Andric   } else {
2216*0fca6ea1SDimitry Andric     GlobalIdent = GV->getGlobalIdentifier();
2217*0fca6ea1SDimitry Andric   }
2218*0fca6ea1SDimitry Andric 
2219*0fca6ea1SDimitry Andric   // Behaviour of functions as operands depends on availability of the
2220*0fca6ea1SDimitry Andric   // corresponding extension (SPV_INTEL_function_pointers):
2221*0fca6ea1SDimitry Andric   // - If there is an extension to operate with functions as operands:
2222*0fca6ea1SDimitry Andric   // We create a proper constant operand and evaluate a correct type for a
2223*0fca6ea1SDimitry Andric   // function pointer.
2224*0fca6ea1SDimitry Andric   // - Without the required extension:
2225fcaf7f86SDimitry Andric   // We have functions as operands in tests with blocks of instruction e.g. in
2226fcaf7f86SDimitry Andric   // transcoding/global_block.ll. These operands are not used and should be
2227fcaf7f86SDimitry Andric   // substituted by zero constants. Their type is expected to be always
2228fcaf7f86SDimitry Andric   // OpTypePointer Function %uchar.
2229fcaf7f86SDimitry Andric   if (isa<Function>(GV)) {
2230fcaf7f86SDimitry Andric     const Constant *ConstVal = GV;
2231fcaf7f86SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
2232fcaf7f86SDimitry Andric     Register NewReg = GR.find(ConstVal, GR.CurMF);
2233fcaf7f86SDimitry Andric     if (!NewReg.isValid()) {
2234fcaf7f86SDimitry Andric       Register NewReg = ResVReg;
2235fcaf7f86SDimitry Andric       GR.add(ConstVal, GR.CurMF, NewReg);
2236*0fca6ea1SDimitry Andric       const Function *GVFun =
2237*0fca6ea1SDimitry Andric           STI.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
2238*0fca6ea1SDimitry Andric               ? dyn_cast<Function>(GV)
2239*0fca6ea1SDimitry Andric               : nullptr;
2240*0fca6ea1SDimitry Andric       if (GVFun) {
2241*0fca6ea1SDimitry Andric         // References to a function via function pointers generate virtual
2242*0fca6ea1SDimitry Andric         // registers without a definition. We will resolve it later, during
2243*0fca6ea1SDimitry Andric         // module analysis stage.
2244*0fca6ea1SDimitry Andric         MachineRegisterInfo *MRI = MIRBuilder.getMRI();
2245*0fca6ea1SDimitry Andric         Register FuncVReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
2246*0fca6ea1SDimitry Andric         MRI->setRegClass(FuncVReg, &SPIRV::IDRegClass);
2247*0fca6ea1SDimitry Andric         MachineInstrBuilder MB =
2248*0fca6ea1SDimitry Andric             BuildMI(BB, I, I.getDebugLoc(),
2249*0fca6ea1SDimitry Andric                     TII.get(SPIRV::OpConstantFunctionPointerINTEL))
2250*0fca6ea1SDimitry Andric                 .addDef(NewReg)
2251*0fca6ea1SDimitry Andric                 .addUse(GR.getSPIRVTypeID(ResType))
2252*0fca6ea1SDimitry Andric                 .addUse(FuncVReg);
2253*0fca6ea1SDimitry Andric         // mapping the function pointer to the used Function
2254*0fca6ea1SDimitry Andric         GR.recordFunctionPointer(&MB.getInstr()->getOperand(2), GVFun);
2255*0fca6ea1SDimitry Andric         return MB.constrainAllUses(TII, TRI, RBI);
2256*0fca6ea1SDimitry Andric       }
2257fcaf7f86SDimitry Andric       return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
2258fcaf7f86SDimitry Andric           .addDef(NewReg)
2259fcaf7f86SDimitry Andric           .addUse(GR.getSPIRVTypeID(ResType))
2260fcaf7f86SDimitry Andric           .constrainAllUses(TII, TRI, RBI);
2261fcaf7f86SDimitry Andric     }
2262fcaf7f86SDimitry Andric     assert(NewReg != ResVReg);
2263fcaf7f86SDimitry Andric     return BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY))
2264fcaf7f86SDimitry Andric         .addDef(ResVReg)
2265fcaf7f86SDimitry Andric         .addUse(NewReg)
2266fcaf7f86SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
2267fcaf7f86SDimitry Andric   }
226881ad6265SDimitry Andric   auto GlobalVar = cast<GlobalVariable>(GV);
2269fcaf7f86SDimitry Andric   assert(GlobalVar->getName() != "llvm.global.annotations");
227081ad6265SDimitry Andric 
227181ad6265SDimitry Andric   bool HasInit = GlobalVar->hasInitializer() &&
227281ad6265SDimitry Andric                  !isa<UndefValue>(GlobalVar->getInitializer());
227381ad6265SDimitry Andric   // Skip empty declaration for GVs with initilaizers till we get the decl with
227481ad6265SDimitry Andric   // passed initializer.
227581ad6265SDimitry Andric   if (HasInit && !Init)
227681ad6265SDimitry Andric     return true;
227781ad6265SDimitry Andric 
227881ad6265SDimitry Andric   unsigned AddrSpace = GV->getAddressSpace();
2279bdd1243dSDimitry Andric   SPIRV::StorageClass::StorageClass Storage =
2280*0fca6ea1SDimitry Andric       addressSpaceToStorageClass(AddrSpace, STI);
228181ad6265SDimitry Andric   bool HasLnkTy = GV->getLinkage() != GlobalValue::InternalLinkage &&
228281ad6265SDimitry Andric                   Storage != SPIRV::StorageClass::Function;
2283bdd1243dSDimitry Andric   SPIRV::LinkageType::LinkageType LnkType =
228481ad6265SDimitry Andric       (GV->isDeclaration() || GV->hasAvailableExternallyLinkage())
228581ad6265SDimitry Andric           ? SPIRV::LinkageType::Import
2286*0fca6ea1SDimitry Andric           : (GV->getLinkage() == GlobalValue::LinkOnceODRLinkage &&
2287*0fca6ea1SDimitry Andric                      STI.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr)
2288*0fca6ea1SDimitry Andric                  ? SPIRV::LinkageType::LinkOnceODR
2289*0fca6ea1SDimitry Andric                  : SPIRV::LinkageType::Export);
229081ad6265SDimitry Andric 
229181ad6265SDimitry Andric   Register Reg = GR.buildGlobalVariable(ResVReg, ResType, GlobalIdent, GV,
229281ad6265SDimitry Andric                                         Storage, Init, GlobalVar->isConstant(),
229381ad6265SDimitry Andric                                         HasLnkTy, LnkType, MIRBuilder, true);
229481ad6265SDimitry Andric   return Reg.isValid();
229581ad6265SDimitry Andric }
229681ad6265SDimitry Andric 
22975f757f3fSDimitry Andric bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
22985f757f3fSDimitry Andric                                            const SPIRVType *ResType,
22995f757f3fSDimitry Andric                                            MachineInstr &I) const {
23005f757f3fSDimitry Andric   if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
23015f757f3fSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::log10);
23025f757f3fSDimitry Andric   }
23035f757f3fSDimitry Andric 
23045f757f3fSDimitry Andric   // There is no log10 instruction in the GLSL Extended Instruction set, so it
23055f757f3fSDimitry Andric   // is implemented as:
23065f757f3fSDimitry Andric   // log10(x) = log2(x) * (1 / log2(10))
23075f757f3fSDimitry Andric   //          = log2(x) * 0.30103
23085f757f3fSDimitry Andric 
23095f757f3fSDimitry Andric   MachineIRBuilder MIRBuilder(I);
23105f757f3fSDimitry Andric   MachineBasicBlock &BB = *I.getParent();
23115f757f3fSDimitry Andric 
23125f757f3fSDimitry Andric   // Build log2(x).
23135f757f3fSDimitry Andric   Register VarReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
23145f757f3fSDimitry Andric   bool Result =
23155f757f3fSDimitry Andric       BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
23165f757f3fSDimitry Andric           .addDef(VarReg)
23175f757f3fSDimitry Andric           .addUse(GR.getSPIRVTypeID(ResType))
23185f757f3fSDimitry Andric           .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
23195f757f3fSDimitry Andric           .addImm(GL::Log2)
23205f757f3fSDimitry Andric           .add(I.getOperand(1))
23215f757f3fSDimitry Andric           .constrainAllUses(TII, TRI, RBI);
23225f757f3fSDimitry Andric 
23235f757f3fSDimitry Andric   // Build 0.30103.
23245f757f3fSDimitry Andric   assert(ResType->getOpcode() == SPIRV::OpTypeVector ||
23255f757f3fSDimitry Andric          ResType->getOpcode() == SPIRV::OpTypeFloat);
23265f757f3fSDimitry Andric   // TODO: Add matrix implementation once supported by the HLSL frontend.
23275f757f3fSDimitry Andric   const SPIRVType *SpirvScalarType =
23285f757f3fSDimitry Andric       ResType->getOpcode() == SPIRV::OpTypeVector
23295f757f3fSDimitry Andric           ? GR.getSPIRVTypeForVReg(ResType->getOperand(1).getReg())
23305f757f3fSDimitry Andric           : ResType;
23315f757f3fSDimitry Andric   Register ScaleReg =
23325f757f3fSDimitry Andric       GR.buildConstantFP(APFloat(0.30103f), MIRBuilder, SpirvScalarType);
23335f757f3fSDimitry Andric 
23345f757f3fSDimitry Andric   // Multiply log2(x) by 0.30103 to get log10(x) result.
23355f757f3fSDimitry Andric   auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector
23365f757f3fSDimitry Andric                     ? SPIRV::OpVectorTimesScalar
23375f757f3fSDimitry Andric                     : SPIRV::OpFMulS;
23385f757f3fSDimitry Andric   Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
23395f757f3fSDimitry Andric                 .addDef(ResVReg)
23405f757f3fSDimitry Andric                 .addUse(GR.getSPIRVTypeID(ResType))
23415f757f3fSDimitry Andric                 .addUse(VarReg)
23425f757f3fSDimitry Andric                 .addUse(ScaleReg)
23435f757f3fSDimitry Andric                 .constrainAllUses(TII, TRI, RBI);
23445f757f3fSDimitry Andric 
23455f757f3fSDimitry Andric   return Result;
23465f757f3fSDimitry Andric }
23475f757f3fSDimitry Andric 
2348*0fca6ea1SDimitry Andric bool SPIRVInstructionSelector::selectSpvThreadId(Register ResVReg,
2349*0fca6ea1SDimitry Andric                                                  const SPIRVType *ResType,
2350*0fca6ea1SDimitry Andric                                                  MachineInstr &I) const {
2351*0fca6ea1SDimitry Andric   // DX intrinsic: @llvm.dx.thread.id(i32)
2352*0fca6ea1SDimitry Andric   // ID  Name      Description
2353*0fca6ea1SDimitry Andric   // 93  ThreadId  reads the thread ID
2354*0fca6ea1SDimitry Andric 
2355*0fca6ea1SDimitry Andric   MachineIRBuilder MIRBuilder(I);
2356*0fca6ea1SDimitry Andric   const SPIRVType *U32Type = GR.getOrCreateSPIRVIntegerType(32, MIRBuilder);
2357*0fca6ea1SDimitry Andric   const SPIRVType *Vec3Ty =
2358*0fca6ea1SDimitry Andric       GR.getOrCreateSPIRVVectorType(U32Type, 3, MIRBuilder);
2359*0fca6ea1SDimitry Andric   const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType(
2360*0fca6ea1SDimitry Andric       Vec3Ty, MIRBuilder, SPIRV::StorageClass::Input);
2361*0fca6ea1SDimitry Andric 
2362*0fca6ea1SDimitry Andric   // Create new register for GlobalInvocationID builtin variable.
2363*0fca6ea1SDimitry Andric   Register NewRegister =
2364*0fca6ea1SDimitry Andric       MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::IDRegClass);
2365*0fca6ea1SDimitry Andric   MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 32));
2366*0fca6ea1SDimitry Andric   GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
2367*0fca6ea1SDimitry Andric 
2368*0fca6ea1SDimitry Andric   // Build GlobalInvocationID global variable with the necessary decorations.
2369*0fca6ea1SDimitry Andric   Register Variable = GR.buildGlobalVariable(
2370*0fca6ea1SDimitry Andric       NewRegister, PtrType,
2371*0fca6ea1SDimitry Andric       getLinkStringForBuiltIn(SPIRV::BuiltIn::GlobalInvocationId), nullptr,
2372*0fca6ea1SDimitry Andric       SPIRV::StorageClass::Input, nullptr, true, true,
2373*0fca6ea1SDimitry Andric       SPIRV::LinkageType::Import, MIRBuilder, false);
2374*0fca6ea1SDimitry Andric 
2375*0fca6ea1SDimitry Andric   // Create new register for loading value.
2376*0fca6ea1SDimitry Andric   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
2377*0fca6ea1SDimitry Andric   Register LoadedRegister = MRI->createVirtualRegister(&SPIRV::IDRegClass);
2378*0fca6ea1SDimitry Andric   MIRBuilder.getMRI()->setType(LoadedRegister, LLT::pointer(0, 32));
2379*0fca6ea1SDimitry Andric   GR.assignSPIRVTypeToVReg(Vec3Ty, LoadedRegister, MIRBuilder.getMF());
2380*0fca6ea1SDimitry Andric 
2381*0fca6ea1SDimitry Andric   // Load v3uint value from the global variable.
2382*0fca6ea1SDimitry Andric   BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
2383*0fca6ea1SDimitry Andric       .addDef(LoadedRegister)
2384*0fca6ea1SDimitry Andric       .addUse(GR.getSPIRVTypeID(Vec3Ty))
2385*0fca6ea1SDimitry Andric       .addUse(Variable);
2386*0fca6ea1SDimitry Andric 
2387*0fca6ea1SDimitry Andric   // Get Thread ID index. Expecting operand is a constant immediate value,
2388*0fca6ea1SDimitry Andric   // wrapped in a type assignment.
2389*0fca6ea1SDimitry Andric   assert(I.getOperand(2).isReg());
2390*0fca6ea1SDimitry Andric   Register ThreadIdReg = I.getOperand(2).getReg();
2391*0fca6ea1SDimitry Andric   SPIRVType *ConstTy = this->MRI->getVRegDef(ThreadIdReg);
2392*0fca6ea1SDimitry Andric   assert(ConstTy && ConstTy->getOpcode() == SPIRV::ASSIGN_TYPE &&
2393*0fca6ea1SDimitry Andric          ConstTy->getOperand(1).isReg());
2394*0fca6ea1SDimitry Andric   Register ConstReg = ConstTy->getOperand(1).getReg();
2395*0fca6ea1SDimitry Andric   const MachineInstr *Const = this->MRI->getVRegDef(ConstReg);
2396*0fca6ea1SDimitry Andric   assert(Const && Const->getOpcode() == TargetOpcode::G_CONSTANT);
2397*0fca6ea1SDimitry Andric   const llvm::APInt &Val = Const->getOperand(1).getCImm()->getValue();
2398*0fca6ea1SDimitry Andric   const uint32_t ThreadId = Val.getZExtValue();
2399*0fca6ea1SDimitry Andric 
2400*0fca6ea1SDimitry Andric   // Extract the thread ID from the loaded vector value.
2401*0fca6ea1SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
2402*0fca6ea1SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
2403*0fca6ea1SDimitry Andric                  .addDef(ResVReg)
2404*0fca6ea1SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
2405*0fca6ea1SDimitry Andric                  .addUse(LoadedRegister)
2406*0fca6ea1SDimitry Andric                  .addImm(ThreadId);
2407*0fca6ea1SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
2408*0fca6ea1SDimitry Andric }
2409*0fca6ea1SDimitry Andric 
241081ad6265SDimitry Andric namespace llvm {
241181ad6265SDimitry Andric InstructionSelector *
241281ad6265SDimitry Andric createSPIRVInstructionSelector(const SPIRVTargetMachine &TM,
241381ad6265SDimitry Andric                                const SPIRVSubtarget &Subtarget,
241481ad6265SDimitry Andric                                const RegisterBankInfo &RBI) {
241581ad6265SDimitry Andric   return new SPIRVInstructionSelector(TM, Subtarget, RBI);
241681ad6265SDimitry Andric }
241781ad6265SDimitry Andric } // namespace llvm
2418