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