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