xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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 
1581ad6265SDimitry Andric #include "SPIRV.h"
1681ad6265SDimitry Andric #include "SPIRVGlobalRegistry.h"
1781ad6265SDimitry Andric #include "SPIRVInstrInfo.h"
1881ad6265SDimitry Andric #include "SPIRVRegisterBankInfo.h"
1981ad6265SDimitry Andric #include "SPIRVRegisterInfo.h"
2081ad6265SDimitry Andric #include "SPIRVTargetMachine.h"
2181ad6265SDimitry Andric #include "SPIRVUtils.h"
2281ad6265SDimitry Andric #include "llvm/ADT/APFloat.h"
23*06c3fb27SDimitry Andric #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
2481ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
2581ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
2681ad6265SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
2781ad6265SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h"
2881ad6265SDimitry Andric #include "llvm/Support/Debug.h"
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric #define DEBUG_TYPE "spirv-isel"
3181ad6265SDimitry Andric 
3281ad6265SDimitry Andric using namespace llvm;
33bdd1243dSDimitry Andric namespace CL = SPIRV::OpenCLExtInst;
34bdd1243dSDimitry Andric namespace GL = SPIRV::GLSLExtInst;
35bdd1243dSDimitry Andric 
36bdd1243dSDimitry Andric using ExtInstList =
37bdd1243dSDimitry Andric     std::vector<std::pair<SPIRV::InstructionSet::InstructionSet, uint32_t>>;
3881ad6265SDimitry Andric 
3981ad6265SDimitry Andric namespace {
4081ad6265SDimitry Andric 
4181ad6265SDimitry Andric #define GET_GLOBALISEL_PREDICATE_BITSET
4281ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
4381ad6265SDimitry Andric #undef GET_GLOBALISEL_PREDICATE_BITSET
4481ad6265SDimitry Andric 
4581ad6265SDimitry Andric class SPIRVInstructionSelector : public InstructionSelector {
4681ad6265SDimitry Andric   const SPIRVSubtarget &STI;
4781ad6265SDimitry Andric   const SPIRVInstrInfo &TII;
4881ad6265SDimitry Andric   const SPIRVRegisterInfo &TRI;
4981ad6265SDimitry Andric   const RegisterBankInfo &RBI;
5081ad6265SDimitry Andric   SPIRVGlobalRegistry &GR;
5181ad6265SDimitry Andric   MachineRegisterInfo *MRI;
5281ad6265SDimitry Andric 
5381ad6265SDimitry Andric public:
5481ad6265SDimitry Andric   SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
5581ad6265SDimitry Andric                            const SPIRVSubtarget &ST,
5681ad6265SDimitry Andric                            const RegisterBankInfo &RBI);
5781ad6265SDimitry Andric   void setupMF(MachineFunction &MF, GISelKnownBits *KB,
58*06c3fb27SDimitry Andric                CodeGenCoverage *CoverageInfo, ProfileSummaryInfo *PSI,
5981ad6265SDimitry Andric                BlockFrequencyInfo *BFI) override;
6081ad6265SDimitry Andric   // Common selection code. Instruction-specific selection occurs in spvSelect.
6181ad6265SDimitry Andric   bool select(MachineInstr &I) override;
6281ad6265SDimitry Andric   static const char *getName() { return DEBUG_TYPE; }
6381ad6265SDimitry Andric 
6481ad6265SDimitry Andric #define GET_GLOBALISEL_PREDICATES_DECL
6581ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
6681ad6265SDimitry Andric #undef GET_GLOBALISEL_PREDICATES_DECL
6781ad6265SDimitry Andric 
6881ad6265SDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_DECL
6981ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
7081ad6265SDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_DECL
7181ad6265SDimitry Andric 
7281ad6265SDimitry Andric private:
7381ad6265SDimitry Andric   // tblgen-erated 'select' implementation, used as the initial selector for
7481ad6265SDimitry Andric   // the patterns that don't require complex C++.
7581ad6265SDimitry Andric   bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
7681ad6265SDimitry Andric 
7781ad6265SDimitry Andric   // All instruction-specific selection that didn't happen in "select()".
7881ad6265SDimitry Andric   // Is basically a large Switch/Case delegating to all other select method.
7981ad6265SDimitry Andric   bool spvSelect(Register ResVReg, const SPIRVType *ResType,
8081ad6265SDimitry Andric                  MachineInstr &I) const;
8181ad6265SDimitry Andric 
8281ad6265SDimitry Andric   bool selectGlobalValue(Register ResVReg, MachineInstr &I,
8381ad6265SDimitry Andric                          const MachineInstr *Init = nullptr) const;
8481ad6265SDimitry Andric 
8581ad6265SDimitry Andric   bool selectUnOpWithSrc(Register ResVReg, const SPIRVType *ResType,
8681ad6265SDimitry Andric                          MachineInstr &I, Register SrcReg,
8781ad6265SDimitry Andric                          unsigned Opcode) const;
8881ad6265SDimitry Andric   bool selectUnOp(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
8981ad6265SDimitry Andric                   unsigned Opcode) const;
9081ad6265SDimitry Andric 
9181ad6265SDimitry Andric   bool selectLoad(Register ResVReg, const SPIRVType *ResType,
9281ad6265SDimitry Andric                   MachineInstr &I) const;
9381ad6265SDimitry Andric   bool selectStore(MachineInstr &I) const;
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric   bool selectMemOperation(Register ResVReg, MachineInstr &I) const;
9681ad6265SDimitry Andric 
9781ad6265SDimitry Andric   bool selectAtomicRMW(Register ResVReg, const SPIRVType *ResType,
9881ad6265SDimitry Andric                        MachineInstr &I, unsigned NewOpcode) const;
9981ad6265SDimitry Andric 
10081ad6265SDimitry Andric   bool selectAtomicCmpXchg(Register ResVReg, const SPIRVType *ResType,
10181ad6265SDimitry Andric                            MachineInstr &I) const;
10281ad6265SDimitry Andric 
10381ad6265SDimitry Andric   bool selectFence(MachineInstr &I) const;
10481ad6265SDimitry Andric 
10581ad6265SDimitry Andric   bool selectAddrSpaceCast(Register ResVReg, const SPIRVType *ResType,
10681ad6265SDimitry Andric                            MachineInstr &I) const;
10781ad6265SDimitry Andric 
10881ad6265SDimitry Andric   bool selectBitreverse(Register ResVReg, const SPIRVType *ResType,
10981ad6265SDimitry Andric                         MachineInstr &I) const;
11081ad6265SDimitry Andric 
11181ad6265SDimitry Andric   bool selectConstVector(Register ResVReg, const SPIRVType *ResType,
11281ad6265SDimitry Andric                          MachineInstr &I) const;
11381ad6265SDimitry Andric 
11481ad6265SDimitry Andric   bool selectCmp(Register ResVReg, const SPIRVType *ResType,
11581ad6265SDimitry Andric                  unsigned comparisonOpcode, MachineInstr &I) const;
11681ad6265SDimitry Andric 
11781ad6265SDimitry Andric   bool selectICmp(Register ResVReg, const SPIRVType *ResType,
11881ad6265SDimitry Andric                   MachineInstr &I) const;
11981ad6265SDimitry Andric   bool selectFCmp(Register ResVReg, const SPIRVType *ResType,
12081ad6265SDimitry Andric                   MachineInstr &I) const;
12181ad6265SDimitry Andric 
12281ad6265SDimitry Andric   void renderImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
12381ad6265SDimitry Andric                    int OpIdx) const;
12481ad6265SDimitry Andric   void renderFImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
12581ad6265SDimitry Andric                     int OpIdx) const;
12681ad6265SDimitry Andric 
12781ad6265SDimitry Andric   bool selectConst(Register ResVReg, const SPIRVType *ResType, const APInt &Imm,
12881ad6265SDimitry Andric                    MachineInstr &I) const;
12981ad6265SDimitry Andric 
13081ad6265SDimitry Andric   bool selectSelect(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
13181ad6265SDimitry Andric                     bool IsSigned) const;
13281ad6265SDimitry Andric   bool selectIToF(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
13381ad6265SDimitry Andric                   bool IsSigned, unsigned Opcode) const;
13481ad6265SDimitry Andric   bool selectExt(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
13581ad6265SDimitry Andric                  bool IsSigned) const;
13681ad6265SDimitry Andric 
13781ad6265SDimitry Andric   bool selectTrunc(Register ResVReg, const SPIRVType *ResType,
13881ad6265SDimitry Andric                    MachineInstr &I) const;
13981ad6265SDimitry Andric 
140bdd1243dSDimitry Andric   bool selectIntToBool(Register IntReg, Register ResVReg, MachineInstr &I,
141bdd1243dSDimitry Andric                        const SPIRVType *intTy, const SPIRVType *boolTy) const;
14281ad6265SDimitry Andric 
14381ad6265SDimitry Andric   bool selectOpUndef(Register ResVReg, const SPIRVType *ResType,
14481ad6265SDimitry Andric                      MachineInstr &I) const;
14581ad6265SDimitry Andric   bool selectIntrinsic(Register ResVReg, const SPIRVType *ResType,
14681ad6265SDimitry Andric                        MachineInstr &I) const;
14781ad6265SDimitry Andric   bool selectExtractVal(Register ResVReg, const SPIRVType *ResType,
14881ad6265SDimitry Andric                         MachineInstr &I) const;
14981ad6265SDimitry Andric   bool selectInsertVal(Register ResVReg, const SPIRVType *ResType,
15081ad6265SDimitry Andric                        MachineInstr &I) const;
15181ad6265SDimitry Andric   bool selectExtractElt(Register ResVReg, const SPIRVType *ResType,
15281ad6265SDimitry Andric                         MachineInstr &I) const;
15381ad6265SDimitry Andric   bool selectInsertElt(Register ResVReg, const SPIRVType *ResType,
15481ad6265SDimitry Andric                        MachineInstr &I) const;
15581ad6265SDimitry Andric   bool selectGEP(Register ResVReg, const SPIRVType *ResType,
15681ad6265SDimitry Andric                  MachineInstr &I) const;
15781ad6265SDimitry Andric 
15881ad6265SDimitry Andric   bool selectFrameIndex(Register ResVReg, const SPIRVType *ResType,
15981ad6265SDimitry Andric                         MachineInstr &I) const;
16081ad6265SDimitry Andric 
16181ad6265SDimitry Andric   bool selectBranch(MachineInstr &I) const;
16281ad6265SDimitry Andric   bool selectBranchCond(MachineInstr &I) const;
16381ad6265SDimitry Andric 
16481ad6265SDimitry Andric   bool selectPhi(Register ResVReg, const SPIRVType *ResType,
16581ad6265SDimitry Andric                  MachineInstr &I) const;
16681ad6265SDimitry Andric 
167bdd1243dSDimitry Andric   bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
168bdd1243dSDimitry Andric                      MachineInstr &I, CL::OpenCLExtInst CLInst) const;
169bdd1243dSDimitry Andric   bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
170bdd1243dSDimitry Andric                      MachineInstr &I, CL::OpenCLExtInst CLInst,
171bdd1243dSDimitry Andric                      GL::GLSLExtInst GLInst) const;
172bdd1243dSDimitry Andric   bool selectExtInst(Register ResVReg, const SPIRVType *ResType,
173bdd1243dSDimitry Andric                      MachineInstr &I, const ExtInstList &ExtInsts) const;
174bdd1243dSDimitry Andric 
17581ad6265SDimitry Andric   Register buildI32Constant(uint32_t Val, MachineInstr &I,
17681ad6265SDimitry Andric                             const SPIRVType *ResType = nullptr) const;
17781ad6265SDimitry Andric 
17881ad6265SDimitry Andric   Register buildZerosVal(const SPIRVType *ResType, MachineInstr &I) const;
17981ad6265SDimitry Andric   Register buildOnesVal(bool AllOnes, const SPIRVType *ResType,
18081ad6265SDimitry Andric                         MachineInstr &I) const;
18181ad6265SDimitry Andric };
18281ad6265SDimitry Andric 
18381ad6265SDimitry Andric } // end anonymous namespace
18481ad6265SDimitry Andric 
18581ad6265SDimitry Andric #define GET_GLOBALISEL_IMPL
18681ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
18781ad6265SDimitry Andric #undef GET_GLOBALISEL_IMPL
18881ad6265SDimitry Andric 
18981ad6265SDimitry Andric SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
19081ad6265SDimitry Andric                                                    const SPIRVSubtarget &ST,
19181ad6265SDimitry Andric                                                    const RegisterBankInfo &RBI)
19281ad6265SDimitry Andric     : InstructionSelector(), STI(ST), TII(*ST.getInstrInfo()),
19381ad6265SDimitry Andric       TRI(*ST.getRegisterInfo()), RBI(RBI), GR(*ST.getSPIRVGlobalRegistry()),
19481ad6265SDimitry Andric #define GET_GLOBALISEL_PREDICATES_INIT
19581ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
19681ad6265SDimitry Andric #undef GET_GLOBALISEL_PREDICATES_INIT
19781ad6265SDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_INIT
19881ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
19981ad6265SDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_INIT
20081ad6265SDimitry Andric {
20181ad6265SDimitry Andric }
20281ad6265SDimitry Andric 
20381ad6265SDimitry Andric void SPIRVInstructionSelector::setupMF(MachineFunction &MF, GISelKnownBits *KB,
204*06c3fb27SDimitry Andric                                        CodeGenCoverage *CoverageInfo,
20581ad6265SDimitry Andric                                        ProfileSummaryInfo *PSI,
20681ad6265SDimitry Andric                                        BlockFrequencyInfo *BFI) {
20781ad6265SDimitry Andric   MRI = &MF.getRegInfo();
20881ad6265SDimitry Andric   GR.setCurrentFunc(MF);
20981ad6265SDimitry Andric   InstructionSelector::setupMF(MF, KB, CoverageInfo, PSI, BFI);
21081ad6265SDimitry Andric }
21181ad6265SDimitry Andric 
212fcaf7f86SDimitry Andric static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI);
213fcaf7f86SDimitry Andric 
21481ad6265SDimitry Andric // Defined in SPIRVLegalizerInfo.cpp.
21581ad6265SDimitry Andric extern bool isTypeFoldingSupported(unsigned Opcode);
21681ad6265SDimitry Andric 
21781ad6265SDimitry Andric bool SPIRVInstructionSelector::select(MachineInstr &I) {
21881ad6265SDimitry Andric   assert(I.getParent() && "Instruction should be in a basic block!");
21981ad6265SDimitry Andric   assert(I.getParent()->getParent() && "Instruction should be in a function!");
22081ad6265SDimitry Andric 
22181ad6265SDimitry Andric   Register Opcode = I.getOpcode();
22281ad6265SDimitry Andric   // If it's not a GMIR instruction, we've selected it already.
22381ad6265SDimitry Andric   if (!isPreISelGenericOpcode(Opcode)) {
22481ad6265SDimitry Andric     if (Opcode == SPIRV::ASSIGN_TYPE) { // These pseudos aren't needed any more.
22581ad6265SDimitry Andric       auto *Def = MRI->getVRegDef(I.getOperand(1).getReg());
22681ad6265SDimitry Andric       if (isTypeFoldingSupported(Def->getOpcode())) {
22781ad6265SDimitry Andric         auto Res = selectImpl(I, *CoverageInfo);
22881ad6265SDimitry Andric         assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT);
22981ad6265SDimitry Andric         if (Res)
23081ad6265SDimitry Andric           return Res;
23181ad6265SDimitry Andric       }
23281ad6265SDimitry Andric       MRI->replaceRegWith(I.getOperand(1).getReg(), I.getOperand(0).getReg());
23381ad6265SDimitry Andric       I.removeFromParent();
234bdd1243dSDimitry Andric       return true;
23581ad6265SDimitry Andric     } else if (I.getNumDefs() == 1) {
23681ad6265SDimitry Andric       // Make all vregs 32 bits (for SPIR-V IDs).
23781ad6265SDimitry Andric       MRI->setType(I.getOperand(0).getReg(), LLT::scalar(32));
23881ad6265SDimitry Andric     }
239bdd1243dSDimitry Andric     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
24081ad6265SDimitry Andric   }
24181ad6265SDimitry Andric 
24281ad6265SDimitry Andric   if (I.getNumOperands() != I.getNumExplicitOperands()) {
24381ad6265SDimitry Andric     LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
24481ad6265SDimitry Andric     return false;
24581ad6265SDimitry Andric   }
24681ad6265SDimitry Andric 
24781ad6265SDimitry Andric   // Common code for getting return reg+type, and removing selected instr
24881ad6265SDimitry Andric   // from parent occurs here. Instr-specific selection happens in spvSelect().
24981ad6265SDimitry Andric   bool HasDefs = I.getNumDefs() > 0;
25081ad6265SDimitry Andric   Register ResVReg = HasDefs ? I.getOperand(0).getReg() : Register(0);
25181ad6265SDimitry Andric   SPIRVType *ResType = HasDefs ? GR.getSPIRVTypeForVReg(ResVReg) : nullptr;
25281ad6265SDimitry Andric   assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
25381ad6265SDimitry Andric   if (spvSelect(ResVReg, ResType, I)) {
25481ad6265SDimitry Andric     if (HasDefs) // Make all vregs 32 bits (for SPIR-V IDs).
25581ad6265SDimitry Andric       MRI->setType(ResVReg, LLT::scalar(32));
25681ad6265SDimitry Andric     I.removeFromParent();
25781ad6265SDimitry Andric     return true;
25881ad6265SDimitry Andric   }
25981ad6265SDimitry Andric   return false;
26081ad6265SDimitry Andric }
26181ad6265SDimitry Andric 
26281ad6265SDimitry Andric bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
26381ad6265SDimitry Andric                                          const SPIRVType *ResType,
26481ad6265SDimitry Andric                                          MachineInstr &I) const {
26581ad6265SDimitry Andric   assert(!isTypeFoldingSupported(I.getOpcode()) ||
26681ad6265SDimitry Andric          I.getOpcode() == TargetOpcode::G_CONSTANT);
26781ad6265SDimitry Andric   const unsigned Opcode = I.getOpcode();
26881ad6265SDimitry Andric   switch (Opcode) {
26981ad6265SDimitry Andric   case TargetOpcode::G_CONSTANT:
27081ad6265SDimitry Andric     return selectConst(ResVReg, ResType, I.getOperand(1).getCImm()->getValue(),
27181ad6265SDimitry Andric                        I);
27281ad6265SDimitry Andric   case TargetOpcode::G_GLOBAL_VALUE:
27381ad6265SDimitry Andric     return selectGlobalValue(ResVReg, I);
27481ad6265SDimitry Andric   case TargetOpcode::G_IMPLICIT_DEF:
27581ad6265SDimitry Andric     return selectOpUndef(ResVReg, ResType, I);
27681ad6265SDimitry Andric 
27781ad6265SDimitry Andric   case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
27881ad6265SDimitry Andric     return selectIntrinsic(ResVReg, ResType, I);
27981ad6265SDimitry Andric   case TargetOpcode::G_BITREVERSE:
28081ad6265SDimitry Andric     return selectBitreverse(ResVReg, ResType, I);
28181ad6265SDimitry Andric 
28281ad6265SDimitry Andric   case TargetOpcode::G_BUILD_VECTOR:
28381ad6265SDimitry Andric     return selectConstVector(ResVReg, ResType, I);
28481ad6265SDimitry Andric 
28581ad6265SDimitry Andric   case TargetOpcode::G_SHUFFLE_VECTOR: {
28681ad6265SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
28781ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle))
28881ad6265SDimitry Andric                    .addDef(ResVReg)
28981ad6265SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType))
29081ad6265SDimitry Andric                    .addUse(I.getOperand(1).getReg())
29181ad6265SDimitry Andric                    .addUse(I.getOperand(2).getReg());
29281ad6265SDimitry Andric     for (auto V : I.getOperand(3).getShuffleMask())
29381ad6265SDimitry Andric       MIB.addImm(V);
29481ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
29581ad6265SDimitry Andric   }
29681ad6265SDimitry Andric   case TargetOpcode::G_MEMMOVE:
29781ad6265SDimitry Andric   case TargetOpcode::G_MEMCPY:
298bdd1243dSDimitry Andric   case TargetOpcode::G_MEMSET:
29981ad6265SDimitry Andric     return selectMemOperation(ResVReg, I);
30081ad6265SDimitry Andric 
30181ad6265SDimitry Andric   case TargetOpcode::G_ICMP:
30281ad6265SDimitry Andric     return selectICmp(ResVReg, ResType, I);
30381ad6265SDimitry Andric   case TargetOpcode::G_FCMP:
30481ad6265SDimitry Andric     return selectFCmp(ResVReg, ResType, I);
30581ad6265SDimitry Andric 
30681ad6265SDimitry Andric   case TargetOpcode::G_FRAME_INDEX:
30781ad6265SDimitry Andric     return selectFrameIndex(ResVReg, ResType, I);
30881ad6265SDimitry Andric 
30981ad6265SDimitry Andric   case TargetOpcode::G_LOAD:
31081ad6265SDimitry Andric     return selectLoad(ResVReg, ResType, I);
31181ad6265SDimitry Andric   case TargetOpcode::G_STORE:
31281ad6265SDimitry Andric     return selectStore(I);
31381ad6265SDimitry Andric 
31481ad6265SDimitry Andric   case TargetOpcode::G_BR:
31581ad6265SDimitry Andric     return selectBranch(I);
31681ad6265SDimitry Andric   case TargetOpcode::G_BRCOND:
31781ad6265SDimitry Andric     return selectBranchCond(I);
31881ad6265SDimitry Andric 
31981ad6265SDimitry Andric   case TargetOpcode::G_PHI:
32081ad6265SDimitry Andric     return selectPhi(ResVReg, ResType, I);
32181ad6265SDimitry Andric 
32281ad6265SDimitry Andric   case TargetOpcode::G_FPTOSI:
32381ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
32481ad6265SDimitry Andric   case TargetOpcode::G_FPTOUI:
32581ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
32681ad6265SDimitry Andric 
32781ad6265SDimitry Andric   case TargetOpcode::G_SITOFP:
32881ad6265SDimitry Andric     return selectIToF(ResVReg, ResType, I, true, SPIRV::OpConvertSToF);
32981ad6265SDimitry Andric   case TargetOpcode::G_UITOFP:
33081ad6265SDimitry Andric     return selectIToF(ResVReg, ResType, I, false, SPIRV::OpConvertUToF);
33181ad6265SDimitry Andric 
33281ad6265SDimitry Andric   case TargetOpcode::G_CTPOP:
33381ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitCount);
334bdd1243dSDimitry Andric   case TargetOpcode::G_SMIN:
335bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::s_min, GL::SMin);
336bdd1243dSDimitry Andric   case TargetOpcode::G_UMIN:
337bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::u_min, GL::UMin);
338bdd1243dSDimitry Andric 
339bdd1243dSDimitry Andric   case TargetOpcode::G_SMAX:
340bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::s_max, GL::SMax);
341bdd1243dSDimitry Andric   case TargetOpcode::G_UMAX:
342bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::u_max, GL::UMax);
343bdd1243dSDimitry Andric 
344bdd1243dSDimitry Andric   case TargetOpcode::G_FMA:
345bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
346bdd1243dSDimitry Andric 
347bdd1243dSDimitry Andric   case TargetOpcode::G_FPOW:
348bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::pow, GL::Pow);
349bdd1243dSDimitry Andric   case TargetOpcode::G_FPOWI:
350bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::pown);
351bdd1243dSDimitry Andric 
352bdd1243dSDimitry Andric   case TargetOpcode::G_FEXP:
353bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::exp, GL::Exp);
354bdd1243dSDimitry Andric   case TargetOpcode::G_FEXP2:
355bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::exp2, GL::Exp2);
356bdd1243dSDimitry Andric 
357bdd1243dSDimitry Andric   case TargetOpcode::G_FLOG:
358bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::log, GL::Log);
359bdd1243dSDimitry Andric   case TargetOpcode::G_FLOG2:
360bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::log2, GL::Log2);
361bdd1243dSDimitry Andric   case TargetOpcode::G_FLOG10:
362bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::log10);
363bdd1243dSDimitry Andric 
364bdd1243dSDimitry Andric   case TargetOpcode::G_FABS:
365bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::fabs, GL::FAbs);
366bdd1243dSDimitry Andric   case TargetOpcode::G_ABS:
367bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::s_abs, GL::SAbs);
368bdd1243dSDimitry Andric 
369bdd1243dSDimitry Andric   case TargetOpcode::G_FMINNUM:
370bdd1243dSDimitry Andric   case TargetOpcode::G_FMINIMUM:
371bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::fmin, GL::FMin);
372bdd1243dSDimitry Andric   case TargetOpcode::G_FMAXNUM:
373bdd1243dSDimitry Andric   case TargetOpcode::G_FMAXIMUM:
374bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::fmax, GL::FMax);
375bdd1243dSDimitry Andric 
376bdd1243dSDimitry Andric   case TargetOpcode::G_FCOPYSIGN:
377bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::copysign);
378bdd1243dSDimitry Andric 
379bdd1243dSDimitry Andric   case TargetOpcode::G_FCEIL:
380bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::ceil, GL::Ceil);
381bdd1243dSDimitry Andric   case TargetOpcode::G_FFLOOR:
382bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::floor, GL::Floor);
383bdd1243dSDimitry Andric 
384bdd1243dSDimitry Andric   case TargetOpcode::G_FCOS:
385bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::cos, GL::Cos);
386bdd1243dSDimitry Andric   case TargetOpcode::G_FSIN:
387bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::sin, GL::Sin);
388bdd1243dSDimitry Andric 
389bdd1243dSDimitry Andric   case TargetOpcode::G_FSQRT:
390bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::sqrt, GL::Sqrt);
391bdd1243dSDimitry Andric 
392bdd1243dSDimitry Andric   case TargetOpcode::G_CTTZ:
393bdd1243dSDimitry Andric   case TargetOpcode::G_CTTZ_ZERO_UNDEF:
394bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::ctz);
395bdd1243dSDimitry Andric   case TargetOpcode::G_CTLZ:
396bdd1243dSDimitry Andric   case TargetOpcode::G_CTLZ_ZERO_UNDEF:
397bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::clz);
398bdd1243dSDimitry Andric 
399bdd1243dSDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUND:
400bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::round, GL::Round);
401bdd1243dSDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
402bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven);
403bdd1243dSDimitry Andric   case TargetOpcode::G_INTRINSIC_TRUNC:
404bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::trunc, GL::Trunc);
405bdd1243dSDimitry Andric   case TargetOpcode::G_FRINT:
406bdd1243dSDimitry Andric   case TargetOpcode::G_FNEARBYINT:
407bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven);
408bdd1243dSDimitry Andric 
409bdd1243dSDimitry Andric   case TargetOpcode::G_SMULH:
410bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::s_mul_hi);
411bdd1243dSDimitry Andric   case TargetOpcode::G_UMULH:
412bdd1243dSDimitry Andric     return selectExtInst(ResVReg, ResType, I, CL::u_mul_hi);
41381ad6265SDimitry Andric 
41481ad6265SDimitry Andric   case TargetOpcode::G_SEXT:
41581ad6265SDimitry Andric     return selectExt(ResVReg, ResType, I, true);
41681ad6265SDimitry Andric   case TargetOpcode::G_ANYEXT:
41781ad6265SDimitry Andric   case TargetOpcode::G_ZEXT:
41881ad6265SDimitry Andric     return selectExt(ResVReg, ResType, I, false);
41981ad6265SDimitry Andric   case TargetOpcode::G_TRUNC:
42081ad6265SDimitry Andric     return selectTrunc(ResVReg, ResType, I);
42181ad6265SDimitry Andric   case TargetOpcode::G_FPTRUNC:
42281ad6265SDimitry Andric   case TargetOpcode::G_FPEXT:
42381ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpFConvert);
42481ad6265SDimitry Andric 
42581ad6265SDimitry Andric   case TargetOpcode::G_PTRTOINT:
42681ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertPtrToU);
42781ad6265SDimitry Andric   case TargetOpcode::G_INTTOPTR:
42881ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertUToPtr);
42981ad6265SDimitry Andric   case TargetOpcode::G_BITCAST:
43081ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast);
43181ad6265SDimitry Andric   case TargetOpcode::G_ADDRSPACE_CAST:
43281ad6265SDimitry Andric     return selectAddrSpaceCast(ResVReg, ResType, I);
433fcaf7f86SDimitry Andric   case TargetOpcode::G_PTR_ADD: {
434fcaf7f86SDimitry Andric     // Currently, we get G_PTR_ADD only as a result of translating
435fcaf7f86SDimitry Andric     // global variables, initialized with constant expressions like GV + Const
436fcaf7f86SDimitry Andric     // (see test opencl/basic/progvar_prog_scope_init.ll).
437fcaf7f86SDimitry Andric     // TODO: extend the handler once we have other cases.
438fcaf7f86SDimitry Andric     assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
439fcaf7f86SDimitry Andric     Register GV = I.getOperand(1).getReg();
440fcaf7f86SDimitry Andric     MachineRegisterInfo::def_instr_iterator II = MRI->def_instr_begin(GV);
441fcaf7f86SDimitry Andric     assert(((*II).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
442fcaf7f86SDimitry Andric             (*II).getOpcode() == TargetOpcode::COPY ||
443fcaf7f86SDimitry Andric             (*II).getOpcode() == SPIRV::OpVariable) &&
444fcaf7f86SDimitry Andric            isImm(I.getOperand(2), MRI));
445fcaf7f86SDimitry Andric     Register Idx = buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I);
446fcaf7f86SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
447fcaf7f86SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
448fcaf7f86SDimitry Andric                    .addDef(ResVReg)
449fcaf7f86SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType))
450fcaf7f86SDimitry Andric                    .addImm(static_cast<uint32_t>(
451fcaf7f86SDimitry Andric                        SPIRV::Opcode::InBoundsPtrAccessChain))
452fcaf7f86SDimitry Andric                    .addUse(GV)
453fcaf7f86SDimitry Andric                    .addUse(Idx)
454fcaf7f86SDimitry Andric                    .addUse(I.getOperand(2).getReg());
455fcaf7f86SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
456fcaf7f86SDimitry Andric   }
45781ad6265SDimitry Andric 
45881ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_OR:
45981ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicOr);
46081ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_ADD:
46181ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicIAdd);
46281ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_AND:
46381ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicAnd);
46481ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_MAX:
46581ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMax);
46681ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_MIN:
46781ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMin);
46881ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_SUB:
46981ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicISub);
47081ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XOR:
47181ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicXor);
47281ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_UMAX:
47381ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMax);
47481ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_UMIN:
47581ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMin);
47681ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XCHG:
47781ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicExchange);
47881ad6265SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG:
47981ad6265SDimitry Andric     return selectAtomicCmpXchg(ResVReg, ResType, I);
48081ad6265SDimitry Andric 
48181ad6265SDimitry Andric   case TargetOpcode::G_FENCE:
48281ad6265SDimitry Andric     return selectFence(I);
48381ad6265SDimitry Andric 
48481ad6265SDimitry Andric   default:
48581ad6265SDimitry Andric     return false;
48681ad6265SDimitry Andric   }
48781ad6265SDimitry Andric }
48881ad6265SDimitry Andric 
489bdd1243dSDimitry Andric bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
490bdd1243dSDimitry Andric                                              const SPIRVType *ResType,
491bdd1243dSDimitry Andric                                              MachineInstr &I,
492bdd1243dSDimitry Andric                                              CL::OpenCLExtInst CLInst) const {
493bdd1243dSDimitry Andric   return selectExtInst(ResVReg, ResType, I,
494bdd1243dSDimitry Andric                        {{SPIRV::InstructionSet::OpenCL_std, CLInst}});
495bdd1243dSDimitry Andric }
496bdd1243dSDimitry Andric 
497bdd1243dSDimitry Andric bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
498bdd1243dSDimitry Andric                                              const SPIRVType *ResType,
499bdd1243dSDimitry Andric                                              MachineInstr &I,
500bdd1243dSDimitry Andric                                              CL::OpenCLExtInst CLInst,
501bdd1243dSDimitry Andric                                              GL::GLSLExtInst GLInst) const {
502bdd1243dSDimitry Andric   ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst},
503bdd1243dSDimitry Andric                           {SPIRV::InstructionSet::GLSL_std_450, GLInst}};
504bdd1243dSDimitry Andric   return selectExtInst(ResVReg, ResType, I, ExtInsts);
505bdd1243dSDimitry Andric }
506bdd1243dSDimitry Andric 
507bdd1243dSDimitry Andric bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
508bdd1243dSDimitry Andric                                              const SPIRVType *ResType,
509bdd1243dSDimitry Andric                                              MachineInstr &I,
510bdd1243dSDimitry Andric                                              const ExtInstList &Insts) const {
511bdd1243dSDimitry Andric 
512bdd1243dSDimitry Andric   for (const auto &Ex : Insts) {
513bdd1243dSDimitry Andric     SPIRV::InstructionSet::InstructionSet Set = Ex.first;
514bdd1243dSDimitry Andric     uint32_t Opcode = Ex.second;
515bdd1243dSDimitry Andric     if (STI.canUseExtInstSet(Set)) {
516bdd1243dSDimitry Andric       MachineBasicBlock &BB = *I.getParent();
517bdd1243dSDimitry Andric       auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
518bdd1243dSDimitry Andric                      .addDef(ResVReg)
519bdd1243dSDimitry Andric                      .addUse(GR.getSPIRVTypeID(ResType))
520bdd1243dSDimitry Andric                      .addImm(static_cast<uint32_t>(Set))
521bdd1243dSDimitry Andric                      .addImm(Opcode);
522bdd1243dSDimitry Andric       const unsigned NumOps = I.getNumOperands();
523bdd1243dSDimitry Andric       for (unsigned i = 1; i < NumOps; ++i)
524bdd1243dSDimitry Andric         MIB.add(I.getOperand(i));
525bdd1243dSDimitry Andric       return MIB.constrainAllUses(TII, TRI, RBI);
526bdd1243dSDimitry Andric     }
527bdd1243dSDimitry Andric   }
528bdd1243dSDimitry Andric   return false;
529bdd1243dSDimitry Andric }
530bdd1243dSDimitry Andric 
53181ad6265SDimitry Andric bool SPIRVInstructionSelector::selectUnOpWithSrc(Register ResVReg,
53281ad6265SDimitry Andric                                                  const SPIRVType *ResType,
53381ad6265SDimitry Andric                                                  MachineInstr &I,
53481ad6265SDimitry Andric                                                  Register SrcReg,
53581ad6265SDimitry Andric                                                  unsigned Opcode) const {
53681ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
53781ad6265SDimitry Andric       .addDef(ResVReg)
53881ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
53981ad6265SDimitry Andric       .addUse(SrcReg)
54081ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
54181ad6265SDimitry Andric }
54281ad6265SDimitry Andric 
54381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectUnOp(Register ResVReg,
54481ad6265SDimitry Andric                                           const SPIRVType *ResType,
54581ad6265SDimitry Andric                                           MachineInstr &I,
54681ad6265SDimitry Andric                                           unsigned Opcode) const {
54781ad6265SDimitry Andric   return selectUnOpWithSrc(ResVReg, ResType, I, I.getOperand(1).getReg(),
54881ad6265SDimitry Andric                            Opcode);
54981ad6265SDimitry Andric }
55081ad6265SDimitry Andric 
551bdd1243dSDimitry Andric static SPIRV::Scope::Scope getScope(SyncScope::ID Ord) {
55281ad6265SDimitry Andric   switch (Ord) {
55381ad6265SDimitry Andric   case SyncScope::SingleThread:
55481ad6265SDimitry Andric     return SPIRV::Scope::Invocation;
55581ad6265SDimitry Andric   case SyncScope::System:
55681ad6265SDimitry Andric     return SPIRV::Scope::Device;
55781ad6265SDimitry Andric   default:
55881ad6265SDimitry Andric     llvm_unreachable("Unsupported synchronization Scope ID.");
55981ad6265SDimitry Andric   }
56081ad6265SDimitry Andric }
56181ad6265SDimitry Andric 
56281ad6265SDimitry Andric static void addMemoryOperands(MachineMemOperand *MemOp,
56381ad6265SDimitry Andric                               MachineInstrBuilder &MIB) {
56481ad6265SDimitry Andric   uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
56581ad6265SDimitry Andric   if (MemOp->isVolatile())
56681ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
56781ad6265SDimitry Andric   if (MemOp->isNonTemporal())
56881ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
56981ad6265SDimitry Andric   if (MemOp->getAlign().value())
57081ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned);
57181ad6265SDimitry Andric 
57281ad6265SDimitry Andric   if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) {
57381ad6265SDimitry Andric     MIB.addImm(SpvMemOp);
57481ad6265SDimitry Andric     if (SpvMemOp & static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned))
57581ad6265SDimitry Andric       MIB.addImm(MemOp->getAlign().value());
57681ad6265SDimitry Andric   }
57781ad6265SDimitry Andric }
57881ad6265SDimitry Andric 
57981ad6265SDimitry Andric static void addMemoryOperands(uint64_t Flags, MachineInstrBuilder &MIB) {
58081ad6265SDimitry Andric   uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
58181ad6265SDimitry Andric   if (Flags & MachineMemOperand::Flags::MOVolatile)
58281ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
58381ad6265SDimitry Andric   if (Flags & MachineMemOperand::Flags::MONonTemporal)
58481ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
58581ad6265SDimitry Andric 
58681ad6265SDimitry Andric   if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None))
58781ad6265SDimitry Andric     MIB.addImm(SpvMemOp);
58881ad6265SDimitry Andric }
58981ad6265SDimitry Andric 
59081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
59181ad6265SDimitry Andric                                           const SPIRVType *ResType,
59281ad6265SDimitry Andric                                           MachineInstr &I) const {
59381ad6265SDimitry Andric   unsigned OpOffset =
59481ad6265SDimitry Andric       I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ? 1 : 0;
59581ad6265SDimitry Andric   Register Ptr = I.getOperand(1 + OpOffset).getReg();
59681ad6265SDimitry Andric   auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
59781ad6265SDimitry Andric                  .addDef(ResVReg)
59881ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
59981ad6265SDimitry Andric                  .addUse(Ptr);
60081ad6265SDimitry Andric   if (!I.getNumMemOperands()) {
60181ad6265SDimitry Andric     assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
60281ad6265SDimitry Andric     addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
60381ad6265SDimitry Andric   } else {
60481ad6265SDimitry Andric     addMemoryOperands(*I.memoperands_begin(), MIB);
60581ad6265SDimitry Andric   }
60681ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
60781ad6265SDimitry Andric }
60881ad6265SDimitry Andric 
60981ad6265SDimitry Andric bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
61081ad6265SDimitry Andric   unsigned OpOffset =
61181ad6265SDimitry Andric       I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ? 1 : 0;
61281ad6265SDimitry Andric   Register StoreVal = I.getOperand(0 + OpOffset).getReg();
61381ad6265SDimitry Andric   Register Ptr = I.getOperand(1 + OpOffset).getReg();
61481ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
61581ad6265SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpStore))
61681ad6265SDimitry Andric                  .addUse(Ptr)
61781ad6265SDimitry Andric                  .addUse(StoreVal);
61881ad6265SDimitry Andric   if (!I.getNumMemOperands()) {
61981ad6265SDimitry Andric     assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
62081ad6265SDimitry Andric     addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
62181ad6265SDimitry Andric   } else {
62281ad6265SDimitry Andric     addMemoryOperands(*I.memoperands_begin(), MIB);
62381ad6265SDimitry Andric   }
62481ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
62581ad6265SDimitry Andric }
62681ad6265SDimitry Andric 
62781ad6265SDimitry Andric bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg,
62881ad6265SDimitry Andric                                                   MachineInstr &I) const {
62981ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
630bdd1243dSDimitry Andric   Register SrcReg = I.getOperand(1).getReg();
631bdd1243dSDimitry Andric   if (I.getOpcode() == TargetOpcode::G_MEMSET) {
632bdd1243dSDimitry Andric     assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
633bdd1243dSDimitry Andric     unsigned Val = getIConstVal(I.getOperand(1).getReg(), MRI);
634bdd1243dSDimitry Andric     unsigned Num = getIConstVal(I.getOperand(2).getReg(), MRI);
635bdd1243dSDimitry Andric     SPIRVType *ValTy = GR.getOrCreateSPIRVIntegerType(8, I, TII);
636bdd1243dSDimitry Andric     SPIRVType *ArrTy = GR.getOrCreateSPIRVArrayType(ValTy, Num, I, TII);
637bdd1243dSDimitry Andric     Register Const = GR.getOrCreateConsIntArray(Val, I, ArrTy, TII);
638bdd1243dSDimitry Andric     SPIRVType *VarTy = GR.getOrCreateSPIRVPointerType(
639bdd1243dSDimitry Andric         ArrTy, I, TII, SPIRV::StorageClass::UniformConstant);
640bdd1243dSDimitry Andric     // TODO: check if we have such GV, add init, use buildGlobalVariable.
641bdd1243dSDimitry Andric     Type *LLVMArrTy = ArrayType::get(
642bdd1243dSDimitry Andric         IntegerType::get(GR.CurMF->getFunction().getContext(), 8), Num);
643bdd1243dSDimitry Andric     GlobalVariable *GV =
644bdd1243dSDimitry Andric         new GlobalVariable(LLVMArrTy, true, GlobalValue::InternalLinkage);
645bdd1243dSDimitry Andric     Register VarReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
646bdd1243dSDimitry Andric     GR.add(GV, GR.CurMF, VarReg);
647bdd1243dSDimitry Andric 
648bdd1243dSDimitry Andric     buildOpDecorate(VarReg, I, TII, SPIRV::Decoration::Constant, {});
649bdd1243dSDimitry Andric     BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
650bdd1243dSDimitry Andric         .addDef(VarReg)
651bdd1243dSDimitry Andric         .addUse(GR.getSPIRVTypeID(VarTy))
652bdd1243dSDimitry Andric         .addImm(SPIRV::StorageClass::UniformConstant)
653bdd1243dSDimitry Andric         .addUse(Const)
654bdd1243dSDimitry Andric         .constrainAllUses(TII, TRI, RBI);
655bdd1243dSDimitry Andric     SPIRVType *SourceTy = GR.getOrCreateSPIRVPointerType(
656bdd1243dSDimitry Andric         ValTy, I, TII, SPIRV::StorageClass::UniformConstant);
657bdd1243dSDimitry Andric     SrcReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
658bdd1243dSDimitry Andric     selectUnOpWithSrc(SrcReg, SourceTy, I, VarReg, SPIRV::OpBitcast);
659bdd1243dSDimitry Andric   }
66081ad6265SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemorySized))
661fcaf7f86SDimitry Andric                  .addUse(I.getOperand(0).getReg())
662bdd1243dSDimitry Andric                  .addUse(SrcReg)
66381ad6265SDimitry Andric                  .addUse(I.getOperand(2).getReg());
66481ad6265SDimitry Andric   if (I.getNumMemOperands())
66581ad6265SDimitry Andric     addMemoryOperands(*I.memoperands_begin(), MIB);
66681ad6265SDimitry Andric   bool Result = MIB.constrainAllUses(TII, TRI, RBI);
667fcaf7f86SDimitry Andric   if (ResVReg.isValid() && ResVReg != MIB->getOperand(0).getReg())
66881ad6265SDimitry Andric     BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), ResVReg)
66981ad6265SDimitry Andric         .addUse(MIB->getOperand(0).getReg());
67081ad6265SDimitry Andric   return Result;
67181ad6265SDimitry Andric }
67281ad6265SDimitry Andric 
67381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg,
67481ad6265SDimitry Andric                                                const SPIRVType *ResType,
67581ad6265SDimitry Andric                                                MachineInstr &I,
67681ad6265SDimitry Andric                                                unsigned NewOpcode) const {
67781ad6265SDimitry Andric   assert(I.hasOneMemOperand());
67881ad6265SDimitry Andric   const MachineMemOperand *MemOp = *I.memoperands_begin();
67981ad6265SDimitry Andric   uint32_t Scope = static_cast<uint32_t>(getScope(MemOp->getSyncScopeID()));
68081ad6265SDimitry Andric   Register ScopeReg = buildI32Constant(Scope, I);
68181ad6265SDimitry Andric 
68281ad6265SDimitry Andric   Register Ptr = I.getOperand(1).getReg();
68381ad6265SDimitry Andric   // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll
68481ad6265SDimitry Andric   // auto ScSem =
68581ad6265SDimitry Andric   // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr));
68681ad6265SDimitry Andric   AtomicOrdering AO = MemOp->getSuccessOrdering();
68781ad6265SDimitry Andric   uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
68881ad6265SDimitry Andric   Register MemSemReg = buildI32Constant(MemSem /*| ScSem*/, I);
68981ad6265SDimitry Andric 
69081ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode))
69181ad6265SDimitry Andric       .addDef(ResVReg)
69281ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
69381ad6265SDimitry Andric       .addUse(Ptr)
69481ad6265SDimitry Andric       .addUse(ScopeReg)
69581ad6265SDimitry Andric       .addUse(MemSemReg)
69681ad6265SDimitry Andric       .addUse(I.getOperand(2).getReg())
69781ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
69881ad6265SDimitry Andric }
69981ad6265SDimitry Andric 
70081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectFence(MachineInstr &I) const {
70181ad6265SDimitry Andric   AtomicOrdering AO = AtomicOrdering(I.getOperand(0).getImm());
70281ad6265SDimitry Andric   uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
70381ad6265SDimitry Andric   Register MemSemReg = buildI32Constant(MemSem, I);
70481ad6265SDimitry Andric   SyncScope::ID Ord = SyncScope::ID(I.getOperand(1).getImm());
70581ad6265SDimitry Andric   uint32_t Scope = static_cast<uint32_t>(getScope(Ord));
70681ad6265SDimitry Andric   Register ScopeReg = buildI32Constant(Scope, I);
70781ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
70881ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMemoryBarrier))
70981ad6265SDimitry Andric       .addUse(ScopeReg)
71081ad6265SDimitry Andric       .addUse(MemSemReg)
71181ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
71281ad6265SDimitry Andric }
71381ad6265SDimitry Andric 
71481ad6265SDimitry Andric bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg,
71581ad6265SDimitry Andric                                                    const SPIRVType *ResType,
71681ad6265SDimitry Andric                                                    MachineInstr &I) const {
717fcaf7f86SDimitry Andric   Register ScopeReg;
718fcaf7f86SDimitry Andric   Register MemSemEqReg;
719fcaf7f86SDimitry Andric   Register MemSemNeqReg;
720fcaf7f86SDimitry Andric   Register Ptr = I.getOperand(2).getReg();
721fcaf7f86SDimitry Andric   if (I.getOpcode() != TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS) {
72281ad6265SDimitry Andric     assert(I.hasOneMemOperand());
72381ad6265SDimitry Andric     const MachineMemOperand *MemOp = *I.memoperands_begin();
724fcaf7f86SDimitry Andric     unsigned Scope = static_cast<uint32_t>(getScope(MemOp->getSyncScopeID()));
725fcaf7f86SDimitry Andric     ScopeReg = buildI32Constant(Scope, I);
72681ad6265SDimitry Andric 
727fcaf7f86SDimitry Andric     unsigned ScSem = static_cast<uint32_t>(
728fcaf7f86SDimitry Andric         getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr)));
729fcaf7f86SDimitry Andric     AtomicOrdering AO = MemOp->getSuccessOrdering();
730fcaf7f86SDimitry Andric     unsigned MemSemEq = static_cast<uint32_t>(getMemSemantics(AO)) | ScSem;
731fcaf7f86SDimitry Andric     MemSemEqReg = buildI32Constant(MemSemEq, I);
732fcaf7f86SDimitry Andric     AtomicOrdering FO = MemOp->getFailureOrdering();
733fcaf7f86SDimitry Andric     unsigned MemSemNeq = static_cast<uint32_t>(getMemSemantics(FO)) | ScSem;
734fcaf7f86SDimitry Andric     MemSemNeqReg =
735fcaf7f86SDimitry Andric         MemSemEq == MemSemNeq ? MemSemEqReg : buildI32Constant(MemSemNeq, I);
736fcaf7f86SDimitry Andric   } else {
737fcaf7f86SDimitry Andric     ScopeReg = I.getOperand(5).getReg();
738fcaf7f86SDimitry Andric     MemSemEqReg = I.getOperand(6).getReg();
739fcaf7f86SDimitry Andric     MemSemNeqReg = I.getOperand(7).getReg();
740fcaf7f86SDimitry Andric   }
741fcaf7f86SDimitry Andric 
74281ad6265SDimitry Andric   Register Cmp = I.getOperand(3).getReg();
74381ad6265SDimitry Andric   Register Val = I.getOperand(4).getReg();
74481ad6265SDimitry Andric   SPIRVType *SpvValTy = GR.getSPIRVTypeForVReg(Val);
745fcaf7f86SDimitry Andric   Register ACmpRes = MRI->createVirtualRegister(&SPIRV::IDRegClass);
74681ad6265SDimitry Andric   const DebugLoc &DL = I.getDebugLoc();
747fcaf7f86SDimitry Andric   bool Result =
748fcaf7f86SDimitry Andric       BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpAtomicCompareExchange))
749fcaf7f86SDimitry Andric           .addDef(ACmpRes)
75081ad6265SDimitry Andric           .addUse(GR.getSPIRVTypeID(SpvValTy))
75181ad6265SDimitry Andric           .addUse(Ptr)
75281ad6265SDimitry Andric           .addUse(ScopeReg)
75381ad6265SDimitry Andric           .addUse(MemSemEqReg)
75481ad6265SDimitry Andric           .addUse(MemSemNeqReg)
75581ad6265SDimitry Andric           .addUse(Val)
75681ad6265SDimitry Andric           .addUse(Cmp)
75781ad6265SDimitry Andric           .constrainAllUses(TII, TRI, RBI);
758fcaf7f86SDimitry Andric   Register CmpSuccReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
759fcaf7f86SDimitry Andric   SPIRVType *BoolTy = GR.getOrCreateSPIRVBoolType(I, TII);
760fcaf7f86SDimitry Andric   Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpIEqual))
761fcaf7f86SDimitry Andric                 .addDef(CmpSuccReg)
762fcaf7f86SDimitry Andric                 .addUse(GR.getSPIRVTypeID(BoolTy))
763fcaf7f86SDimitry Andric                 .addUse(ACmpRes)
764fcaf7f86SDimitry Andric                 .addUse(Cmp)
765fcaf7f86SDimitry Andric                 .constrainAllUses(TII, TRI, RBI);
766fcaf7f86SDimitry Andric   Register TmpReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
767fcaf7f86SDimitry Andric   Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
768fcaf7f86SDimitry Andric                 .addDef(TmpReg)
769fcaf7f86SDimitry Andric                 .addUse(GR.getSPIRVTypeID(ResType))
770fcaf7f86SDimitry Andric                 .addUse(ACmpRes)
771fcaf7f86SDimitry Andric                 .addUse(GR.getOrCreateUndef(I, ResType, TII))
772fcaf7f86SDimitry Andric                 .addImm(0)
773fcaf7f86SDimitry Andric                 .constrainAllUses(TII, TRI, RBI);
774fcaf7f86SDimitry Andric   Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
775fcaf7f86SDimitry Andric                 .addDef(ResVReg)
776fcaf7f86SDimitry Andric                 .addUse(GR.getSPIRVTypeID(ResType))
777fcaf7f86SDimitry Andric                 .addUse(CmpSuccReg)
778fcaf7f86SDimitry Andric                 .addUse(TmpReg)
779fcaf7f86SDimitry Andric                 .addImm(1)
780fcaf7f86SDimitry Andric                 .constrainAllUses(TII, TRI, RBI);
781fcaf7f86SDimitry Andric   return Result;
78281ad6265SDimitry Andric }
78381ad6265SDimitry Andric 
784bdd1243dSDimitry Andric static bool isGenericCastablePtr(SPIRV::StorageClass::StorageClass SC) {
78581ad6265SDimitry Andric   switch (SC) {
78681ad6265SDimitry Andric   case SPIRV::StorageClass::Workgroup:
78781ad6265SDimitry Andric   case SPIRV::StorageClass::CrossWorkgroup:
78881ad6265SDimitry Andric   case SPIRV::StorageClass::Function:
78981ad6265SDimitry Andric     return true;
79081ad6265SDimitry Andric   default:
79181ad6265SDimitry Andric     return false;
79281ad6265SDimitry Andric   }
79381ad6265SDimitry Andric }
79481ad6265SDimitry Andric 
79581ad6265SDimitry Andric // In SPIR-V address space casting can only happen to and from the Generic
79681ad6265SDimitry Andric // storage class. We can also only case Workgroup, CrossWorkgroup, or Function
79781ad6265SDimitry Andric // pointers to and from Generic pointers. As such, we can convert e.g. from
79881ad6265SDimitry Andric // Workgroup to Function by going via a Generic pointer as an intermediary. All
79981ad6265SDimitry Andric // other combinations can only be done by a bitcast, and are probably not safe.
80081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
80181ad6265SDimitry Andric                                                    const SPIRVType *ResType,
80281ad6265SDimitry Andric                                                    MachineInstr &I) const {
803fcaf7f86SDimitry Andric   // If the AddrSpaceCast user is single and in OpConstantComposite or
804fcaf7f86SDimitry Andric   // OpVariable, we should select OpSpecConstantOp.
805fcaf7f86SDimitry Andric   auto UIs = MRI->use_instructions(ResVReg);
806fcaf7f86SDimitry Andric   if (!UIs.empty() && ++UIs.begin() == UIs.end() &&
807fcaf7f86SDimitry Andric       (UIs.begin()->getOpcode() == SPIRV::OpConstantComposite ||
808fcaf7f86SDimitry Andric        UIs.begin()->getOpcode() == SPIRV::OpVariable ||
809fcaf7f86SDimitry Andric        isSpvIntrinsic(*UIs.begin(), Intrinsic::spv_init_global))) {
810fcaf7f86SDimitry Andric     Register NewReg = I.getOperand(1).getReg();
811fcaf7f86SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
812fcaf7f86SDimitry Andric     SPIRVType *SpvBaseTy = GR.getOrCreateSPIRVIntegerType(8, I, TII);
813fcaf7f86SDimitry Andric     ResType = GR.getOrCreateSPIRVPointerType(SpvBaseTy, I, TII,
814fcaf7f86SDimitry Andric                                              SPIRV::StorageClass::Generic);
815fcaf7f86SDimitry Andric     bool Result =
816fcaf7f86SDimitry Andric         BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp))
817fcaf7f86SDimitry Andric             .addDef(ResVReg)
818fcaf7f86SDimitry Andric             .addUse(GR.getSPIRVTypeID(ResType))
819fcaf7f86SDimitry Andric             .addImm(static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric))
820fcaf7f86SDimitry Andric             .addUse(NewReg)
821fcaf7f86SDimitry Andric             .constrainAllUses(TII, TRI, RBI);
822fcaf7f86SDimitry Andric     return Result;
823fcaf7f86SDimitry Andric   }
82481ad6265SDimitry Andric   Register SrcPtr = I.getOperand(1).getReg();
82581ad6265SDimitry Andric   SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
826bdd1243dSDimitry Andric   SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtr);
827bdd1243dSDimitry Andric   SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResVReg);
82881ad6265SDimitry Andric 
82981ad6265SDimitry Andric   // Casting from an eligable pointer to Generic.
83081ad6265SDimitry Andric   if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC))
83181ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
83281ad6265SDimitry Andric   // Casting from Generic to an eligable pointer.
83381ad6265SDimitry Andric   if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC))
83481ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
83581ad6265SDimitry Andric   // Casting between 2 eligable pointers using Generic as an intermediary.
83681ad6265SDimitry Andric   if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
83781ad6265SDimitry Andric     Register Tmp = MRI->createVirtualRegister(&SPIRV::IDRegClass);
83881ad6265SDimitry Andric     SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
83981ad6265SDimitry Andric         SrcPtrTy, I, TII, SPIRV::StorageClass::Generic);
84081ad6265SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
84181ad6265SDimitry Andric     const DebugLoc &DL = I.getDebugLoc();
84281ad6265SDimitry Andric     bool Success = BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric))
84381ad6265SDimitry Andric                        .addDef(Tmp)
84481ad6265SDimitry Andric                        .addUse(GR.getSPIRVTypeID(GenericPtrTy))
84581ad6265SDimitry Andric                        .addUse(SrcPtr)
84681ad6265SDimitry Andric                        .constrainAllUses(TII, TRI, RBI);
84781ad6265SDimitry Andric     return Success && BuildMI(BB, I, DL, TII.get(SPIRV::OpGenericCastToPtr))
84881ad6265SDimitry Andric                           .addDef(ResVReg)
84981ad6265SDimitry Andric                           .addUse(GR.getSPIRVTypeID(ResType))
85081ad6265SDimitry Andric                           .addUse(Tmp)
85181ad6265SDimitry Andric                           .constrainAllUses(TII, TRI, RBI);
85281ad6265SDimitry Andric   }
85381ad6265SDimitry Andric   // TODO Should this case just be disallowed completely?
85481ad6265SDimitry Andric   // We're casting 2 other arbitrary address spaces, so have to bitcast.
85581ad6265SDimitry Andric   return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast);
85681ad6265SDimitry Andric }
85781ad6265SDimitry Andric 
85881ad6265SDimitry Andric static unsigned getFCmpOpcode(unsigned PredNum) {
85981ad6265SDimitry Andric   auto Pred = static_cast<CmpInst::Predicate>(PredNum);
86081ad6265SDimitry Andric   switch (Pred) {
86181ad6265SDimitry Andric   case CmpInst::FCMP_OEQ:
86281ad6265SDimitry Andric     return SPIRV::OpFOrdEqual;
86381ad6265SDimitry Andric   case CmpInst::FCMP_OGE:
86481ad6265SDimitry Andric     return SPIRV::OpFOrdGreaterThanEqual;
86581ad6265SDimitry Andric   case CmpInst::FCMP_OGT:
86681ad6265SDimitry Andric     return SPIRV::OpFOrdGreaterThan;
86781ad6265SDimitry Andric   case CmpInst::FCMP_OLE:
86881ad6265SDimitry Andric     return SPIRV::OpFOrdLessThanEqual;
86981ad6265SDimitry Andric   case CmpInst::FCMP_OLT:
87081ad6265SDimitry Andric     return SPIRV::OpFOrdLessThan;
87181ad6265SDimitry Andric   case CmpInst::FCMP_ONE:
87281ad6265SDimitry Andric     return SPIRV::OpFOrdNotEqual;
87381ad6265SDimitry Andric   case CmpInst::FCMP_ORD:
87481ad6265SDimitry Andric     return SPIRV::OpOrdered;
87581ad6265SDimitry Andric   case CmpInst::FCMP_UEQ:
87681ad6265SDimitry Andric     return SPIRV::OpFUnordEqual;
87781ad6265SDimitry Andric   case CmpInst::FCMP_UGE:
87881ad6265SDimitry Andric     return SPIRV::OpFUnordGreaterThanEqual;
87981ad6265SDimitry Andric   case CmpInst::FCMP_UGT:
88081ad6265SDimitry Andric     return SPIRV::OpFUnordGreaterThan;
88181ad6265SDimitry Andric   case CmpInst::FCMP_ULE:
88281ad6265SDimitry Andric     return SPIRV::OpFUnordLessThanEqual;
88381ad6265SDimitry Andric   case CmpInst::FCMP_ULT:
88481ad6265SDimitry Andric     return SPIRV::OpFUnordLessThan;
88581ad6265SDimitry Andric   case CmpInst::FCMP_UNE:
88681ad6265SDimitry Andric     return SPIRV::OpFUnordNotEqual;
88781ad6265SDimitry Andric   case CmpInst::FCMP_UNO:
88881ad6265SDimitry Andric     return SPIRV::OpUnordered;
88981ad6265SDimitry Andric   default:
89081ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for FCmp");
89181ad6265SDimitry Andric   }
89281ad6265SDimitry Andric }
89381ad6265SDimitry Andric 
89481ad6265SDimitry Andric static unsigned getICmpOpcode(unsigned PredNum) {
89581ad6265SDimitry Andric   auto Pred = static_cast<CmpInst::Predicate>(PredNum);
89681ad6265SDimitry Andric   switch (Pred) {
89781ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
89881ad6265SDimitry Andric     return SPIRV::OpIEqual;
89981ad6265SDimitry Andric   case CmpInst::ICMP_NE:
90081ad6265SDimitry Andric     return SPIRV::OpINotEqual;
90181ad6265SDimitry Andric   case CmpInst::ICMP_SGE:
90281ad6265SDimitry Andric     return SPIRV::OpSGreaterThanEqual;
90381ad6265SDimitry Andric   case CmpInst::ICMP_SGT:
90481ad6265SDimitry Andric     return SPIRV::OpSGreaterThan;
90581ad6265SDimitry Andric   case CmpInst::ICMP_SLE:
90681ad6265SDimitry Andric     return SPIRV::OpSLessThanEqual;
90781ad6265SDimitry Andric   case CmpInst::ICMP_SLT:
90881ad6265SDimitry Andric     return SPIRV::OpSLessThan;
90981ad6265SDimitry Andric   case CmpInst::ICMP_UGE:
91081ad6265SDimitry Andric     return SPIRV::OpUGreaterThanEqual;
91181ad6265SDimitry Andric   case CmpInst::ICMP_UGT:
91281ad6265SDimitry Andric     return SPIRV::OpUGreaterThan;
91381ad6265SDimitry Andric   case CmpInst::ICMP_ULE:
91481ad6265SDimitry Andric     return SPIRV::OpULessThanEqual;
91581ad6265SDimitry Andric   case CmpInst::ICMP_ULT:
91681ad6265SDimitry Andric     return SPIRV::OpULessThan;
91781ad6265SDimitry Andric   default:
91881ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for ICmp");
91981ad6265SDimitry Andric   }
92081ad6265SDimitry Andric }
92181ad6265SDimitry Andric 
92281ad6265SDimitry Andric static unsigned getPtrCmpOpcode(unsigned Pred) {
92381ad6265SDimitry Andric   switch (static_cast<CmpInst::Predicate>(Pred)) {
92481ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
92581ad6265SDimitry Andric     return SPIRV::OpPtrEqual;
92681ad6265SDimitry Andric   case CmpInst::ICMP_NE:
92781ad6265SDimitry Andric     return SPIRV::OpPtrNotEqual;
92881ad6265SDimitry Andric   default:
92981ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for pointer comparison");
93081ad6265SDimitry Andric   }
93181ad6265SDimitry Andric }
93281ad6265SDimitry Andric 
93381ad6265SDimitry Andric // Return the logical operation, or abort if none exists.
93481ad6265SDimitry Andric static unsigned getBoolCmpOpcode(unsigned PredNum) {
93581ad6265SDimitry Andric   auto Pred = static_cast<CmpInst::Predicate>(PredNum);
93681ad6265SDimitry Andric   switch (Pred) {
93781ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
93881ad6265SDimitry Andric     return SPIRV::OpLogicalEqual;
93981ad6265SDimitry Andric   case CmpInst::ICMP_NE:
94081ad6265SDimitry Andric     return SPIRV::OpLogicalNotEqual;
94181ad6265SDimitry Andric   default:
94281ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for Bool comparison");
94381ad6265SDimitry Andric   }
94481ad6265SDimitry Andric }
94581ad6265SDimitry Andric 
94681ad6265SDimitry Andric bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
94781ad6265SDimitry Andric                                                 const SPIRVType *ResType,
94881ad6265SDimitry Andric                                                 MachineInstr &I) const {
94981ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
95081ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse))
95181ad6265SDimitry Andric       .addDef(ResVReg)
95281ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
95381ad6265SDimitry Andric       .addUse(I.getOperand(1).getReg())
95481ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
95581ad6265SDimitry Andric }
95681ad6265SDimitry Andric 
95781ad6265SDimitry Andric bool SPIRVInstructionSelector::selectConstVector(Register ResVReg,
95881ad6265SDimitry Andric                                                  const SPIRVType *ResType,
95981ad6265SDimitry Andric                                                  MachineInstr &I) const {
96081ad6265SDimitry Andric   // TODO: only const case is supported for now.
96181ad6265SDimitry Andric   assert(std::all_of(
96281ad6265SDimitry Andric       I.operands_begin(), I.operands_end(), [this](const MachineOperand &MO) {
96381ad6265SDimitry Andric         if (MO.isDef())
96481ad6265SDimitry Andric           return true;
96581ad6265SDimitry Andric         if (!MO.isReg())
96681ad6265SDimitry Andric           return false;
96781ad6265SDimitry Andric         SPIRVType *ConstTy = this->MRI->getVRegDef(MO.getReg());
96881ad6265SDimitry Andric         assert(ConstTy && ConstTy->getOpcode() == SPIRV::ASSIGN_TYPE &&
96981ad6265SDimitry Andric                ConstTy->getOperand(1).isReg());
97081ad6265SDimitry Andric         Register ConstReg = ConstTy->getOperand(1).getReg();
97181ad6265SDimitry Andric         const MachineInstr *Const = this->MRI->getVRegDef(ConstReg);
97281ad6265SDimitry Andric         assert(Const);
97381ad6265SDimitry Andric         return (Const->getOpcode() == TargetOpcode::G_CONSTANT ||
97481ad6265SDimitry Andric                 Const->getOpcode() == TargetOpcode::G_FCONSTANT);
97581ad6265SDimitry Andric       }));
97681ad6265SDimitry Andric 
97781ad6265SDimitry Andric   auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
97881ad6265SDimitry Andric                      TII.get(SPIRV::OpConstantComposite))
97981ad6265SDimitry Andric                  .addDef(ResVReg)
98081ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType));
98181ad6265SDimitry Andric   for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i)
98281ad6265SDimitry Andric     MIB.addUse(I.getOperand(i).getReg());
98381ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
98481ad6265SDimitry Andric }
98581ad6265SDimitry Andric 
98681ad6265SDimitry Andric bool SPIRVInstructionSelector::selectCmp(Register ResVReg,
98781ad6265SDimitry Andric                                          const SPIRVType *ResType,
98881ad6265SDimitry Andric                                          unsigned CmpOpc,
98981ad6265SDimitry Andric                                          MachineInstr &I) const {
99081ad6265SDimitry Andric   Register Cmp0 = I.getOperand(2).getReg();
99181ad6265SDimitry Andric   Register Cmp1 = I.getOperand(3).getReg();
99281ad6265SDimitry Andric   assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() ==
99381ad6265SDimitry Andric              GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() &&
99481ad6265SDimitry Andric          "CMP operands should have the same type");
99581ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(CmpOpc))
99681ad6265SDimitry Andric       .addDef(ResVReg)
99781ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
99881ad6265SDimitry Andric       .addUse(Cmp0)
99981ad6265SDimitry Andric       .addUse(Cmp1)
100081ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
100181ad6265SDimitry Andric }
100281ad6265SDimitry Andric 
100381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectICmp(Register ResVReg,
100481ad6265SDimitry Andric                                           const SPIRVType *ResType,
100581ad6265SDimitry Andric                                           MachineInstr &I) const {
100681ad6265SDimitry Andric   auto Pred = I.getOperand(1).getPredicate();
100781ad6265SDimitry Andric   unsigned CmpOpc;
100881ad6265SDimitry Andric 
100981ad6265SDimitry Andric   Register CmpOperand = I.getOperand(2).getReg();
101081ad6265SDimitry Andric   if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer))
101181ad6265SDimitry Andric     CmpOpc = getPtrCmpOpcode(Pred);
101281ad6265SDimitry Andric   else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool))
101381ad6265SDimitry Andric     CmpOpc = getBoolCmpOpcode(Pred);
101481ad6265SDimitry Andric   else
101581ad6265SDimitry Andric     CmpOpc = getICmpOpcode(Pred);
101681ad6265SDimitry Andric   return selectCmp(ResVReg, ResType, CmpOpc, I);
101781ad6265SDimitry Andric }
101881ad6265SDimitry Andric 
101981ad6265SDimitry Andric void SPIRVInstructionSelector::renderFImm32(MachineInstrBuilder &MIB,
102081ad6265SDimitry Andric                                             const MachineInstr &I,
102181ad6265SDimitry Andric                                             int OpIdx) const {
102281ad6265SDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
102381ad6265SDimitry Andric          "Expected G_FCONSTANT");
102481ad6265SDimitry Andric   const ConstantFP *FPImm = I.getOperand(1).getFPImm();
102581ad6265SDimitry Andric   addNumImm(FPImm->getValueAPF().bitcastToAPInt(), MIB);
102681ad6265SDimitry Andric }
102781ad6265SDimitry Andric 
102881ad6265SDimitry Andric void SPIRVInstructionSelector::renderImm32(MachineInstrBuilder &MIB,
102981ad6265SDimitry Andric                                            const MachineInstr &I,
103081ad6265SDimitry Andric                                            int OpIdx) const {
103181ad6265SDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
103281ad6265SDimitry Andric          "Expected G_CONSTANT");
103381ad6265SDimitry Andric   addNumImm(I.getOperand(1).getCImm()->getValue(), MIB);
103481ad6265SDimitry Andric }
103581ad6265SDimitry Andric 
103681ad6265SDimitry Andric Register
103781ad6265SDimitry Andric SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I,
103881ad6265SDimitry Andric                                            const SPIRVType *ResType) const {
1039753f127fSDimitry Andric   Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32);
104081ad6265SDimitry Andric   const SPIRVType *SpvI32Ty =
104181ad6265SDimitry Andric       ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII);
1042753f127fSDimitry Andric   // Find a constant in DT or build a new one.
1043753f127fSDimitry Andric   auto ConstInt = ConstantInt::get(LLVMTy, Val);
1044753f127fSDimitry Andric   Register NewReg = GR.find(ConstInt, GR.CurMF);
1045753f127fSDimitry Andric   if (!NewReg.isValid()) {
104681ad6265SDimitry Andric     NewReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
1047753f127fSDimitry Andric     GR.add(ConstInt, GR.CurMF, NewReg);
104881ad6265SDimitry Andric     MachineInstr *MI;
104981ad6265SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
105081ad6265SDimitry Andric     if (Val == 0) {
105181ad6265SDimitry Andric       MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
105281ad6265SDimitry Andric                .addDef(NewReg)
105381ad6265SDimitry Andric                .addUse(GR.getSPIRVTypeID(SpvI32Ty));
105481ad6265SDimitry Andric     } else {
105581ad6265SDimitry Andric       MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
105681ad6265SDimitry Andric                .addDef(NewReg)
105781ad6265SDimitry Andric                .addUse(GR.getSPIRVTypeID(SpvI32Ty))
105881ad6265SDimitry Andric                .addImm(APInt(32, Val).getZExtValue());
105981ad6265SDimitry Andric     }
106081ad6265SDimitry Andric     constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
1061753f127fSDimitry Andric   }
106281ad6265SDimitry Andric   return NewReg;
106381ad6265SDimitry Andric }
106481ad6265SDimitry Andric 
106581ad6265SDimitry Andric bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
106681ad6265SDimitry Andric                                           const SPIRVType *ResType,
106781ad6265SDimitry Andric                                           MachineInstr &I) const {
106881ad6265SDimitry Andric   unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate());
106981ad6265SDimitry Andric   return selectCmp(ResVReg, ResType, CmpOp, I);
107081ad6265SDimitry Andric }
107181ad6265SDimitry Andric 
107281ad6265SDimitry Andric Register SPIRVInstructionSelector::buildZerosVal(const SPIRVType *ResType,
107381ad6265SDimitry Andric                                                  MachineInstr &I) const {
1074fcaf7f86SDimitry Andric   if (ResType->getOpcode() == SPIRV::OpTypeVector)
1075fcaf7f86SDimitry Andric     return GR.getOrCreateConsIntVector(0, I, ResType, TII);
1076fcaf7f86SDimitry Andric   return GR.getOrCreateConstInt(0, I, ResType, TII);
107781ad6265SDimitry Andric }
107881ad6265SDimitry Andric 
107981ad6265SDimitry Andric Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
108081ad6265SDimitry Andric                                                 const SPIRVType *ResType,
108181ad6265SDimitry Andric                                                 MachineInstr &I) const {
108281ad6265SDimitry Andric   unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
1083*06c3fb27SDimitry Andric   APInt One =
1084*06c3fb27SDimitry Andric       AllOnes ? APInt::getAllOnes(BitWidth) : APInt::getOneBitSet(BitWidth, 0);
1085fcaf7f86SDimitry Andric   if (ResType->getOpcode() == SPIRV::OpTypeVector)
1086fcaf7f86SDimitry Andric     return GR.getOrCreateConsIntVector(One.getZExtValue(), I, ResType, TII);
1087fcaf7f86SDimitry Andric   return GR.getOrCreateConstInt(One.getZExtValue(), I, ResType, TII);
108881ad6265SDimitry Andric }
108981ad6265SDimitry Andric 
109081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectSelect(Register ResVReg,
109181ad6265SDimitry Andric                                             const SPIRVType *ResType,
109281ad6265SDimitry Andric                                             MachineInstr &I,
109381ad6265SDimitry Andric                                             bool IsSigned) const {
109481ad6265SDimitry Andric   // To extend a bool, we need to use OpSelect between constants.
109581ad6265SDimitry Andric   Register ZeroReg = buildZerosVal(ResType, I);
109681ad6265SDimitry Andric   Register OneReg = buildOnesVal(IsSigned, ResType, I);
109781ad6265SDimitry Andric   bool IsScalarBool =
109881ad6265SDimitry Andric       GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool);
109981ad6265SDimitry Andric   unsigned Opcode =
110081ad6265SDimitry Andric       IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectSIVCond;
110181ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
110281ad6265SDimitry Andric       .addDef(ResVReg)
110381ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
110481ad6265SDimitry Andric       .addUse(I.getOperand(1).getReg())
110581ad6265SDimitry Andric       .addUse(OneReg)
110681ad6265SDimitry Andric       .addUse(ZeroReg)
110781ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
110881ad6265SDimitry Andric }
110981ad6265SDimitry Andric 
111081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectIToF(Register ResVReg,
111181ad6265SDimitry Andric                                           const SPIRVType *ResType,
111281ad6265SDimitry Andric                                           MachineInstr &I, bool IsSigned,
111381ad6265SDimitry Andric                                           unsigned Opcode) const {
111481ad6265SDimitry Andric   Register SrcReg = I.getOperand(1).getReg();
111581ad6265SDimitry Andric   // We can convert bool value directly to float type without OpConvert*ToF,
111681ad6265SDimitry Andric   // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
111781ad6265SDimitry Andric   if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) {
111881ad6265SDimitry Andric     unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
111981ad6265SDimitry Andric     SPIRVType *TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII);
112081ad6265SDimitry Andric     if (ResType->getOpcode() == SPIRV::OpTypeVector) {
112181ad6265SDimitry Andric       const unsigned NumElts = ResType->getOperand(2).getImm();
112281ad6265SDimitry Andric       TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII);
112381ad6265SDimitry Andric     }
112481ad6265SDimitry Andric     SrcReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
112581ad6265SDimitry Andric     selectSelect(SrcReg, TmpType, I, false);
112681ad6265SDimitry Andric   }
112781ad6265SDimitry Andric   return selectUnOpWithSrc(ResVReg, ResType, I, SrcReg, Opcode);
112881ad6265SDimitry Andric }
112981ad6265SDimitry Andric 
113081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectExt(Register ResVReg,
113181ad6265SDimitry Andric                                          const SPIRVType *ResType,
113281ad6265SDimitry Andric                                          MachineInstr &I, bool IsSigned) const {
113381ad6265SDimitry Andric   if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool))
113481ad6265SDimitry Andric     return selectSelect(ResVReg, ResType, I, IsSigned);
113581ad6265SDimitry Andric   unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
113681ad6265SDimitry Andric   return selectUnOp(ResVReg, ResType, I, Opcode);
113781ad6265SDimitry Andric }
113881ad6265SDimitry Andric 
113981ad6265SDimitry Andric bool SPIRVInstructionSelector::selectIntToBool(Register IntReg,
114081ad6265SDimitry Andric                                                Register ResVReg,
1141bdd1243dSDimitry Andric                                                MachineInstr &I,
114281ad6265SDimitry Andric                                                const SPIRVType *IntTy,
1143bdd1243dSDimitry Andric                                                const SPIRVType *BoolTy) const {
114481ad6265SDimitry Andric   // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
114581ad6265SDimitry Andric   Register BitIntReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
114681ad6265SDimitry Andric   bool IsVectorTy = IntTy->getOpcode() == SPIRV::OpTypeVector;
114781ad6265SDimitry Andric   unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
114881ad6265SDimitry Andric   Register Zero = buildZerosVal(IntTy, I);
114981ad6265SDimitry Andric   Register One = buildOnesVal(false, IntTy, I);
115081ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
115181ad6265SDimitry Andric   BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
115281ad6265SDimitry Andric       .addDef(BitIntReg)
115381ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(IntTy))
115481ad6265SDimitry Andric       .addUse(IntReg)
115581ad6265SDimitry Andric       .addUse(One)
115681ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
115781ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
115881ad6265SDimitry Andric       .addDef(ResVReg)
115981ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(BoolTy))
116081ad6265SDimitry Andric       .addUse(BitIntReg)
116181ad6265SDimitry Andric       .addUse(Zero)
116281ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
116381ad6265SDimitry Andric }
116481ad6265SDimitry Andric 
116581ad6265SDimitry Andric bool SPIRVInstructionSelector::selectTrunc(Register ResVReg,
116681ad6265SDimitry Andric                                            const SPIRVType *ResType,
116781ad6265SDimitry Andric                                            MachineInstr &I) const {
116881ad6265SDimitry Andric   if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool)) {
116981ad6265SDimitry Andric     Register IntReg = I.getOperand(1).getReg();
117081ad6265SDimitry Andric     const SPIRVType *ArgType = GR.getSPIRVTypeForVReg(IntReg);
1171bdd1243dSDimitry Andric     return selectIntToBool(IntReg, ResVReg, I, ArgType, ResType);
117281ad6265SDimitry Andric   }
117381ad6265SDimitry Andric   bool IsSigned = GR.isScalarOrVectorSigned(ResType);
117481ad6265SDimitry Andric   unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
117581ad6265SDimitry Andric   return selectUnOp(ResVReg, ResType, I, Opcode);
117681ad6265SDimitry Andric }
117781ad6265SDimitry Andric 
117881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectConst(Register ResVReg,
117981ad6265SDimitry Andric                                            const SPIRVType *ResType,
118081ad6265SDimitry Andric                                            const APInt &Imm,
118181ad6265SDimitry Andric                                            MachineInstr &I) const {
1182fcaf7f86SDimitry Andric   unsigned TyOpcode = ResType->getOpcode();
1183*06c3fb27SDimitry Andric   assert(TyOpcode != SPIRV::OpTypePointer || Imm.isZero());
118481ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
1185fcaf7f86SDimitry Andric   if ((TyOpcode == SPIRV::OpTypePointer || TyOpcode == SPIRV::OpTypeEvent) &&
1186*06c3fb27SDimitry Andric       Imm.isZero())
118781ad6265SDimitry Andric     return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
118881ad6265SDimitry Andric         .addDef(ResVReg)
118981ad6265SDimitry Andric         .addUse(GR.getSPIRVTypeID(ResType))
119081ad6265SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
1191fcaf7f86SDimitry Andric   if (TyOpcode == SPIRV::OpTypeInt) {
1192*06c3fb27SDimitry Andric     assert(Imm.getBitWidth() <= 64 && "Unsupported integer width!");
1193fcaf7f86SDimitry Andric     Register Reg = GR.getOrCreateConstInt(Imm.getZExtValue(), I, ResType, TII);
1194fcaf7f86SDimitry Andric     if (Reg == ResVReg)
1195fcaf7f86SDimitry Andric       return true;
1196fcaf7f86SDimitry Andric     return BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY))
1197fcaf7f86SDimitry Andric         .addDef(ResVReg)
1198fcaf7f86SDimitry Andric         .addUse(Reg)
1199fcaf7f86SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
120081ad6265SDimitry Andric   }
120181ad6265SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
120281ad6265SDimitry Andric                  .addDef(ResVReg)
120381ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType));
120481ad6265SDimitry Andric   // <=32-bit integers should be caught by the sdag pattern.
120581ad6265SDimitry Andric   assert(Imm.getBitWidth() > 32);
120681ad6265SDimitry Andric   addNumImm(Imm, MIB);
120781ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
120881ad6265SDimitry Andric }
120981ad6265SDimitry Andric 
121081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg,
121181ad6265SDimitry Andric                                              const SPIRVType *ResType,
121281ad6265SDimitry Andric                                              MachineInstr &I) const {
121381ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
121481ad6265SDimitry Andric       .addDef(ResVReg)
121581ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
121681ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
121781ad6265SDimitry Andric }
121881ad6265SDimitry Andric 
121981ad6265SDimitry Andric static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI) {
122081ad6265SDimitry Andric   assert(MO.isReg());
122181ad6265SDimitry Andric   const SPIRVType *TypeInst = MRI->getVRegDef(MO.getReg());
122281ad6265SDimitry Andric   if (TypeInst->getOpcode() != SPIRV::ASSIGN_TYPE)
122381ad6265SDimitry Andric     return false;
122481ad6265SDimitry Andric   assert(TypeInst->getOperand(1).isReg());
122581ad6265SDimitry Andric   MachineInstr *ImmInst = MRI->getVRegDef(TypeInst->getOperand(1).getReg());
122681ad6265SDimitry Andric   return ImmInst->getOpcode() == TargetOpcode::G_CONSTANT;
122781ad6265SDimitry Andric }
122881ad6265SDimitry Andric 
122981ad6265SDimitry Andric static int64_t foldImm(const MachineOperand &MO, MachineRegisterInfo *MRI) {
123081ad6265SDimitry Andric   const SPIRVType *TypeInst = MRI->getVRegDef(MO.getReg());
123181ad6265SDimitry Andric   MachineInstr *ImmInst = MRI->getVRegDef(TypeInst->getOperand(1).getReg());
123281ad6265SDimitry Andric   assert(ImmInst->getOpcode() == TargetOpcode::G_CONSTANT);
123381ad6265SDimitry Andric   return ImmInst->getOperand(1).getCImm()->getZExtValue();
123481ad6265SDimitry Andric }
123581ad6265SDimitry Andric 
123681ad6265SDimitry Andric bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg,
123781ad6265SDimitry Andric                                                const SPIRVType *ResType,
123881ad6265SDimitry Andric                                                MachineInstr &I) const {
123981ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
1240fcaf7f86SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeInsert))
124181ad6265SDimitry Andric                  .addDef(ResVReg)
124281ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
124381ad6265SDimitry Andric                  // object to insert
124481ad6265SDimitry Andric                  .addUse(I.getOperand(3).getReg())
124581ad6265SDimitry Andric                  // composite to insert into
1246fcaf7f86SDimitry Andric                  .addUse(I.getOperand(2).getReg());
1247fcaf7f86SDimitry Andric   for (unsigned i = 4; i < I.getNumOperands(); i++)
1248fcaf7f86SDimitry Andric     MIB.addImm(foldImm(I.getOperand(i), MRI));
1249fcaf7f86SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
125081ad6265SDimitry Andric }
125181ad6265SDimitry Andric 
125281ad6265SDimitry Andric bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg,
125381ad6265SDimitry Andric                                                 const SPIRVType *ResType,
125481ad6265SDimitry Andric                                                 MachineInstr &I) const {
125581ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
1256fcaf7f86SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
125781ad6265SDimitry Andric                  .addDef(ResVReg)
125881ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
1259fcaf7f86SDimitry Andric                  .addUse(I.getOperand(2).getReg());
1260fcaf7f86SDimitry Andric   for (unsigned i = 3; i < I.getNumOperands(); i++)
1261fcaf7f86SDimitry Andric     MIB.addImm(foldImm(I.getOperand(i), MRI));
1262fcaf7f86SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
126381ad6265SDimitry Andric }
126481ad6265SDimitry Andric 
126581ad6265SDimitry Andric bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg,
126681ad6265SDimitry Andric                                                const SPIRVType *ResType,
126781ad6265SDimitry Andric                                                MachineInstr &I) const {
126881ad6265SDimitry Andric   if (isImm(I.getOperand(4), MRI))
126981ad6265SDimitry Andric     return selectInsertVal(ResVReg, ResType, I);
127081ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
127181ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorInsertDynamic))
127281ad6265SDimitry Andric       .addDef(ResVReg)
127381ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
127481ad6265SDimitry Andric       .addUse(I.getOperand(2).getReg())
127581ad6265SDimitry Andric       .addUse(I.getOperand(3).getReg())
127681ad6265SDimitry Andric       .addUse(I.getOperand(4).getReg())
127781ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
127881ad6265SDimitry Andric }
127981ad6265SDimitry Andric 
128081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg,
128181ad6265SDimitry Andric                                                 const SPIRVType *ResType,
128281ad6265SDimitry Andric                                                 MachineInstr &I) const {
128381ad6265SDimitry Andric   if (isImm(I.getOperand(3), MRI))
128481ad6265SDimitry Andric     return selectExtractVal(ResVReg, ResType, I);
128581ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
128681ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorExtractDynamic))
128781ad6265SDimitry Andric       .addDef(ResVReg)
128881ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
128981ad6265SDimitry Andric       .addUse(I.getOperand(2).getReg())
129081ad6265SDimitry Andric       .addUse(I.getOperand(3).getReg())
129181ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
129281ad6265SDimitry Andric }
129381ad6265SDimitry Andric 
129481ad6265SDimitry Andric bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
129581ad6265SDimitry Andric                                          const SPIRVType *ResType,
129681ad6265SDimitry Andric                                          MachineInstr &I) const {
129781ad6265SDimitry Andric   // In general we should also support OpAccessChain instrs here (i.e. not
129881ad6265SDimitry Andric   // PtrAccessChain) but SPIRV-LLVM Translator doesn't emit them at all and so
129981ad6265SDimitry Andric   // do we to stay compliant with its test and more importantly consumers.
130081ad6265SDimitry Andric   unsigned Opcode = I.getOperand(2).getImm() ? SPIRV::OpInBoundsPtrAccessChain
130181ad6265SDimitry Andric                                              : SPIRV::OpPtrAccessChain;
130281ad6265SDimitry Andric   auto Res = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
130381ad6265SDimitry Andric                  .addDef(ResVReg)
130481ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
130581ad6265SDimitry Andric                  // Object to get a pointer to.
130681ad6265SDimitry Andric                  .addUse(I.getOperand(3).getReg());
130781ad6265SDimitry Andric   // Adding indices.
130881ad6265SDimitry Andric   for (unsigned i = 4; i < I.getNumExplicitOperands(); ++i)
130981ad6265SDimitry Andric     Res.addUse(I.getOperand(i).getReg());
131081ad6265SDimitry Andric   return Res.constrainAllUses(TII, TRI, RBI);
131181ad6265SDimitry Andric }
131281ad6265SDimitry Andric 
131381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
131481ad6265SDimitry Andric                                                const SPIRVType *ResType,
131581ad6265SDimitry Andric                                                MachineInstr &I) const {
131681ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
131781ad6265SDimitry Andric   switch (I.getIntrinsicID()) {
131881ad6265SDimitry Andric   case Intrinsic::spv_load:
131981ad6265SDimitry Andric     return selectLoad(ResVReg, ResType, I);
132081ad6265SDimitry Andric   case Intrinsic::spv_store:
132181ad6265SDimitry Andric     return selectStore(I);
132281ad6265SDimitry Andric   case Intrinsic::spv_extractv:
132381ad6265SDimitry Andric     return selectExtractVal(ResVReg, ResType, I);
132481ad6265SDimitry Andric   case Intrinsic::spv_insertv:
132581ad6265SDimitry Andric     return selectInsertVal(ResVReg, ResType, I);
132681ad6265SDimitry Andric   case Intrinsic::spv_extractelt:
132781ad6265SDimitry Andric     return selectExtractElt(ResVReg, ResType, I);
132881ad6265SDimitry Andric   case Intrinsic::spv_insertelt:
132981ad6265SDimitry Andric     return selectInsertElt(ResVReg, ResType, I);
133081ad6265SDimitry Andric   case Intrinsic::spv_gep:
133181ad6265SDimitry Andric     return selectGEP(ResVReg, ResType, I);
133281ad6265SDimitry Andric   case Intrinsic::spv_unref_global:
133381ad6265SDimitry Andric   case Intrinsic::spv_init_global: {
133481ad6265SDimitry Andric     MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());
133581ad6265SDimitry Andric     MachineInstr *Init = I.getNumExplicitOperands() > 2
133681ad6265SDimitry Andric                              ? MRI->getVRegDef(I.getOperand(2).getReg())
133781ad6265SDimitry Andric                              : nullptr;
133881ad6265SDimitry Andric     assert(MI);
133981ad6265SDimitry Andric     return selectGlobalValue(MI->getOperand(0).getReg(), *MI, Init);
1340*06c3fb27SDimitry Andric   }
1341*06c3fb27SDimitry Andric   case Intrinsic::spv_undef: {
1342*06c3fb27SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
1343*06c3fb27SDimitry Andric                    .addDef(ResVReg)
1344*06c3fb27SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType));
1345*06c3fb27SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
1346*06c3fb27SDimitry Andric   }
134781ad6265SDimitry Andric   case Intrinsic::spv_const_composite: {
134881ad6265SDimitry Andric     // If no values are attached, the composite is null constant.
134981ad6265SDimitry Andric     bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
135081ad6265SDimitry Andric     unsigned Opcode =
135181ad6265SDimitry Andric         IsNull ? SPIRV::OpConstantNull : SPIRV::OpConstantComposite;
135281ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
135381ad6265SDimitry Andric                    .addDef(ResVReg)
135481ad6265SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType));
135581ad6265SDimitry Andric     // skip type MD node we already used when generated assign.type for this
135681ad6265SDimitry Andric     if (!IsNull) {
135781ad6265SDimitry Andric       for (unsigned i = I.getNumExplicitDefs() + 1;
135881ad6265SDimitry Andric            i < I.getNumExplicitOperands(); ++i) {
135981ad6265SDimitry Andric         MIB.addUse(I.getOperand(i).getReg());
136081ad6265SDimitry Andric       }
136181ad6265SDimitry Andric     }
136281ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
1363*06c3fb27SDimitry Andric   }
136481ad6265SDimitry Andric   case Intrinsic::spv_assign_name: {
136581ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName));
136681ad6265SDimitry Andric     MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg());
136781ad6265SDimitry Andric     for (unsigned i = I.getNumExplicitDefs() + 2;
136881ad6265SDimitry Andric          i < I.getNumExplicitOperands(); ++i) {
136981ad6265SDimitry Andric       MIB.addImm(I.getOperand(i).getImm());
137081ad6265SDimitry Andric     }
137181ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
1372*06c3fb27SDimitry Andric   }
137381ad6265SDimitry Andric   case Intrinsic::spv_switch: {
137481ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch));
137581ad6265SDimitry Andric     for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
137681ad6265SDimitry Andric       if (I.getOperand(i).isReg())
137781ad6265SDimitry Andric         MIB.addReg(I.getOperand(i).getReg());
137881ad6265SDimitry Andric       else if (I.getOperand(i).isCImm())
137981ad6265SDimitry Andric         addNumImm(I.getOperand(i).getCImm()->getValue(), MIB);
138081ad6265SDimitry Andric       else if (I.getOperand(i).isMBB())
138181ad6265SDimitry Andric         MIB.addMBB(I.getOperand(i).getMBB());
138281ad6265SDimitry Andric       else
138381ad6265SDimitry Andric         llvm_unreachable("Unexpected OpSwitch operand");
138481ad6265SDimitry Andric     }
138581ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
1386*06c3fb27SDimitry Andric   }
1387fcaf7f86SDimitry Andric   case Intrinsic::spv_cmpxchg:
1388fcaf7f86SDimitry Andric     return selectAtomicCmpXchg(ResVReg, ResType, I);
1389bdd1243dSDimitry Andric   case Intrinsic::spv_unreachable:
1390bdd1243dSDimitry Andric     BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUnreachable));
1391bdd1243dSDimitry Andric     break;
1392bdd1243dSDimitry Andric   case Intrinsic::spv_alloca:
1393bdd1243dSDimitry Andric     return selectFrameIndex(ResVReg, ResType, I);
139481ad6265SDimitry Andric   default:
139581ad6265SDimitry Andric     llvm_unreachable("Intrinsic selection not implemented");
139681ad6265SDimitry Andric   }
139781ad6265SDimitry Andric   return true;
139881ad6265SDimitry Andric }
139981ad6265SDimitry Andric 
140081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg,
140181ad6265SDimitry Andric                                                 const SPIRVType *ResType,
140281ad6265SDimitry Andric                                                 MachineInstr &I) const {
140381ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
140481ad6265SDimitry Andric       .addDef(ResVReg)
140581ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
140681ad6265SDimitry Andric       .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
140781ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
140881ad6265SDimitry Andric }
140981ad6265SDimitry Andric 
141081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const {
141181ad6265SDimitry Andric   // InstructionSelector walks backwards through the instructions. We can use
141281ad6265SDimitry Andric   // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
141381ad6265SDimitry Andric   // first, so can generate an OpBranchConditional here. If there is no
141481ad6265SDimitry Andric   // G_BRCOND, we just use OpBranch for a regular unconditional branch.
141581ad6265SDimitry Andric   const MachineInstr *PrevI = I.getPrevNode();
141681ad6265SDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
141781ad6265SDimitry Andric   if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) {
141881ad6265SDimitry Andric     return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
141981ad6265SDimitry Andric         .addUse(PrevI->getOperand(0).getReg())
142081ad6265SDimitry Andric         .addMBB(PrevI->getOperand(1).getMBB())
142181ad6265SDimitry Andric         .addMBB(I.getOperand(0).getMBB())
142281ad6265SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
142381ad6265SDimitry Andric   }
142481ad6265SDimitry Andric   return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch))
142581ad6265SDimitry Andric       .addMBB(I.getOperand(0).getMBB())
142681ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
142781ad6265SDimitry Andric }
142881ad6265SDimitry Andric 
142981ad6265SDimitry Andric bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const {
143081ad6265SDimitry Andric   // InstructionSelector walks backwards through the instructions. For an
143181ad6265SDimitry Andric   // explicit conditional branch with no fallthrough, we use both a G_BR and a
143281ad6265SDimitry Andric   // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
143381ad6265SDimitry Andric   // generate the OpBranchConditional in selectBranch above.
143481ad6265SDimitry Andric   //
143581ad6265SDimitry Andric   // If an OpBranchConditional has been generated, we simply return, as the work
143681ad6265SDimitry Andric   // is alread done. If there is no OpBranchConditional, LLVM must be relying on
143781ad6265SDimitry Andric   // implicit fallthrough to the next basic block, so we need to create an
143881ad6265SDimitry Andric   // OpBranchConditional with an explicit "false" argument pointing to the next
143981ad6265SDimitry Andric   // basic block that LLVM would fall through to.
144081ad6265SDimitry Andric   const MachineInstr *NextI = I.getNextNode();
144181ad6265SDimitry Andric   // Check if this has already been successfully selected.
144281ad6265SDimitry Andric   if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional)
144381ad6265SDimitry Andric     return true;
144481ad6265SDimitry Andric   // Must be relying on implicit block fallthrough, so generate an
144581ad6265SDimitry Andric   // OpBranchConditional with the "next" basic block as the "false" target.
144681ad6265SDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
144781ad6265SDimitry Andric   unsigned NextMBBNum = MBB.getNextNode()->getNumber();
144881ad6265SDimitry Andric   MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum);
144981ad6265SDimitry Andric   return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
145081ad6265SDimitry Andric       .addUse(I.getOperand(0).getReg())
145181ad6265SDimitry Andric       .addMBB(I.getOperand(1).getMBB())
145281ad6265SDimitry Andric       .addMBB(NextMBB)
145381ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
145481ad6265SDimitry Andric }
145581ad6265SDimitry Andric 
145681ad6265SDimitry Andric bool SPIRVInstructionSelector::selectPhi(Register ResVReg,
145781ad6265SDimitry Andric                                          const SPIRVType *ResType,
145881ad6265SDimitry Andric                                          MachineInstr &I) const {
145981ad6265SDimitry Andric   auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpPhi))
146081ad6265SDimitry Andric                  .addDef(ResVReg)
146181ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType));
146281ad6265SDimitry Andric   const unsigned NumOps = I.getNumOperands();
146381ad6265SDimitry Andric   for (unsigned i = 1; i < NumOps; i += 2) {
146481ad6265SDimitry Andric     MIB.addUse(I.getOperand(i + 0).getReg());
146581ad6265SDimitry Andric     MIB.addMBB(I.getOperand(i + 1).getMBB());
146681ad6265SDimitry Andric   }
146781ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
146881ad6265SDimitry Andric }
146981ad6265SDimitry Andric 
147081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectGlobalValue(
147181ad6265SDimitry Andric     Register ResVReg, MachineInstr &I, const MachineInstr *Init) const {
147281ad6265SDimitry Andric   // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
147381ad6265SDimitry Andric   MachineIRBuilder MIRBuilder(I);
147481ad6265SDimitry Andric   const GlobalValue *GV = I.getOperand(1).getGlobal();
147581ad6265SDimitry Andric   SPIRVType *ResType = GR.getOrCreateSPIRVType(
147681ad6265SDimitry Andric       GV->getType(), MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false);
147781ad6265SDimitry Andric 
147881ad6265SDimitry Andric   std::string GlobalIdent = GV->getGlobalIdentifier();
1479fcaf7f86SDimitry Andric   // We have functions as operands in tests with blocks of instruction e.g. in
1480fcaf7f86SDimitry Andric   // transcoding/global_block.ll. These operands are not used and should be
1481fcaf7f86SDimitry Andric   // substituted by zero constants. Their type is expected to be always
1482fcaf7f86SDimitry Andric   // OpTypePointer Function %uchar.
1483fcaf7f86SDimitry Andric   if (isa<Function>(GV)) {
1484fcaf7f86SDimitry Andric     const Constant *ConstVal = GV;
1485fcaf7f86SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
1486fcaf7f86SDimitry Andric     Register NewReg = GR.find(ConstVal, GR.CurMF);
1487fcaf7f86SDimitry Andric     if (!NewReg.isValid()) {
1488fcaf7f86SDimitry Andric       SPIRVType *SpvBaseTy = GR.getOrCreateSPIRVIntegerType(8, I, TII);
1489fcaf7f86SDimitry Andric       ResType = GR.getOrCreateSPIRVPointerType(SpvBaseTy, I, TII);
1490fcaf7f86SDimitry Andric       Register NewReg = ResVReg;
1491fcaf7f86SDimitry Andric       GR.add(ConstVal, GR.CurMF, NewReg);
1492fcaf7f86SDimitry Andric       return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
1493fcaf7f86SDimitry Andric           .addDef(NewReg)
1494fcaf7f86SDimitry Andric           .addUse(GR.getSPIRVTypeID(ResType))
1495fcaf7f86SDimitry Andric           .constrainAllUses(TII, TRI, RBI);
1496fcaf7f86SDimitry Andric     }
1497fcaf7f86SDimitry Andric     assert(NewReg != ResVReg);
1498fcaf7f86SDimitry Andric     return BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY))
1499fcaf7f86SDimitry Andric         .addDef(ResVReg)
1500fcaf7f86SDimitry Andric         .addUse(NewReg)
1501fcaf7f86SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
1502fcaf7f86SDimitry Andric   }
150381ad6265SDimitry Andric   auto GlobalVar = cast<GlobalVariable>(GV);
1504fcaf7f86SDimitry Andric   assert(GlobalVar->getName() != "llvm.global.annotations");
150581ad6265SDimitry Andric 
150681ad6265SDimitry Andric   bool HasInit = GlobalVar->hasInitializer() &&
150781ad6265SDimitry Andric                  !isa<UndefValue>(GlobalVar->getInitializer());
150881ad6265SDimitry Andric   // Skip empty declaration for GVs with initilaizers till we get the decl with
150981ad6265SDimitry Andric   // passed initializer.
151081ad6265SDimitry Andric   if (HasInit && !Init)
151181ad6265SDimitry Andric     return true;
151281ad6265SDimitry Andric 
151381ad6265SDimitry Andric   unsigned AddrSpace = GV->getAddressSpace();
1514bdd1243dSDimitry Andric   SPIRV::StorageClass::StorageClass Storage =
1515bdd1243dSDimitry Andric       addressSpaceToStorageClass(AddrSpace);
151681ad6265SDimitry Andric   bool HasLnkTy = GV->getLinkage() != GlobalValue::InternalLinkage &&
151781ad6265SDimitry Andric                   Storage != SPIRV::StorageClass::Function;
1518bdd1243dSDimitry Andric   SPIRV::LinkageType::LinkageType LnkType =
151981ad6265SDimitry Andric       (GV->isDeclaration() || GV->hasAvailableExternallyLinkage())
152081ad6265SDimitry Andric           ? SPIRV::LinkageType::Import
152181ad6265SDimitry Andric           : SPIRV::LinkageType::Export;
152281ad6265SDimitry Andric 
152381ad6265SDimitry Andric   Register Reg = GR.buildGlobalVariable(ResVReg, ResType, GlobalIdent, GV,
152481ad6265SDimitry Andric                                         Storage, Init, GlobalVar->isConstant(),
152581ad6265SDimitry Andric                                         HasLnkTy, LnkType, MIRBuilder, true);
152681ad6265SDimitry Andric   return Reg.isValid();
152781ad6265SDimitry Andric }
152881ad6265SDimitry Andric 
152981ad6265SDimitry Andric namespace llvm {
153081ad6265SDimitry Andric InstructionSelector *
153181ad6265SDimitry Andric createSPIRVInstructionSelector(const SPIRVTargetMachine &TM,
153281ad6265SDimitry Andric                                const SPIRVSubtarget &Subtarget,
153381ad6265SDimitry Andric                                const RegisterBankInfo &RBI) {
153481ad6265SDimitry Andric   return new SPIRVInstructionSelector(TM, Subtarget, RBI);
153581ad6265SDimitry Andric }
153681ad6265SDimitry Andric } // namespace llvm
1537