xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (revision 753f127f3ace09432b2baeffd71a308760641a62)
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"
2381ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
2481ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.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;
3381ad6265SDimitry Andric 
3481ad6265SDimitry Andric namespace {
3581ad6265SDimitry Andric 
3681ad6265SDimitry Andric #define GET_GLOBALISEL_PREDICATE_BITSET
3781ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
3881ad6265SDimitry Andric #undef GET_GLOBALISEL_PREDICATE_BITSET
3981ad6265SDimitry Andric 
4081ad6265SDimitry Andric class SPIRVInstructionSelector : public InstructionSelector {
4181ad6265SDimitry Andric   const SPIRVSubtarget &STI;
4281ad6265SDimitry Andric   const SPIRVInstrInfo &TII;
4381ad6265SDimitry Andric   const SPIRVRegisterInfo &TRI;
4481ad6265SDimitry Andric   const RegisterBankInfo &RBI;
4581ad6265SDimitry Andric   SPIRVGlobalRegistry &GR;
4681ad6265SDimitry Andric   MachineRegisterInfo *MRI;
4781ad6265SDimitry Andric 
4881ad6265SDimitry Andric public:
4981ad6265SDimitry Andric   SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
5081ad6265SDimitry Andric                            const SPIRVSubtarget &ST,
5181ad6265SDimitry Andric                            const RegisterBankInfo &RBI);
5281ad6265SDimitry Andric   void setupMF(MachineFunction &MF, GISelKnownBits *KB,
5381ad6265SDimitry Andric                CodeGenCoverage &CoverageInfo, ProfileSummaryInfo *PSI,
5481ad6265SDimitry Andric                BlockFrequencyInfo *BFI) override;
5581ad6265SDimitry Andric   // Common selection code. Instruction-specific selection occurs in spvSelect.
5681ad6265SDimitry Andric   bool select(MachineInstr &I) override;
5781ad6265SDimitry Andric   static const char *getName() { return DEBUG_TYPE; }
5881ad6265SDimitry Andric 
5981ad6265SDimitry Andric #define GET_GLOBALISEL_PREDICATES_DECL
6081ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
6181ad6265SDimitry Andric #undef GET_GLOBALISEL_PREDICATES_DECL
6281ad6265SDimitry Andric 
6381ad6265SDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_DECL
6481ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
6581ad6265SDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_DECL
6681ad6265SDimitry Andric 
6781ad6265SDimitry Andric private:
6881ad6265SDimitry Andric   // tblgen-erated 'select' implementation, used as the initial selector for
6981ad6265SDimitry Andric   // the patterns that don't require complex C++.
7081ad6265SDimitry Andric   bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
7181ad6265SDimitry Andric 
7281ad6265SDimitry Andric   // All instruction-specific selection that didn't happen in "select()".
7381ad6265SDimitry Andric   // Is basically a large Switch/Case delegating to all other select method.
7481ad6265SDimitry Andric   bool spvSelect(Register ResVReg, const SPIRVType *ResType,
7581ad6265SDimitry Andric                  MachineInstr &I) const;
7681ad6265SDimitry Andric 
7781ad6265SDimitry Andric   bool selectGlobalValue(Register ResVReg, MachineInstr &I,
7881ad6265SDimitry Andric                          const MachineInstr *Init = nullptr) const;
7981ad6265SDimitry Andric 
8081ad6265SDimitry Andric   bool selectUnOpWithSrc(Register ResVReg, const SPIRVType *ResType,
8181ad6265SDimitry Andric                          MachineInstr &I, Register SrcReg,
8281ad6265SDimitry Andric                          unsigned Opcode) const;
8381ad6265SDimitry Andric   bool selectUnOp(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
8481ad6265SDimitry Andric                   unsigned Opcode) const;
8581ad6265SDimitry Andric 
8681ad6265SDimitry Andric   bool selectLoad(Register ResVReg, const SPIRVType *ResType,
8781ad6265SDimitry Andric                   MachineInstr &I) const;
8881ad6265SDimitry Andric   bool selectStore(MachineInstr &I) const;
8981ad6265SDimitry Andric 
9081ad6265SDimitry Andric   bool selectMemOperation(Register ResVReg, MachineInstr &I) const;
9181ad6265SDimitry Andric 
9281ad6265SDimitry Andric   bool selectAtomicRMW(Register ResVReg, const SPIRVType *ResType,
9381ad6265SDimitry Andric                        MachineInstr &I, unsigned NewOpcode) const;
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric   bool selectAtomicCmpXchg(Register ResVReg, const SPIRVType *ResType,
9681ad6265SDimitry Andric                            MachineInstr &I) const;
9781ad6265SDimitry Andric 
9881ad6265SDimitry Andric   bool selectFence(MachineInstr &I) const;
9981ad6265SDimitry Andric 
10081ad6265SDimitry Andric   bool selectAddrSpaceCast(Register ResVReg, const SPIRVType *ResType,
10181ad6265SDimitry Andric                            MachineInstr &I) const;
10281ad6265SDimitry Andric 
10381ad6265SDimitry Andric   bool selectBitreverse(Register ResVReg, const SPIRVType *ResType,
10481ad6265SDimitry Andric                         MachineInstr &I) const;
10581ad6265SDimitry Andric 
10681ad6265SDimitry Andric   bool selectConstVector(Register ResVReg, const SPIRVType *ResType,
10781ad6265SDimitry Andric                          MachineInstr &I) const;
10881ad6265SDimitry Andric 
10981ad6265SDimitry Andric   bool selectCmp(Register ResVReg, const SPIRVType *ResType,
11081ad6265SDimitry Andric                  unsigned comparisonOpcode, MachineInstr &I) const;
11181ad6265SDimitry Andric 
11281ad6265SDimitry Andric   bool selectICmp(Register ResVReg, const SPIRVType *ResType,
11381ad6265SDimitry Andric                   MachineInstr &I) const;
11481ad6265SDimitry Andric   bool selectFCmp(Register ResVReg, const SPIRVType *ResType,
11581ad6265SDimitry Andric                   MachineInstr &I) const;
11681ad6265SDimitry Andric 
11781ad6265SDimitry Andric   void renderImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
11881ad6265SDimitry Andric                    int OpIdx) const;
11981ad6265SDimitry Andric   void renderFImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
12081ad6265SDimitry Andric                     int OpIdx) const;
12181ad6265SDimitry Andric 
12281ad6265SDimitry Andric   bool selectConst(Register ResVReg, const SPIRVType *ResType, const APInt &Imm,
12381ad6265SDimitry Andric                    MachineInstr &I) const;
12481ad6265SDimitry Andric 
12581ad6265SDimitry Andric   bool selectSelect(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
12681ad6265SDimitry Andric                     bool IsSigned) const;
12781ad6265SDimitry Andric   bool selectIToF(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
12881ad6265SDimitry Andric                   bool IsSigned, unsigned Opcode) const;
12981ad6265SDimitry Andric   bool selectExt(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
13081ad6265SDimitry Andric                  bool IsSigned) const;
13181ad6265SDimitry Andric 
13281ad6265SDimitry Andric   bool selectTrunc(Register ResVReg, const SPIRVType *ResType,
13381ad6265SDimitry Andric                    MachineInstr &I) const;
13481ad6265SDimitry Andric 
13581ad6265SDimitry Andric   bool selectIntToBool(Register IntReg, Register ResVReg,
13681ad6265SDimitry Andric                        const SPIRVType *intTy, const SPIRVType *boolTy,
13781ad6265SDimitry Andric                        MachineInstr &I) const;
13881ad6265SDimitry Andric 
13981ad6265SDimitry Andric   bool selectOpUndef(Register ResVReg, const SPIRVType *ResType,
14081ad6265SDimitry Andric                      MachineInstr &I) const;
14181ad6265SDimitry Andric   bool selectIntrinsic(Register ResVReg, const SPIRVType *ResType,
14281ad6265SDimitry Andric                        MachineInstr &I) const;
14381ad6265SDimitry Andric   bool selectExtractVal(Register ResVReg, const SPIRVType *ResType,
14481ad6265SDimitry Andric                         MachineInstr &I) const;
14581ad6265SDimitry Andric   bool selectInsertVal(Register ResVReg, const SPIRVType *ResType,
14681ad6265SDimitry Andric                        MachineInstr &I) const;
14781ad6265SDimitry Andric   bool selectExtractElt(Register ResVReg, const SPIRVType *ResType,
14881ad6265SDimitry Andric                         MachineInstr &I) const;
14981ad6265SDimitry Andric   bool selectInsertElt(Register ResVReg, const SPIRVType *ResType,
15081ad6265SDimitry Andric                        MachineInstr &I) const;
15181ad6265SDimitry Andric   bool selectGEP(Register ResVReg, const SPIRVType *ResType,
15281ad6265SDimitry Andric                  MachineInstr &I) const;
15381ad6265SDimitry Andric 
15481ad6265SDimitry Andric   bool selectFrameIndex(Register ResVReg, const SPIRVType *ResType,
15581ad6265SDimitry Andric                         MachineInstr &I) const;
15681ad6265SDimitry Andric 
15781ad6265SDimitry Andric   bool selectBranch(MachineInstr &I) const;
15881ad6265SDimitry Andric   bool selectBranchCond(MachineInstr &I) const;
15981ad6265SDimitry Andric 
16081ad6265SDimitry Andric   bool selectPhi(Register ResVReg, const SPIRVType *ResType,
16181ad6265SDimitry Andric                  MachineInstr &I) const;
16281ad6265SDimitry Andric 
16381ad6265SDimitry Andric   Register buildI32Constant(uint32_t Val, MachineInstr &I,
16481ad6265SDimitry Andric                             const SPIRVType *ResType = nullptr) const;
16581ad6265SDimitry Andric 
16681ad6265SDimitry Andric   Register buildZerosVal(const SPIRVType *ResType, MachineInstr &I) const;
16781ad6265SDimitry Andric   Register buildOnesVal(bool AllOnes, const SPIRVType *ResType,
16881ad6265SDimitry Andric                         MachineInstr &I) const;
16981ad6265SDimitry Andric };
17081ad6265SDimitry Andric 
17181ad6265SDimitry Andric } // end anonymous namespace
17281ad6265SDimitry Andric 
17381ad6265SDimitry Andric #define GET_GLOBALISEL_IMPL
17481ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
17581ad6265SDimitry Andric #undef GET_GLOBALISEL_IMPL
17681ad6265SDimitry Andric 
17781ad6265SDimitry Andric SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
17881ad6265SDimitry Andric                                                    const SPIRVSubtarget &ST,
17981ad6265SDimitry Andric                                                    const RegisterBankInfo &RBI)
18081ad6265SDimitry Andric     : InstructionSelector(), STI(ST), TII(*ST.getInstrInfo()),
18181ad6265SDimitry Andric       TRI(*ST.getRegisterInfo()), RBI(RBI), GR(*ST.getSPIRVGlobalRegistry()),
18281ad6265SDimitry Andric #define GET_GLOBALISEL_PREDICATES_INIT
18381ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
18481ad6265SDimitry Andric #undef GET_GLOBALISEL_PREDICATES_INIT
18581ad6265SDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_INIT
18681ad6265SDimitry Andric #include "SPIRVGenGlobalISel.inc"
18781ad6265SDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_INIT
18881ad6265SDimitry Andric {
18981ad6265SDimitry Andric }
19081ad6265SDimitry Andric 
19181ad6265SDimitry Andric void SPIRVInstructionSelector::setupMF(MachineFunction &MF, GISelKnownBits *KB,
19281ad6265SDimitry Andric                                        CodeGenCoverage &CoverageInfo,
19381ad6265SDimitry Andric                                        ProfileSummaryInfo *PSI,
19481ad6265SDimitry Andric                                        BlockFrequencyInfo *BFI) {
19581ad6265SDimitry Andric   MRI = &MF.getRegInfo();
19681ad6265SDimitry Andric   GR.setCurrentFunc(MF);
19781ad6265SDimitry Andric   InstructionSelector::setupMF(MF, KB, CoverageInfo, PSI, BFI);
19881ad6265SDimitry Andric }
19981ad6265SDimitry Andric 
20081ad6265SDimitry Andric // Defined in SPIRVLegalizerInfo.cpp.
20181ad6265SDimitry Andric extern bool isTypeFoldingSupported(unsigned Opcode);
20281ad6265SDimitry Andric 
20381ad6265SDimitry Andric bool SPIRVInstructionSelector::select(MachineInstr &I) {
20481ad6265SDimitry Andric   assert(I.getParent() && "Instruction should be in a basic block!");
20581ad6265SDimitry Andric   assert(I.getParent()->getParent() && "Instruction should be in a function!");
20681ad6265SDimitry Andric 
20781ad6265SDimitry Andric   Register Opcode = I.getOpcode();
20881ad6265SDimitry Andric   // If it's not a GMIR instruction, we've selected it already.
20981ad6265SDimitry Andric   if (!isPreISelGenericOpcode(Opcode)) {
21081ad6265SDimitry Andric     if (Opcode == SPIRV::ASSIGN_TYPE) { // These pseudos aren't needed any more.
21181ad6265SDimitry Andric       auto *Def = MRI->getVRegDef(I.getOperand(1).getReg());
21281ad6265SDimitry Andric       if (isTypeFoldingSupported(Def->getOpcode())) {
21381ad6265SDimitry Andric         auto Res = selectImpl(I, *CoverageInfo);
21481ad6265SDimitry Andric         assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT);
21581ad6265SDimitry Andric         if (Res)
21681ad6265SDimitry Andric           return Res;
21781ad6265SDimitry Andric       }
21881ad6265SDimitry Andric       MRI->replaceRegWith(I.getOperand(1).getReg(), I.getOperand(0).getReg());
21981ad6265SDimitry Andric       I.removeFromParent();
22081ad6265SDimitry Andric     } else if (I.getNumDefs() == 1) {
22181ad6265SDimitry Andric       // Make all vregs 32 bits (for SPIR-V IDs).
22281ad6265SDimitry Andric       MRI->setType(I.getOperand(0).getReg(), LLT::scalar(32));
22381ad6265SDimitry Andric     }
22481ad6265SDimitry Andric     return true;
22581ad6265SDimitry Andric   }
22681ad6265SDimitry Andric 
22781ad6265SDimitry Andric   if (I.getNumOperands() != I.getNumExplicitOperands()) {
22881ad6265SDimitry Andric     LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
22981ad6265SDimitry Andric     return false;
23081ad6265SDimitry Andric   }
23181ad6265SDimitry Andric 
23281ad6265SDimitry Andric   // Common code for getting return reg+type, and removing selected instr
23381ad6265SDimitry Andric   // from parent occurs here. Instr-specific selection happens in spvSelect().
23481ad6265SDimitry Andric   bool HasDefs = I.getNumDefs() > 0;
23581ad6265SDimitry Andric   Register ResVReg = HasDefs ? I.getOperand(0).getReg() : Register(0);
23681ad6265SDimitry Andric   SPIRVType *ResType = HasDefs ? GR.getSPIRVTypeForVReg(ResVReg) : nullptr;
23781ad6265SDimitry Andric   assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
23881ad6265SDimitry Andric   if (spvSelect(ResVReg, ResType, I)) {
23981ad6265SDimitry Andric     if (HasDefs) // Make all vregs 32 bits (for SPIR-V IDs).
24081ad6265SDimitry Andric       MRI->setType(ResVReg, LLT::scalar(32));
24181ad6265SDimitry Andric     I.removeFromParent();
24281ad6265SDimitry Andric     return true;
24381ad6265SDimitry Andric   }
24481ad6265SDimitry Andric   return false;
24581ad6265SDimitry Andric }
24681ad6265SDimitry Andric 
24781ad6265SDimitry Andric bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
24881ad6265SDimitry Andric                                          const SPIRVType *ResType,
24981ad6265SDimitry Andric                                          MachineInstr &I) const {
25081ad6265SDimitry Andric   assert(!isTypeFoldingSupported(I.getOpcode()) ||
25181ad6265SDimitry Andric          I.getOpcode() == TargetOpcode::G_CONSTANT);
25281ad6265SDimitry Andric   const unsigned Opcode = I.getOpcode();
25381ad6265SDimitry Andric   switch (Opcode) {
25481ad6265SDimitry Andric   case TargetOpcode::G_CONSTANT:
25581ad6265SDimitry Andric     return selectConst(ResVReg, ResType, I.getOperand(1).getCImm()->getValue(),
25681ad6265SDimitry Andric                        I);
25781ad6265SDimitry Andric   case TargetOpcode::G_GLOBAL_VALUE:
25881ad6265SDimitry Andric     return selectGlobalValue(ResVReg, I);
25981ad6265SDimitry Andric   case TargetOpcode::G_IMPLICIT_DEF:
26081ad6265SDimitry Andric     return selectOpUndef(ResVReg, ResType, I);
26181ad6265SDimitry Andric 
26281ad6265SDimitry Andric   case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
26381ad6265SDimitry Andric     return selectIntrinsic(ResVReg, ResType, I);
26481ad6265SDimitry Andric   case TargetOpcode::G_BITREVERSE:
26581ad6265SDimitry Andric     return selectBitreverse(ResVReg, ResType, I);
26681ad6265SDimitry Andric 
26781ad6265SDimitry Andric   case TargetOpcode::G_BUILD_VECTOR:
26881ad6265SDimitry Andric     return selectConstVector(ResVReg, ResType, I);
26981ad6265SDimitry Andric 
27081ad6265SDimitry Andric   case TargetOpcode::G_SHUFFLE_VECTOR: {
27181ad6265SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
27281ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle))
27381ad6265SDimitry Andric                    .addDef(ResVReg)
27481ad6265SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType))
27581ad6265SDimitry Andric                    .addUse(I.getOperand(1).getReg())
27681ad6265SDimitry Andric                    .addUse(I.getOperand(2).getReg());
27781ad6265SDimitry Andric     for (auto V : I.getOperand(3).getShuffleMask())
27881ad6265SDimitry Andric       MIB.addImm(V);
27981ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
28081ad6265SDimitry Andric   }
28181ad6265SDimitry Andric   case TargetOpcode::G_MEMMOVE:
28281ad6265SDimitry Andric   case TargetOpcode::G_MEMCPY:
28381ad6265SDimitry Andric     return selectMemOperation(ResVReg, I);
28481ad6265SDimitry Andric 
28581ad6265SDimitry Andric   case TargetOpcode::G_ICMP:
28681ad6265SDimitry Andric     return selectICmp(ResVReg, ResType, I);
28781ad6265SDimitry Andric   case TargetOpcode::G_FCMP:
28881ad6265SDimitry Andric     return selectFCmp(ResVReg, ResType, I);
28981ad6265SDimitry Andric 
29081ad6265SDimitry Andric   case TargetOpcode::G_FRAME_INDEX:
29181ad6265SDimitry Andric     return selectFrameIndex(ResVReg, ResType, I);
29281ad6265SDimitry Andric 
29381ad6265SDimitry Andric   case TargetOpcode::G_LOAD:
29481ad6265SDimitry Andric     return selectLoad(ResVReg, ResType, I);
29581ad6265SDimitry Andric   case TargetOpcode::G_STORE:
29681ad6265SDimitry Andric     return selectStore(I);
29781ad6265SDimitry Andric 
29881ad6265SDimitry Andric   case TargetOpcode::G_BR:
29981ad6265SDimitry Andric     return selectBranch(I);
30081ad6265SDimitry Andric   case TargetOpcode::G_BRCOND:
30181ad6265SDimitry Andric     return selectBranchCond(I);
30281ad6265SDimitry Andric 
30381ad6265SDimitry Andric   case TargetOpcode::G_PHI:
30481ad6265SDimitry Andric     return selectPhi(ResVReg, ResType, I);
30581ad6265SDimitry Andric 
30681ad6265SDimitry Andric   case TargetOpcode::G_FPTOSI:
30781ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS);
30881ad6265SDimitry Andric   case TargetOpcode::G_FPTOUI:
30981ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU);
31081ad6265SDimitry Andric 
31181ad6265SDimitry Andric   case TargetOpcode::G_SITOFP:
31281ad6265SDimitry Andric     return selectIToF(ResVReg, ResType, I, true, SPIRV::OpConvertSToF);
31381ad6265SDimitry Andric   case TargetOpcode::G_UITOFP:
31481ad6265SDimitry Andric     return selectIToF(ResVReg, ResType, I, false, SPIRV::OpConvertUToF);
31581ad6265SDimitry Andric 
31681ad6265SDimitry Andric   case TargetOpcode::G_CTPOP:
31781ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitCount);
31881ad6265SDimitry Andric 
31981ad6265SDimitry Andric   case TargetOpcode::G_SEXT:
32081ad6265SDimitry Andric     return selectExt(ResVReg, ResType, I, true);
32181ad6265SDimitry Andric   case TargetOpcode::G_ANYEXT:
32281ad6265SDimitry Andric   case TargetOpcode::G_ZEXT:
32381ad6265SDimitry Andric     return selectExt(ResVReg, ResType, I, false);
32481ad6265SDimitry Andric   case TargetOpcode::G_TRUNC:
32581ad6265SDimitry Andric     return selectTrunc(ResVReg, ResType, I);
32681ad6265SDimitry Andric   case TargetOpcode::G_FPTRUNC:
32781ad6265SDimitry Andric   case TargetOpcode::G_FPEXT:
32881ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpFConvert);
32981ad6265SDimitry Andric 
33081ad6265SDimitry Andric   case TargetOpcode::G_PTRTOINT:
33181ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertPtrToU);
33281ad6265SDimitry Andric   case TargetOpcode::G_INTTOPTR:
33381ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertUToPtr);
33481ad6265SDimitry Andric   case TargetOpcode::G_BITCAST:
33581ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast);
33681ad6265SDimitry Andric   case TargetOpcode::G_ADDRSPACE_CAST:
33781ad6265SDimitry Andric     return selectAddrSpaceCast(ResVReg, ResType, I);
33881ad6265SDimitry Andric 
33981ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_OR:
34081ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicOr);
34181ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_ADD:
34281ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicIAdd);
34381ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_AND:
34481ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicAnd);
34581ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_MAX:
34681ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMax);
34781ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_MIN:
34881ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMin);
34981ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_SUB:
35081ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicISub);
35181ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XOR:
35281ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicXor);
35381ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_UMAX:
35481ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMax);
35581ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_UMIN:
35681ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMin);
35781ad6265SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XCHG:
35881ad6265SDimitry Andric     return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicExchange);
35981ad6265SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG:
36081ad6265SDimitry Andric     return selectAtomicCmpXchg(ResVReg, ResType, I);
36181ad6265SDimitry Andric 
36281ad6265SDimitry Andric   case TargetOpcode::G_FENCE:
36381ad6265SDimitry Andric     return selectFence(I);
36481ad6265SDimitry Andric 
36581ad6265SDimitry Andric   default:
36681ad6265SDimitry Andric     return false;
36781ad6265SDimitry Andric   }
36881ad6265SDimitry Andric }
36981ad6265SDimitry Andric 
37081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectUnOpWithSrc(Register ResVReg,
37181ad6265SDimitry Andric                                                  const SPIRVType *ResType,
37281ad6265SDimitry Andric                                                  MachineInstr &I,
37381ad6265SDimitry Andric                                                  Register SrcReg,
37481ad6265SDimitry Andric                                                  unsigned Opcode) const {
37581ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
37681ad6265SDimitry Andric       .addDef(ResVReg)
37781ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
37881ad6265SDimitry Andric       .addUse(SrcReg)
37981ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
38081ad6265SDimitry Andric }
38181ad6265SDimitry Andric 
38281ad6265SDimitry Andric bool SPIRVInstructionSelector::selectUnOp(Register ResVReg,
38381ad6265SDimitry Andric                                           const SPIRVType *ResType,
38481ad6265SDimitry Andric                                           MachineInstr &I,
38581ad6265SDimitry Andric                                           unsigned Opcode) const {
38681ad6265SDimitry Andric   return selectUnOpWithSrc(ResVReg, ResType, I, I.getOperand(1).getReg(),
38781ad6265SDimitry Andric                            Opcode);
38881ad6265SDimitry Andric }
38981ad6265SDimitry Andric 
39081ad6265SDimitry Andric static SPIRV::MemorySemantics getMemSemantics(AtomicOrdering Ord) {
39181ad6265SDimitry Andric   switch (Ord) {
39281ad6265SDimitry Andric   case AtomicOrdering::Acquire:
39381ad6265SDimitry Andric     return SPIRV::MemorySemantics::Acquire;
39481ad6265SDimitry Andric   case AtomicOrdering::Release:
39581ad6265SDimitry Andric     return SPIRV::MemorySemantics::Release;
39681ad6265SDimitry Andric   case AtomicOrdering::AcquireRelease:
39781ad6265SDimitry Andric     return SPIRV::MemorySemantics::AcquireRelease;
39881ad6265SDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
39981ad6265SDimitry Andric     return SPIRV::MemorySemantics::SequentiallyConsistent;
40081ad6265SDimitry Andric   case AtomicOrdering::Unordered:
40181ad6265SDimitry Andric   case AtomicOrdering::Monotonic:
40281ad6265SDimitry Andric   case AtomicOrdering::NotAtomic:
40381ad6265SDimitry Andric     return SPIRV::MemorySemantics::None;
40481ad6265SDimitry Andric   }
40581ad6265SDimitry Andric }
40681ad6265SDimitry Andric 
40781ad6265SDimitry Andric static SPIRV::Scope getScope(SyncScope::ID Ord) {
40881ad6265SDimitry Andric   switch (Ord) {
40981ad6265SDimitry Andric   case SyncScope::SingleThread:
41081ad6265SDimitry Andric     return SPIRV::Scope::Invocation;
41181ad6265SDimitry Andric   case SyncScope::System:
41281ad6265SDimitry Andric     return SPIRV::Scope::Device;
41381ad6265SDimitry Andric   default:
41481ad6265SDimitry Andric     llvm_unreachable("Unsupported synchronization Scope ID.");
41581ad6265SDimitry Andric   }
41681ad6265SDimitry Andric }
41781ad6265SDimitry Andric 
41881ad6265SDimitry Andric static void addMemoryOperands(MachineMemOperand *MemOp,
41981ad6265SDimitry Andric                               MachineInstrBuilder &MIB) {
42081ad6265SDimitry Andric   uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
42181ad6265SDimitry Andric   if (MemOp->isVolatile())
42281ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
42381ad6265SDimitry Andric   if (MemOp->isNonTemporal())
42481ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
42581ad6265SDimitry Andric   if (MemOp->getAlign().value())
42681ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned);
42781ad6265SDimitry Andric 
42881ad6265SDimitry Andric   if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) {
42981ad6265SDimitry Andric     MIB.addImm(SpvMemOp);
43081ad6265SDimitry Andric     if (SpvMemOp & static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned))
43181ad6265SDimitry Andric       MIB.addImm(MemOp->getAlign().value());
43281ad6265SDimitry Andric   }
43381ad6265SDimitry Andric }
43481ad6265SDimitry Andric 
43581ad6265SDimitry Andric static void addMemoryOperands(uint64_t Flags, MachineInstrBuilder &MIB) {
43681ad6265SDimitry Andric   uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None);
43781ad6265SDimitry Andric   if (Flags & MachineMemOperand::Flags::MOVolatile)
43881ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
43981ad6265SDimitry Andric   if (Flags & MachineMemOperand::Flags::MONonTemporal)
44081ad6265SDimitry Andric     SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
44181ad6265SDimitry Andric 
44281ad6265SDimitry Andric   if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None))
44381ad6265SDimitry Andric     MIB.addImm(SpvMemOp);
44481ad6265SDimitry Andric }
44581ad6265SDimitry Andric 
44681ad6265SDimitry Andric bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
44781ad6265SDimitry Andric                                           const SPIRVType *ResType,
44881ad6265SDimitry Andric                                           MachineInstr &I) const {
44981ad6265SDimitry Andric   unsigned OpOffset =
45081ad6265SDimitry Andric       I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ? 1 : 0;
45181ad6265SDimitry Andric   Register Ptr = I.getOperand(1 + OpOffset).getReg();
45281ad6265SDimitry Andric   auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
45381ad6265SDimitry Andric                  .addDef(ResVReg)
45481ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
45581ad6265SDimitry Andric                  .addUse(Ptr);
45681ad6265SDimitry Andric   if (!I.getNumMemOperands()) {
45781ad6265SDimitry Andric     assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
45881ad6265SDimitry Andric     addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
45981ad6265SDimitry Andric   } else {
46081ad6265SDimitry Andric     addMemoryOperands(*I.memoperands_begin(), MIB);
46181ad6265SDimitry Andric   }
46281ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
46381ad6265SDimitry Andric }
46481ad6265SDimitry Andric 
46581ad6265SDimitry Andric bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
46681ad6265SDimitry Andric   unsigned OpOffset =
46781ad6265SDimitry Andric       I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ? 1 : 0;
46881ad6265SDimitry Andric   Register StoreVal = I.getOperand(0 + OpOffset).getReg();
46981ad6265SDimitry Andric   Register Ptr = I.getOperand(1 + OpOffset).getReg();
47081ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
47181ad6265SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpStore))
47281ad6265SDimitry Andric                  .addUse(Ptr)
47381ad6265SDimitry Andric                  .addUse(StoreVal);
47481ad6265SDimitry Andric   if (!I.getNumMemOperands()) {
47581ad6265SDimitry Andric     assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
47681ad6265SDimitry Andric     addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB);
47781ad6265SDimitry Andric   } else {
47881ad6265SDimitry Andric     addMemoryOperands(*I.memoperands_begin(), MIB);
47981ad6265SDimitry Andric   }
48081ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
48181ad6265SDimitry Andric }
48281ad6265SDimitry Andric 
48381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg,
48481ad6265SDimitry Andric                                                   MachineInstr &I) const {
48581ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
48681ad6265SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemorySized))
48781ad6265SDimitry Andric                  .addDef(I.getOperand(0).getReg())
48881ad6265SDimitry Andric                  .addUse(I.getOperand(1).getReg())
48981ad6265SDimitry Andric                  .addUse(I.getOperand(2).getReg());
49081ad6265SDimitry Andric   if (I.getNumMemOperands())
49181ad6265SDimitry Andric     addMemoryOperands(*I.memoperands_begin(), MIB);
49281ad6265SDimitry Andric   bool Result = MIB.constrainAllUses(TII, TRI, RBI);
49381ad6265SDimitry Andric   if (ResVReg.isValid() && ResVReg != MIB->getOperand(0).getReg()) {
49481ad6265SDimitry Andric     BuildMI(BB, I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), ResVReg)
49581ad6265SDimitry Andric         .addUse(MIB->getOperand(0).getReg());
49681ad6265SDimitry Andric   }
49781ad6265SDimitry Andric   return Result;
49881ad6265SDimitry Andric }
49981ad6265SDimitry Andric 
50081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg,
50181ad6265SDimitry Andric                                                const SPIRVType *ResType,
50281ad6265SDimitry Andric                                                MachineInstr &I,
50381ad6265SDimitry Andric                                                unsigned NewOpcode) const {
50481ad6265SDimitry Andric   assert(I.hasOneMemOperand());
50581ad6265SDimitry Andric   const MachineMemOperand *MemOp = *I.memoperands_begin();
50681ad6265SDimitry Andric   uint32_t Scope = static_cast<uint32_t>(getScope(MemOp->getSyncScopeID()));
50781ad6265SDimitry Andric   Register ScopeReg = buildI32Constant(Scope, I);
50881ad6265SDimitry Andric 
50981ad6265SDimitry Andric   Register Ptr = I.getOperand(1).getReg();
51081ad6265SDimitry Andric   // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll
51181ad6265SDimitry Andric   // auto ScSem =
51281ad6265SDimitry Andric   // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr));
51381ad6265SDimitry Andric   AtomicOrdering AO = MemOp->getSuccessOrdering();
51481ad6265SDimitry Andric   uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
51581ad6265SDimitry Andric   Register MemSemReg = buildI32Constant(MemSem /*| ScSem*/, I);
51681ad6265SDimitry Andric 
51781ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode))
51881ad6265SDimitry Andric       .addDef(ResVReg)
51981ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
52081ad6265SDimitry Andric       .addUse(Ptr)
52181ad6265SDimitry Andric       .addUse(ScopeReg)
52281ad6265SDimitry Andric       .addUse(MemSemReg)
52381ad6265SDimitry Andric       .addUse(I.getOperand(2).getReg())
52481ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
52581ad6265SDimitry Andric }
52681ad6265SDimitry Andric 
52781ad6265SDimitry Andric bool SPIRVInstructionSelector::selectFence(MachineInstr &I) const {
52881ad6265SDimitry Andric   AtomicOrdering AO = AtomicOrdering(I.getOperand(0).getImm());
52981ad6265SDimitry Andric   uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
53081ad6265SDimitry Andric   Register MemSemReg = buildI32Constant(MemSem, I);
53181ad6265SDimitry Andric   SyncScope::ID Ord = SyncScope::ID(I.getOperand(1).getImm());
53281ad6265SDimitry Andric   uint32_t Scope = static_cast<uint32_t>(getScope(Ord));
53381ad6265SDimitry Andric   Register ScopeReg = buildI32Constant(Scope, I);
53481ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
53581ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMemoryBarrier))
53681ad6265SDimitry Andric       .addUse(ScopeReg)
53781ad6265SDimitry Andric       .addUse(MemSemReg)
53881ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
53981ad6265SDimitry Andric }
54081ad6265SDimitry Andric 
54181ad6265SDimitry Andric bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg,
54281ad6265SDimitry Andric                                                    const SPIRVType *ResType,
54381ad6265SDimitry Andric                                                    MachineInstr &I) const {
54481ad6265SDimitry Andric   assert(I.hasOneMemOperand());
54581ad6265SDimitry Andric   const MachineMemOperand *MemOp = *I.memoperands_begin();
54681ad6265SDimitry Andric   uint32_t Scope = static_cast<uint32_t>(getScope(MemOp->getSyncScopeID()));
54781ad6265SDimitry Andric   Register ScopeReg = buildI32Constant(Scope, I);
54881ad6265SDimitry Andric 
54981ad6265SDimitry Andric   Register Ptr = I.getOperand(2).getReg();
55081ad6265SDimitry Andric   Register Cmp = I.getOperand(3).getReg();
55181ad6265SDimitry Andric   Register Val = I.getOperand(4).getReg();
55281ad6265SDimitry Andric 
55381ad6265SDimitry Andric   SPIRVType *SpvValTy = GR.getSPIRVTypeForVReg(Val);
55481ad6265SDimitry Andric   SPIRV::StorageClass SC = GR.getPointerStorageClass(Ptr);
55581ad6265SDimitry Andric   uint32_t ScSem = static_cast<uint32_t>(getMemSemanticsForStorageClass(SC));
55681ad6265SDimitry Andric   AtomicOrdering AO = MemOp->getSuccessOrdering();
55781ad6265SDimitry Andric   uint32_t MemSemEq = static_cast<uint32_t>(getMemSemantics(AO)) | ScSem;
55881ad6265SDimitry Andric   Register MemSemEqReg = buildI32Constant(MemSemEq, I);
55981ad6265SDimitry Andric   AtomicOrdering FO = MemOp->getFailureOrdering();
56081ad6265SDimitry Andric   uint32_t MemSemNeq = static_cast<uint32_t>(getMemSemantics(FO)) | ScSem;
56181ad6265SDimitry Andric   Register MemSemNeqReg =
56281ad6265SDimitry Andric       MemSemEq == MemSemNeq ? MemSemEqReg : buildI32Constant(MemSemNeq, I);
56381ad6265SDimitry Andric   const DebugLoc &DL = I.getDebugLoc();
56481ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpAtomicCompareExchange))
56581ad6265SDimitry Andric       .addDef(ResVReg)
56681ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(SpvValTy))
56781ad6265SDimitry Andric       .addUse(Ptr)
56881ad6265SDimitry Andric       .addUse(ScopeReg)
56981ad6265SDimitry Andric       .addUse(MemSemEqReg)
57081ad6265SDimitry Andric       .addUse(MemSemNeqReg)
57181ad6265SDimitry Andric       .addUse(Val)
57281ad6265SDimitry Andric       .addUse(Cmp)
57381ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
57481ad6265SDimitry Andric }
57581ad6265SDimitry Andric 
57681ad6265SDimitry Andric static bool isGenericCastablePtr(SPIRV::StorageClass SC) {
57781ad6265SDimitry Andric   switch (SC) {
57881ad6265SDimitry Andric   case SPIRV::StorageClass::Workgroup:
57981ad6265SDimitry Andric   case SPIRV::StorageClass::CrossWorkgroup:
58081ad6265SDimitry Andric   case SPIRV::StorageClass::Function:
58181ad6265SDimitry Andric     return true;
58281ad6265SDimitry Andric   default:
58381ad6265SDimitry Andric     return false;
58481ad6265SDimitry Andric   }
58581ad6265SDimitry Andric }
58681ad6265SDimitry Andric 
58781ad6265SDimitry Andric // In SPIR-V address space casting can only happen to and from the Generic
58881ad6265SDimitry Andric // storage class. We can also only case Workgroup, CrossWorkgroup, or Function
58981ad6265SDimitry Andric // pointers to and from Generic pointers. As such, we can convert e.g. from
59081ad6265SDimitry Andric // Workgroup to Function by going via a Generic pointer as an intermediary. All
59181ad6265SDimitry Andric // other combinations can only be done by a bitcast, and are probably not safe.
59281ad6265SDimitry Andric bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
59381ad6265SDimitry Andric                                                    const SPIRVType *ResType,
59481ad6265SDimitry Andric                                                    MachineInstr &I) const {
59581ad6265SDimitry Andric   Register SrcPtr = I.getOperand(1).getReg();
59681ad6265SDimitry Andric   SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
59781ad6265SDimitry Andric   SPIRV::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtr);
59881ad6265SDimitry Andric   SPIRV::StorageClass DstSC = GR.getPointerStorageClass(ResVReg);
59981ad6265SDimitry Andric 
60081ad6265SDimitry Andric   // Casting from an eligable pointer to Generic.
60181ad6265SDimitry Andric   if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC))
60281ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric);
60381ad6265SDimitry Andric   // Casting from Generic to an eligable pointer.
60481ad6265SDimitry Andric   if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC))
60581ad6265SDimitry Andric     return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr);
60681ad6265SDimitry Andric   // Casting between 2 eligable pointers using Generic as an intermediary.
60781ad6265SDimitry Andric   if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) {
60881ad6265SDimitry Andric     Register Tmp = MRI->createVirtualRegister(&SPIRV::IDRegClass);
60981ad6265SDimitry Andric     SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
61081ad6265SDimitry Andric         SrcPtrTy, I, TII, SPIRV::StorageClass::Generic);
61181ad6265SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
61281ad6265SDimitry Andric     const DebugLoc &DL = I.getDebugLoc();
61381ad6265SDimitry Andric     bool Success = BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric))
61481ad6265SDimitry Andric                        .addDef(Tmp)
61581ad6265SDimitry Andric                        .addUse(GR.getSPIRVTypeID(GenericPtrTy))
61681ad6265SDimitry Andric                        .addUse(SrcPtr)
61781ad6265SDimitry Andric                        .constrainAllUses(TII, TRI, RBI);
61881ad6265SDimitry Andric     return Success && BuildMI(BB, I, DL, TII.get(SPIRV::OpGenericCastToPtr))
61981ad6265SDimitry Andric                           .addDef(ResVReg)
62081ad6265SDimitry Andric                           .addUse(GR.getSPIRVTypeID(ResType))
62181ad6265SDimitry Andric                           .addUse(Tmp)
62281ad6265SDimitry Andric                           .constrainAllUses(TII, TRI, RBI);
62381ad6265SDimitry Andric   }
62481ad6265SDimitry Andric   // TODO Should this case just be disallowed completely?
62581ad6265SDimitry Andric   // We're casting 2 other arbitrary address spaces, so have to bitcast.
62681ad6265SDimitry Andric   return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast);
62781ad6265SDimitry Andric }
62881ad6265SDimitry Andric 
62981ad6265SDimitry Andric static unsigned getFCmpOpcode(unsigned PredNum) {
63081ad6265SDimitry Andric   auto Pred = static_cast<CmpInst::Predicate>(PredNum);
63181ad6265SDimitry Andric   switch (Pred) {
63281ad6265SDimitry Andric   case CmpInst::FCMP_OEQ:
63381ad6265SDimitry Andric     return SPIRV::OpFOrdEqual;
63481ad6265SDimitry Andric   case CmpInst::FCMP_OGE:
63581ad6265SDimitry Andric     return SPIRV::OpFOrdGreaterThanEqual;
63681ad6265SDimitry Andric   case CmpInst::FCMP_OGT:
63781ad6265SDimitry Andric     return SPIRV::OpFOrdGreaterThan;
63881ad6265SDimitry Andric   case CmpInst::FCMP_OLE:
63981ad6265SDimitry Andric     return SPIRV::OpFOrdLessThanEqual;
64081ad6265SDimitry Andric   case CmpInst::FCMP_OLT:
64181ad6265SDimitry Andric     return SPIRV::OpFOrdLessThan;
64281ad6265SDimitry Andric   case CmpInst::FCMP_ONE:
64381ad6265SDimitry Andric     return SPIRV::OpFOrdNotEqual;
64481ad6265SDimitry Andric   case CmpInst::FCMP_ORD:
64581ad6265SDimitry Andric     return SPIRV::OpOrdered;
64681ad6265SDimitry Andric   case CmpInst::FCMP_UEQ:
64781ad6265SDimitry Andric     return SPIRV::OpFUnordEqual;
64881ad6265SDimitry Andric   case CmpInst::FCMP_UGE:
64981ad6265SDimitry Andric     return SPIRV::OpFUnordGreaterThanEqual;
65081ad6265SDimitry Andric   case CmpInst::FCMP_UGT:
65181ad6265SDimitry Andric     return SPIRV::OpFUnordGreaterThan;
65281ad6265SDimitry Andric   case CmpInst::FCMP_ULE:
65381ad6265SDimitry Andric     return SPIRV::OpFUnordLessThanEqual;
65481ad6265SDimitry Andric   case CmpInst::FCMP_ULT:
65581ad6265SDimitry Andric     return SPIRV::OpFUnordLessThan;
65681ad6265SDimitry Andric   case CmpInst::FCMP_UNE:
65781ad6265SDimitry Andric     return SPIRV::OpFUnordNotEqual;
65881ad6265SDimitry Andric   case CmpInst::FCMP_UNO:
65981ad6265SDimitry Andric     return SPIRV::OpUnordered;
66081ad6265SDimitry Andric   default:
66181ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for FCmp");
66281ad6265SDimitry Andric   }
66381ad6265SDimitry Andric }
66481ad6265SDimitry Andric 
66581ad6265SDimitry Andric static unsigned getICmpOpcode(unsigned PredNum) {
66681ad6265SDimitry Andric   auto Pred = static_cast<CmpInst::Predicate>(PredNum);
66781ad6265SDimitry Andric   switch (Pred) {
66881ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
66981ad6265SDimitry Andric     return SPIRV::OpIEqual;
67081ad6265SDimitry Andric   case CmpInst::ICMP_NE:
67181ad6265SDimitry Andric     return SPIRV::OpINotEqual;
67281ad6265SDimitry Andric   case CmpInst::ICMP_SGE:
67381ad6265SDimitry Andric     return SPIRV::OpSGreaterThanEqual;
67481ad6265SDimitry Andric   case CmpInst::ICMP_SGT:
67581ad6265SDimitry Andric     return SPIRV::OpSGreaterThan;
67681ad6265SDimitry Andric   case CmpInst::ICMP_SLE:
67781ad6265SDimitry Andric     return SPIRV::OpSLessThanEqual;
67881ad6265SDimitry Andric   case CmpInst::ICMP_SLT:
67981ad6265SDimitry Andric     return SPIRV::OpSLessThan;
68081ad6265SDimitry Andric   case CmpInst::ICMP_UGE:
68181ad6265SDimitry Andric     return SPIRV::OpUGreaterThanEqual;
68281ad6265SDimitry Andric   case CmpInst::ICMP_UGT:
68381ad6265SDimitry Andric     return SPIRV::OpUGreaterThan;
68481ad6265SDimitry Andric   case CmpInst::ICMP_ULE:
68581ad6265SDimitry Andric     return SPIRV::OpULessThanEqual;
68681ad6265SDimitry Andric   case CmpInst::ICMP_ULT:
68781ad6265SDimitry Andric     return SPIRV::OpULessThan;
68881ad6265SDimitry Andric   default:
68981ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for ICmp");
69081ad6265SDimitry Andric   }
69181ad6265SDimitry Andric }
69281ad6265SDimitry Andric 
69381ad6265SDimitry Andric static unsigned getPtrCmpOpcode(unsigned Pred) {
69481ad6265SDimitry Andric   switch (static_cast<CmpInst::Predicate>(Pred)) {
69581ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
69681ad6265SDimitry Andric     return SPIRV::OpPtrEqual;
69781ad6265SDimitry Andric   case CmpInst::ICMP_NE:
69881ad6265SDimitry Andric     return SPIRV::OpPtrNotEqual;
69981ad6265SDimitry Andric   default:
70081ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for pointer comparison");
70181ad6265SDimitry Andric   }
70281ad6265SDimitry Andric }
70381ad6265SDimitry Andric 
70481ad6265SDimitry Andric // Return the logical operation, or abort if none exists.
70581ad6265SDimitry Andric static unsigned getBoolCmpOpcode(unsigned PredNum) {
70681ad6265SDimitry Andric   auto Pred = static_cast<CmpInst::Predicate>(PredNum);
70781ad6265SDimitry Andric   switch (Pred) {
70881ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
70981ad6265SDimitry Andric     return SPIRV::OpLogicalEqual;
71081ad6265SDimitry Andric   case CmpInst::ICMP_NE:
71181ad6265SDimitry Andric     return SPIRV::OpLogicalNotEqual;
71281ad6265SDimitry Andric   default:
71381ad6265SDimitry Andric     llvm_unreachable("Unknown predicate type for Bool comparison");
71481ad6265SDimitry Andric   }
71581ad6265SDimitry Andric }
71681ad6265SDimitry Andric 
71781ad6265SDimitry Andric bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
71881ad6265SDimitry Andric                                                 const SPIRVType *ResType,
71981ad6265SDimitry Andric                                                 MachineInstr &I) const {
72081ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
72181ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse))
72281ad6265SDimitry Andric       .addDef(ResVReg)
72381ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
72481ad6265SDimitry Andric       .addUse(I.getOperand(1).getReg())
72581ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
72681ad6265SDimitry Andric }
72781ad6265SDimitry Andric 
72881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectConstVector(Register ResVReg,
72981ad6265SDimitry Andric                                                  const SPIRVType *ResType,
73081ad6265SDimitry Andric                                                  MachineInstr &I) const {
73181ad6265SDimitry Andric   // TODO: only const case is supported for now.
73281ad6265SDimitry Andric   assert(std::all_of(
73381ad6265SDimitry Andric       I.operands_begin(), I.operands_end(), [this](const MachineOperand &MO) {
73481ad6265SDimitry Andric         if (MO.isDef())
73581ad6265SDimitry Andric           return true;
73681ad6265SDimitry Andric         if (!MO.isReg())
73781ad6265SDimitry Andric           return false;
73881ad6265SDimitry Andric         SPIRVType *ConstTy = this->MRI->getVRegDef(MO.getReg());
73981ad6265SDimitry Andric         assert(ConstTy && ConstTy->getOpcode() == SPIRV::ASSIGN_TYPE &&
74081ad6265SDimitry Andric                ConstTy->getOperand(1).isReg());
74181ad6265SDimitry Andric         Register ConstReg = ConstTy->getOperand(1).getReg();
74281ad6265SDimitry Andric         const MachineInstr *Const = this->MRI->getVRegDef(ConstReg);
74381ad6265SDimitry Andric         assert(Const);
74481ad6265SDimitry Andric         return (Const->getOpcode() == TargetOpcode::G_CONSTANT ||
74581ad6265SDimitry Andric                 Const->getOpcode() == TargetOpcode::G_FCONSTANT);
74681ad6265SDimitry Andric       }));
74781ad6265SDimitry Andric 
74881ad6265SDimitry Andric   auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
74981ad6265SDimitry Andric                      TII.get(SPIRV::OpConstantComposite))
75081ad6265SDimitry Andric                  .addDef(ResVReg)
75181ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType));
75281ad6265SDimitry Andric   for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i)
75381ad6265SDimitry Andric     MIB.addUse(I.getOperand(i).getReg());
75481ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
75581ad6265SDimitry Andric }
75681ad6265SDimitry Andric 
75781ad6265SDimitry Andric bool SPIRVInstructionSelector::selectCmp(Register ResVReg,
75881ad6265SDimitry Andric                                          const SPIRVType *ResType,
75981ad6265SDimitry Andric                                          unsigned CmpOpc,
76081ad6265SDimitry Andric                                          MachineInstr &I) const {
76181ad6265SDimitry Andric   Register Cmp0 = I.getOperand(2).getReg();
76281ad6265SDimitry Andric   Register Cmp1 = I.getOperand(3).getReg();
76381ad6265SDimitry Andric   assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() ==
76481ad6265SDimitry Andric              GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() &&
76581ad6265SDimitry Andric          "CMP operands should have the same type");
76681ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(CmpOpc))
76781ad6265SDimitry Andric       .addDef(ResVReg)
76881ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
76981ad6265SDimitry Andric       .addUse(Cmp0)
77081ad6265SDimitry Andric       .addUse(Cmp1)
77181ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
77281ad6265SDimitry Andric }
77381ad6265SDimitry Andric 
77481ad6265SDimitry Andric bool SPIRVInstructionSelector::selectICmp(Register ResVReg,
77581ad6265SDimitry Andric                                           const SPIRVType *ResType,
77681ad6265SDimitry Andric                                           MachineInstr &I) const {
77781ad6265SDimitry Andric   auto Pred = I.getOperand(1).getPredicate();
77881ad6265SDimitry Andric   unsigned CmpOpc;
77981ad6265SDimitry Andric 
78081ad6265SDimitry Andric   Register CmpOperand = I.getOperand(2).getReg();
78181ad6265SDimitry Andric   if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer))
78281ad6265SDimitry Andric     CmpOpc = getPtrCmpOpcode(Pred);
78381ad6265SDimitry Andric   else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool))
78481ad6265SDimitry Andric     CmpOpc = getBoolCmpOpcode(Pred);
78581ad6265SDimitry Andric   else
78681ad6265SDimitry Andric     CmpOpc = getICmpOpcode(Pred);
78781ad6265SDimitry Andric   return selectCmp(ResVReg, ResType, CmpOpc, I);
78881ad6265SDimitry Andric }
78981ad6265SDimitry Andric 
79081ad6265SDimitry Andric void SPIRVInstructionSelector::renderFImm32(MachineInstrBuilder &MIB,
79181ad6265SDimitry Andric                                             const MachineInstr &I,
79281ad6265SDimitry Andric                                             int OpIdx) const {
79381ad6265SDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
79481ad6265SDimitry Andric          "Expected G_FCONSTANT");
79581ad6265SDimitry Andric   const ConstantFP *FPImm = I.getOperand(1).getFPImm();
79681ad6265SDimitry Andric   addNumImm(FPImm->getValueAPF().bitcastToAPInt(), MIB);
79781ad6265SDimitry Andric }
79881ad6265SDimitry Andric 
79981ad6265SDimitry Andric void SPIRVInstructionSelector::renderImm32(MachineInstrBuilder &MIB,
80081ad6265SDimitry Andric                                            const MachineInstr &I,
80181ad6265SDimitry Andric                                            int OpIdx) const {
80281ad6265SDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
80381ad6265SDimitry Andric          "Expected G_CONSTANT");
80481ad6265SDimitry Andric   addNumImm(I.getOperand(1).getCImm()->getValue(), MIB);
80581ad6265SDimitry Andric }
80681ad6265SDimitry Andric 
80781ad6265SDimitry Andric Register
80881ad6265SDimitry Andric SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I,
80981ad6265SDimitry Andric                                            const SPIRVType *ResType) const {
810*753f127fSDimitry Andric   Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32);
81181ad6265SDimitry Andric   const SPIRVType *SpvI32Ty =
81281ad6265SDimitry Andric       ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII);
813*753f127fSDimitry Andric   // Find a constant in DT or build a new one.
814*753f127fSDimitry Andric   auto ConstInt = ConstantInt::get(LLVMTy, Val);
815*753f127fSDimitry Andric   Register NewReg = GR.find(ConstInt, GR.CurMF);
816*753f127fSDimitry Andric   if (!NewReg.isValid()) {
81781ad6265SDimitry Andric     NewReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
818*753f127fSDimitry Andric     GR.add(ConstInt, GR.CurMF, NewReg);
81981ad6265SDimitry Andric     MachineInstr *MI;
82081ad6265SDimitry Andric     MachineBasicBlock &BB = *I.getParent();
82181ad6265SDimitry Andric     if (Val == 0) {
82281ad6265SDimitry Andric       MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
82381ad6265SDimitry Andric                .addDef(NewReg)
82481ad6265SDimitry Andric                .addUse(GR.getSPIRVTypeID(SpvI32Ty));
82581ad6265SDimitry Andric     } else {
82681ad6265SDimitry Andric       MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
82781ad6265SDimitry Andric                .addDef(NewReg)
82881ad6265SDimitry Andric                .addUse(GR.getSPIRVTypeID(SpvI32Ty))
82981ad6265SDimitry Andric                .addImm(APInt(32, Val).getZExtValue());
83081ad6265SDimitry Andric     }
83181ad6265SDimitry Andric     constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
832*753f127fSDimitry Andric   }
83381ad6265SDimitry Andric   return NewReg;
83481ad6265SDimitry Andric }
83581ad6265SDimitry Andric 
83681ad6265SDimitry Andric bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
83781ad6265SDimitry Andric                                           const SPIRVType *ResType,
83881ad6265SDimitry Andric                                           MachineInstr &I) const {
83981ad6265SDimitry Andric   unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate());
84081ad6265SDimitry Andric   return selectCmp(ResVReg, ResType, CmpOp, I);
84181ad6265SDimitry Andric }
84281ad6265SDimitry Andric 
84381ad6265SDimitry Andric Register SPIRVInstructionSelector::buildZerosVal(const SPIRVType *ResType,
84481ad6265SDimitry Andric                                                  MachineInstr &I) const {
84581ad6265SDimitry Andric   return buildI32Constant(0, I, ResType);
84681ad6265SDimitry Andric }
84781ad6265SDimitry Andric 
84881ad6265SDimitry Andric Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
84981ad6265SDimitry Andric                                                 const SPIRVType *ResType,
85081ad6265SDimitry Andric                                                 MachineInstr &I) const {
85181ad6265SDimitry Andric   unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
85281ad6265SDimitry Andric   APInt One = AllOnes ? APInt::getAllOnesValue(BitWidth)
85381ad6265SDimitry Andric                       : APInt::getOneBitSet(BitWidth, 0);
85481ad6265SDimitry Andric   Register OneReg = buildI32Constant(One.getZExtValue(), I, ResType);
85581ad6265SDimitry Andric   if (ResType->getOpcode() == SPIRV::OpTypeVector) {
85681ad6265SDimitry Andric     const unsigned NumEles = ResType->getOperand(2).getImm();
85781ad6265SDimitry Andric     Register OneVec = MRI->createVirtualRegister(&SPIRV::IDRegClass);
85881ad6265SDimitry Andric     unsigned Opcode = SPIRV::OpConstantComposite;
85981ad6265SDimitry Andric     auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
86081ad6265SDimitry Andric                    .addDef(OneVec)
86181ad6265SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType));
86281ad6265SDimitry Andric     for (unsigned i = 0; i < NumEles; ++i)
86381ad6265SDimitry Andric       MIB.addUse(OneReg);
86481ad6265SDimitry Andric     constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
86581ad6265SDimitry Andric     return OneVec;
86681ad6265SDimitry Andric   }
86781ad6265SDimitry Andric   return OneReg;
86881ad6265SDimitry Andric }
86981ad6265SDimitry Andric 
87081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectSelect(Register ResVReg,
87181ad6265SDimitry Andric                                             const SPIRVType *ResType,
87281ad6265SDimitry Andric                                             MachineInstr &I,
87381ad6265SDimitry Andric                                             bool IsSigned) const {
87481ad6265SDimitry Andric   // To extend a bool, we need to use OpSelect between constants.
87581ad6265SDimitry Andric   Register ZeroReg = buildZerosVal(ResType, I);
87681ad6265SDimitry Andric   Register OneReg = buildOnesVal(IsSigned, ResType, I);
87781ad6265SDimitry Andric   bool IsScalarBool =
87881ad6265SDimitry Andric       GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool);
87981ad6265SDimitry Andric   unsigned Opcode =
88081ad6265SDimitry Andric       IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectSIVCond;
88181ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
88281ad6265SDimitry Andric       .addDef(ResVReg)
88381ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
88481ad6265SDimitry Andric       .addUse(I.getOperand(1).getReg())
88581ad6265SDimitry Andric       .addUse(OneReg)
88681ad6265SDimitry Andric       .addUse(ZeroReg)
88781ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
88881ad6265SDimitry Andric }
88981ad6265SDimitry Andric 
89081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectIToF(Register ResVReg,
89181ad6265SDimitry Andric                                           const SPIRVType *ResType,
89281ad6265SDimitry Andric                                           MachineInstr &I, bool IsSigned,
89381ad6265SDimitry Andric                                           unsigned Opcode) const {
89481ad6265SDimitry Andric   Register SrcReg = I.getOperand(1).getReg();
89581ad6265SDimitry Andric   // We can convert bool value directly to float type without OpConvert*ToF,
89681ad6265SDimitry Andric   // however the translator generates OpSelect+OpConvert*ToF, so we do the same.
89781ad6265SDimitry Andric   if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) {
89881ad6265SDimitry Andric     unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
89981ad6265SDimitry Andric     SPIRVType *TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII);
90081ad6265SDimitry Andric     if (ResType->getOpcode() == SPIRV::OpTypeVector) {
90181ad6265SDimitry Andric       const unsigned NumElts = ResType->getOperand(2).getImm();
90281ad6265SDimitry Andric       TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII);
90381ad6265SDimitry Andric     }
90481ad6265SDimitry Andric     SrcReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
90581ad6265SDimitry Andric     selectSelect(SrcReg, TmpType, I, false);
90681ad6265SDimitry Andric   }
90781ad6265SDimitry Andric   return selectUnOpWithSrc(ResVReg, ResType, I, SrcReg, Opcode);
90881ad6265SDimitry Andric }
90981ad6265SDimitry Andric 
91081ad6265SDimitry Andric bool SPIRVInstructionSelector::selectExt(Register ResVReg,
91181ad6265SDimitry Andric                                          const SPIRVType *ResType,
91281ad6265SDimitry Andric                                          MachineInstr &I, bool IsSigned) const {
91381ad6265SDimitry Andric   if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool))
91481ad6265SDimitry Andric     return selectSelect(ResVReg, ResType, I, IsSigned);
91581ad6265SDimitry Andric   unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
91681ad6265SDimitry Andric   return selectUnOp(ResVReg, ResType, I, Opcode);
91781ad6265SDimitry Andric }
91881ad6265SDimitry Andric 
91981ad6265SDimitry Andric bool SPIRVInstructionSelector::selectIntToBool(Register IntReg,
92081ad6265SDimitry Andric                                                Register ResVReg,
92181ad6265SDimitry Andric                                                const SPIRVType *IntTy,
92281ad6265SDimitry Andric                                                const SPIRVType *BoolTy,
92381ad6265SDimitry Andric                                                MachineInstr &I) const {
92481ad6265SDimitry Andric   // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero.
92581ad6265SDimitry Andric   Register BitIntReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
92681ad6265SDimitry Andric   bool IsVectorTy = IntTy->getOpcode() == SPIRV::OpTypeVector;
92781ad6265SDimitry Andric   unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
92881ad6265SDimitry Andric   Register Zero = buildZerosVal(IntTy, I);
92981ad6265SDimitry Andric   Register One = buildOnesVal(false, IntTy, I);
93081ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
93181ad6265SDimitry Andric   BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
93281ad6265SDimitry Andric       .addDef(BitIntReg)
93381ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(IntTy))
93481ad6265SDimitry Andric       .addUse(IntReg)
93581ad6265SDimitry Andric       .addUse(One)
93681ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
93781ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
93881ad6265SDimitry Andric       .addDef(ResVReg)
93981ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(BoolTy))
94081ad6265SDimitry Andric       .addUse(BitIntReg)
94181ad6265SDimitry Andric       .addUse(Zero)
94281ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
94381ad6265SDimitry Andric }
94481ad6265SDimitry Andric 
94581ad6265SDimitry Andric bool SPIRVInstructionSelector::selectTrunc(Register ResVReg,
94681ad6265SDimitry Andric                                            const SPIRVType *ResType,
94781ad6265SDimitry Andric                                            MachineInstr &I) const {
94881ad6265SDimitry Andric   if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool)) {
94981ad6265SDimitry Andric     Register IntReg = I.getOperand(1).getReg();
95081ad6265SDimitry Andric     const SPIRVType *ArgType = GR.getSPIRVTypeForVReg(IntReg);
95181ad6265SDimitry Andric     return selectIntToBool(IntReg, ResVReg, ArgType, ResType, I);
95281ad6265SDimitry Andric   }
95381ad6265SDimitry Andric   bool IsSigned = GR.isScalarOrVectorSigned(ResType);
95481ad6265SDimitry Andric   unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
95581ad6265SDimitry Andric   return selectUnOp(ResVReg, ResType, I, Opcode);
95681ad6265SDimitry Andric }
95781ad6265SDimitry Andric 
95881ad6265SDimitry Andric bool SPIRVInstructionSelector::selectConst(Register ResVReg,
95981ad6265SDimitry Andric                                            const SPIRVType *ResType,
96081ad6265SDimitry Andric                                            const APInt &Imm,
96181ad6265SDimitry Andric                                            MachineInstr &I) const {
96281ad6265SDimitry Andric   assert(ResType->getOpcode() != SPIRV::OpTypePointer || Imm.isNullValue());
96381ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
96481ad6265SDimitry Andric   if (ResType->getOpcode() == SPIRV::OpTypePointer && Imm.isNullValue()) {
96581ad6265SDimitry Andric     return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
96681ad6265SDimitry Andric         .addDef(ResVReg)
96781ad6265SDimitry Andric         .addUse(GR.getSPIRVTypeID(ResType))
96881ad6265SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
96981ad6265SDimitry Andric   }
97081ad6265SDimitry Andric   auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
97181ad6265SDimitry Andric                  .addDef(ResVReg)
97281ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType));
97381ad6265SDimitry Andric   // <=32-bit integers should be caught by the sdag pattern.
97481ad6265SDimitry Andric   assert(Imm.getBitWidth() > 32);
97581ad6265SDimitry Andric   addNumImm(Imm, MIB);
97681ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
97781ad6265SDimitry Andric }
97881ad6265SDimitry Andric 
97981ad6265SDimitry Andric bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg,
98081ad6265SDimitry Andric                                              const SPIRVType *ResType,
98181ad6265SDimitry Andric                                              MachineInstr &I) const {
98281ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef))
98381ad6265SDimitry Andric       .addDef(ResVReg)
98481ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
98581ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
98681ad6265SDimitry Andric }
98781ad6265SDimitry Andric 
98881ad6265SDimitry Andric static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI) {
98981ad6265SDimitry Andric   assert(MO.isReg());
99081ad6265SDimitry Andric   const SPIRVType *TypeInst = MRI->getVRegDef(MO.getReg());
99181ad6265SDimitry Andric   if (TypeInst->getOpcode() != SPIRV::ASSIGN_TYPE)
99281ad6265SDimitry Andric     return false;
99381ad6265SDimitry Andric   assert(TypeInst->getOperand(1).isReg());
99481ad6265SDimitry Andric   MachineInstr *ImmInst = MRI->getVRegDef(TypeInst->getOperand(1).getReg());
99581ad6265SDimitry Andric   return ImmInst->getOpcode() == TargetOpcode::G_CONSTANT;
99681ad6265SDimitry Andric }
99781ad6265SDimitry Andric 
99881ad6265SDimitry Andric static int64_t foldImm(const MachineOperand &MO, MachineRegisterInfo *MRI) {
99981ad6265SDimitry Andric   const SPIRVType *TypeInst = MRI->getVRegDef(MO.getReg());
100081ad6265SDimitry Andric   MachineInstr *ImmInst = MRI->getVRegDef(TypeInst->getOperand(1).getReg());
100181ad6265SDimitry Andric   assert(ImmInst->getOpcode() == TargetOpcode::G_CONSTANT);
100281ad6265SDimitry Andric   return ImmInst->getOperand(1).getCImm()->getZExtValue();
100381ad6265SDimitry Andric }
100481ad6265SDimitry Andric 
100581ad6265SDimitry Andric bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg,
100681ad6265SDimitry Andric                                                const SPIRVType *ResType,
100781ad6265SDimitry Andric                                                MachineInstr &I) const {
100881ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
100981ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeInsert))
101081ad6265SDimitry Andric       .addDef(ResVReg)
101181ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
101281ad6265SDimitry Andric       // object to insert
101381ad6265SDimitry Andric       .addUse(I.getOperand(3).getReg())
101481ad6265SDimitry Andric       // composite to insert into
101581ad6265SDimitry Andric       .addUse(I.getOperand(2).getReg())
101681ad6265SDimitry Andric       // TODO: support arbitrary number of indices
101781ad6265SDimitry Andric       .addImm(foldImm(I.getOperand(4), MRI))
101881ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
101981ad6265SDimitry Andric }
102081ad6265SDimitry Andric 
102181ad6265SDimitry Andric bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg,
102281ad6265SDimitry Andric                                                 const SPIRVType *ResType,
102381ad6265SDimitry Andric                                                 MachineInstr &I) const {
102481ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
102581ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract))
102681ad6265SDimitry Andric       .addDef(ResVReg)
102781ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
102881ad6265SDimitry Andric       .addUse(I.getOperand(2).getReg())
102981ad6265SDimitry Andric       // TODO: support arbitrary number of indices
103081ad6265SDimitry Andric       .addImm(foldImm(I.getOperand(3), MRI))
103181ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
103281ad6265SDimitry Andric }
103381ad6265SDimitry Andric 
103481ad6265SDimitry Andric bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg,
103581ad6265SDimitry Andric                                                const SPIRVType *ResType,
103681ad6265SDimitry Andric                                                MachineInstr &I) const {
103781ad6265SDimitry Andric   if (isImm(I.getOperand(4), MRI))
103881ad6265SDimitry Andric     return selectInsertVal(ResVReg, ResType, I);
103981ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
104081ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorInsertDynamic))
104181ad6265SDimitry Andric       .addDef(ResVReg)
104281ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
104381ad6265SDimitry Andric       .addUse(I.getOperand(2).getReg())
104481ad6265SDimitry Andric       .addUse(I.getOperand(3).getReg())
104581ad6265SDimitry Andric       .addUse(I.getOperand(4).getReg())
104681ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
104781ad6265SDimitry Andric }
104881ad6265SDimitry Andric 
104981ad6265SDimitry Andric bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg,
105081ad6265SDimitry Andric                                                 const SPIRVType *ResType,
105181ad6265SDimitry Andric                                                 MachineInstr &I) const {
105281ad6265SDimitry Andric   if (isImm(I.getOperand(3), MRI))
105381ad6265SDimitry Andric     return selectExtractVal(ResVReg, ResType, I);
105481ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
105581ad6265SDimitry Andric   return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorExtractDynamic))
105681ad6265SDimitry Andric       .addDef(ResVReg)
105781ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
105881ad6265SDimitry Andric       .addUse(I.getOperand(2).getReg())
105981ad6265SDimitry Andric       .addUse(I.getOperand(3).getReg())
106081ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
106181ad6265SDimitry Andric }
106281ad6265SDimitry Andric 
106381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
106481ad6265SDimitry Andric                                          const SPIRVType *ResType,
106581ad6265SDimitry Andric                                          MachineInstr &I) const {
106681ad6265SDimitry Andric   // In general we should also support OpAccessChain instrs here (i.e. not
106781ad6265SDimitry Andric   // PtrAccessChain) but SPIRV-LLVM Translator doesn't emit them at all and so
106881ad6265SDimitry Andric   // do we to stay compliant with its test and more importantly consumers.
106981ad6265SDimitry Andric   unsigned Opcode = I.getOperand(2).getImm() ? SPIRV::OpInBoundsPtrAccessChain
107081ad6265SDimitry Andric                                              : SPIRV::OpPtrAccessChain;
107181ad6265SDimitry Andric   auto Res = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
107281ad6265SDimitry Andric                  .addDef(ResVReg)
107381ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType))
107481ad6265SDimitry Andric                  // Object to get a pointer to.
107581ad6265SDimitry Andric                  .addUse(I.getOperand(3).getReg());
107681ad6265SDimitry Andric   // Adding indices.
107781ad6265SDimitry Andric   for (unsigned i = 4; i < I.getNumExplicitOperands(); ++i)
107881ad6265SDimitry Andric     Res.addUse(I.getOperand(i).getReg());
107981ad6265SDimitry Andric   return Res.constrainAllUses(TII, TRI, RBI);
108081ad6265SDimitry Andric }
108181ad6265SDimitry Andric 
108281ad6265SDimitry Andric bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
108381ad6265SDimitry Andric                                                const SPIRVType *ResType,
108481ad6265SDimitry Andric                                                MachineInstr &I) const {
108581ad6265SDimitry Andric   MachineBasicBlock &BB = *I.getParent();
108681ad6265SDimitry Andric   switch (I.getIntrinsicID()) {
108781ad6265SDimitry Andric   case Intrinsic::spv_load:
108881ad6265SDimitry Andric     return selectLoad(ResVReg, ResType, I);
108981ad6265SDimitry Andric     break;
109081ad6265SDimitry Andric   case Intrinsic::spv_store:
109181ad6265SDimitry Andric     return selectStore(I);
109281ad6265SDimitry Andric     break;
109381ad6265SDimitry Andric   case Intrinsic::spv_extractv:
109481ad6265SDimitry Andric     return selectExtractVal(ResVReg, ResType, I);
109581ad6265SDimitry Andric     break;
109681ad6265SDimitry Andric   case Intrinsic::spv_insertv:
109781ad6265SDimitry Andric     return selectInsertVal(ResVReg, ResType, I);
109881ad6265SDimitry Andric     break;
109981ad6265SDimitry Andric   case Intrinsic::spv_extractelt:
110081ad6265SDimitry Andric     return selectExtractElt(ResVReg, ResType, I);
110181ad6265SDimitry Andric     break;
110281ad6265SDimitry Andric   case Intrinsic::spv_insertelt:
110381ad6265SDimitry Andric     return selectInsertElt(ResVReg, ResType, I);
110481ad6265SDimitry Andric     break;
110581ad6265SDimitry Andric   case Intrinsic::spv_gep:
110681ad6265SDimitry Andric     return selectGEP(ResVReg, ResType, I);
110781ad6265SDimitry Andric     break;
110881ad6265SDimitry Andric   case Intrinsic::spv_unref_global:
110981ad6265SDimitry Andric   case Intrinsic::spv_init_global: {
111081ad6265SDimitry Andric     MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());
111181ad6265SDimitry Andric     MachineInstr *Init = I.getNumExplicitOperands() > 2
111281ad6265SDimitry Andric                              ? MRI->getVRegDef(I.getOperand(2).getReg())
111381ad6265SDimitry Andric                              : nullptr;
111481ad6265SDimitry Andric     assert(MI);
111581ad6265SDimitry Andric     return selectGlobalValue(MI->getOperand(0).getReg(), *MI, Init);
111681ad6265SDimitry Andric   } break;
111781ad6265SDimitry Andric   case Intrinsic::spv_const_composite: {
111881ad6265SDimitry Andric     // If no values are attached, the composite is null constant.
111981ad6265SDimitry Andric     bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands();
112081ad6265SDimitry Andric     unsigned Opcode =
112181ad6265SDimitry Andric         IsNull ? SPIRV::OpConstantNull : SPIRV::OpConstantComposite;
112281ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode))
112381ad6265SDimitry Andric                    .addDef(ResVReg)
112481ad6265SDimitry Andric                    .addUse(GR.getSPIRVTypeID(ResType));
112581ad6265SDimitry Andric     // skip type MD node we already used when generated assign.type for this
112681ad6265SDimitry Andric     if (!IsNull) {
112781ad6265SDimitry Andric       for (unsigned i = I.getNumExplicitDefs() + 1;
112881ad6265SDimitry Andric            i < I.getNumExplicitOperands(); ++i) {
112981ad6265SDimitry Andric         MIB.addUse(I.getOperand(i).getReg());
113081ad6265SDimitry Andric       }
113181ad6265SDimitry Andric     }
113281ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
113381ad6265SDimitry Andric   } break;
113481ad6265SDimitry Andric   case Intrinsic::spv_assign_name: {
113581ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName));
113681ad6265SDimitry Andric     MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg());
113781ad6265SDimitry Andric     for (unsigned i = I.getNumExplicitDefs() + 2;
113881ad6265SDimitry Andric          i < I.getNumExplicitOperands(); ++i) {
113981ad6265SDimitry Andric       MIB.addImm(I.getOperand(i).getImm());
114081ad6265SDimitry Andric     }
114181ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
114281ad6265SDimitry Andric   } break;
114381ad6265SDimitry Andric   case Intrinsic::spv_switch: {
114481ad6265SDimitry Andric     auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch));
114581ad6265SDimitry Andric     for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) {
114681ad6265SDimitry Andric       if (I.getOperand(i).isReg())
114781ad6265SDimitry Andric         MIB.addReg(I.getOperand(i).getReg());
114881ad6265SDimitry Andric       else if (I.getOperand(i).isCImm())
114981ad6265SDimitry Andric         addNumImm(I.getOperand(i).getCImm()->getValue(), MIB);
115081ad6265SDimitry Andric       else if (I.getOperand(i).isMBB())
115181ad6265SDimitry Andric         MIB.addMBB(I.getOperand(i).getMBB());
115281ad6265SDimitry Andric       else
115381ad6265SDimitry Andric         llvm_unreachable("Unexpected OpSwitch operand");
115481ad6265SDimitry Andric     }
115581ad6265SDimitry Andric     return MIB.constrainAllUses(TII, TRI, RBI);
115681ad6265SDimitry Andric   } break;
115781ad6265SDimitry Andric   default:
115881ad6265SDimitry Andric     llvm_unreachable("Intrinsic selection not implemented");
115981ad6265SDimitry Andric   }
116081ad6265SDimitry Andric   return true;
116181ad6265SDimitry Andric }
116281ad6265SDimitry Andric 
116381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg,
116481ad6265SDimitry Andric                                                 const SPIRVType *ResType,
116581ad6265SDimitry Andric                                                 MachineInstr &I) const {
116681ad6265SDimitry Andric   return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
116781ad6265SDimitry Andric       .addDef(ResVReg)
116881ad6265SDimitry Andric       .addUse(GR.getSPIRVTypeID(ResType))
116981ad6265SDimitry Andric       .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
117081ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
117181ad6265SDimitry Andric }
117281ad6265SDimitry Andric 
117381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const {
117481ad6265SDimitry Andric   // InstructionSelector walks backwards through the instructions. We can use
117581ad6265SDimitry Andric   // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR
117681ad6265SDimitry Andric   // first, so can generate an OpBranchConditional here. If there is no
117781ad6265SDimitry Andric   // G_BRCOND, we just use OpBranch for a regular unconditional branch.
117881ad6265SDimitry Andric   const MachineInstr *PrevI = I.getPrevNode();
117981ad6265SDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
118081ad6265SDimitry Andric   if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) {
118181ad6265SDimitry Andric     return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
118281ad6265SDimitry Andric         .addUse(PrevI->getOperand(0).getReg())
118381ad6265SDimitry Andric         .addMBB(PrevI->getOperand(1).getMBB())
118481ad6265SDimitry Andric         .addMBB(I.getOperand(0).getMBB())
118581ad6265SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
118681ad6265SDimitry Andric   }
118781ad6265SDimitry Andric   return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch))
118881ad6265SDimitry Andric       .addMBB(I.getOperand(0).getMBB())
118981ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
119081ad6265SDimitry Andric }
119181ad6265SDimitry Andric 
119281ad6265SDimitry Andric bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const {
119381ad6265SDimitry Andric   // InstructionSelector walks backwards through the instructions. For an
119481ad6265SDimitry Andric   // explicit conditional branch with no fallthrough, we use both a G_BR and a
119581ad6265SDimitry Andric   // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and
119681ad6265SDimitry Andric   // generate the OpBranchConditional in selectBranch above.
119781ad6265SDimitry Andric   //
119881ad6265SDimitry Andric   // If an OpBranchConditional has been generated, we simply return, as the work
119981ad6265SDimitry Andric   // is alread done. If there is no OpBranchConditional, LLVM must be relying on
120081ad6265SDimitry Andric   // implicit fallthrough to the next basic block, so we need to create an
120181ad6265SDimitry Andric   // OpBranchConditional with an explicit "false" argument pointing to the next
120281ad6265SDimitry Andric   // basic block that LLVM would fall through to.
120381ad6265SDimitry Andric   const MachineInstr *NextI = I.getNextNode();
120481ad6265SDimitry Andric   // Check if this has already been successfully selected.
120581ad6265SDimitry Andric   if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional)
120681ad6265SDimitry Andric     return true;
120781ad6265SDimitry Andric   // Must be relying on implicit block fallthrough, so generate an
120881ad6265SDimitry Andric   // OpBranchConditional with the "next" basic block as the "false" target.
120981ad6265SDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
121081ad6265SDimitry Andric   unsigned NextMBBNum = MBB.getNextNode()->getNumber();
121181ad6265SDimitry Andric   MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum);
121281ad6265SDimitry Andric   return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional))
121381ad6265SDimitry Andric       .addUse(I.getOperand(0).getReg())
121481ad6265SDimitry Andric       .addMBB(I.getOperand(1).getMBB())
121581ad6265SDimitry Andric       .addMBB(NextMBB)
121681ad6265SDimitry Andric       .constrainAllUses(TII, TRI, RBI);
121781ad6265SDimitry Andric }
121881ad6265SDimitry Andric 
121981ad6265SDimitry Andric bool SPIRVInstructionSelector::selectPhi(Register ResVReg,
122081ad6265SDimitry Andric                                          const SPIRVType *ResType,
122181ad6265SDimitry Andric                                          MachineInstr &I) const {
122281ad6265SDimitry Andric   auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpPhi))
122381ad6265SDimitry Andric                  .addDef(ResVReg)
122481ad6265SDimitry Andric                  .addUse(GR.getSPIRVTypeID(ResType));
122581ad6265SDimitry Andric   const unsigned NumOps = I.getNumOperands();
122681ad6265SDimitry Andric   for (unsigned i = 1; i < NumOps; i += 2) {
122781ad6265SDimitry Andric     MIB.addUse(I.getOperand(i + 0).getReg());
122881ad6265SDimitry Andric     MIB.addMBB(I.getOperand(i + 1).getMBB());
122981ad6265SDimitry Andric   }
123081ad6265SDimitry Andric   return MIB.constrainAllUses(TII, TRI, RBI);
123181ad6265SDimitry Andric }
123281ad6265SDimitry Andric 
123381ad6265SDimitry Andric bool SPIRVInstructionSelector::selectGlobalValue(
123481ad6265SDimitry Andric     Register ResVReg, MachineInstr &I, const MachineInstr *Init) const {
123581ad6265SDimitry Andric   // FIXME: don't use MachineIRBuilder here, replace it with BuildMI.
123681ad6265SDimitry Andric   MachineIRBuilder MIRBuilder(I);
123781ad6265SDimitry Andric   const GlobalValue *GV = I.getOperand(1).getGlobal();
123881ad6265SDimitry Andric   SPIRVType *ResType = GR.getOrCreateSPIRVType(
123981ad6265SDimitry Andric       GV->getType(), MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false);
124081ad6265SDimitry Andric 
124181ad6265SDimitry Andric   std::string GlobalIdent = GV->getGlobalIdentifier();
124281ad6265SDimitry Andric   // TODO: suport @llvm.global.annotations.
124381ad6265SDimitry Andric   auto GlobalVar = cast<GlobalVariable>(GV);
124481ad6265SDimitry Andric 
124581ad6265SDimitry Andric   bool HasInit = GlobalVar->hasInitializer() &&
124681ad6265SDimitry Andric                  !isa<UndefValue>(GlobalVar->getInitializer());
124781ad6265SDimitry Andric   // Skip empty declaration for GVs with initilaizers till we get the decl with
124881ad6265SDimitry Andric   // passed initializer.
124981ad6265SDimitry Andric   if (HasInit && !Init)
125081ad6265SDimitry Andric     return true;
125181ad6265SDimitry Andric 
125281ad6265SDimitry Andric   unsigned AddrSpace = GV->getAddressSpace();
125381ad6265SDimitry Andric   SPIRV::StorageClass Storage = addressSpaceToStorageClass(AddrSpace);
125481ad6265SDimitry Andric   bool HasLnkTy = GV->getLinkage() != GlobalValue::InternalLinkage &&
125581ad6265SDimitry Andric                   Storage != SPIRV::StorageClass::Function;
125681ad6265SDimitry Andric   SPIRV::LinkageType LnkType =
125781ad6265SDimitry Andric       (GV->isDeclaration() || GV->hasAvailableExternallyLinkage())
125881ad6265SDimitry Andric           ? SPIRV::LinkageType::Import
125981ad6265SDimitry Andric           : SPIRV::LinkageType::Export;
126081ad6265SDimitry Andric 
126181ad6265SDimitry Andric   Register Reg = GR.buildGlobalVariable(ResVReg, ResType, GlobalIdent, GV,
126281ad6265SDimitry Andric                                         Storage, Init, GlobalVar->isConstant(),
126381ad6265SDimitry Andric                                         HasLnkTy, LnkType, MIRBuilder, true);
126481ad6265SDimitry Andric   return Reg.isValid();
126581ad6265SDimitry Andric }
126681ad6265SDimitry Andric 
126781ad6265SDimitry Andric namespace llvm {
126881ad6265SDimitry Andric InstructionSelector *
126981ad6265SDimitry Andric createSPIRVInstructionSelector(const SPIRVTargetMachine &TM,
127081ad6265SDimitry Andric                                const SPIRVSubtarget &Subtarget,
127181ad6265SDimitry Andric                                const RegisterBankInfo &RBI) {
127281ad6265SDimitry Andric   return new SPIRVInstructionSelector(TM, Subtarget, RBI);
127381ad6265SDimitry Andric }
127481ad6265SDimitry Andric } // namespace llvm
1275