1eab7d363SIlia Diachkov //===- SPIRVInstructionSelector.cpp ------------------------------*- C++ -*-==// 2eab7d363SIlia Diachkov // 3eab7d363SIlia Diachkov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4eab7d363SIlia Diachkov // See https://llvm.org/LICENSE.txt for license information. 5eab7d363SIlia Diachkov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6eab7d363SIlia Diachkov // 7eab7d363SIlia Diachkov //===----------------------------------------------------------------------===// 8eab7d363SIlia Diachkov // 9eab7d363SIlia Diachkov // This file implements the targeting of the InstructionSelector class for 10eab7d363SIlia Diachkov // SPIRV. 11eab7d363SIlia Diachkov // TODO: This should be generated by TableGen. 12eab7d363SIlia Diachkov // 13eab7d363SIlia Diachkov //===----------------------------------------------------------------------===// 14eab7d363SIlia Diachkov 158b732658SPaulo Matos #include "MCTargetDesc/SPIRVBaseInfo.h" 1605640657SPaulo Matos #include "MCTargetDesc/SPIRVMCTargetDesc.h" 17eab7d363SIlia Diachkov #include "SPIRV.h" 18eab7d363SIlia Diachkov #include "SPIRVGlobalRegistry.h" 19eab7d363SIlia Diachkov #include "SPIRVInstrInfo.h" 20eab7d363SIlia Diachkov #include "SPIRVRegisterBankInfo.h" 21eab7d363SIlia Diachkov #include "SPIRVRegisterInfo.h" 22eab7d363SIlia Diachkov #include "SPIRVTargetMachine.h" 23eab7d363SIlia Diachkov #include "SPIRVUtils.h" 24eab7d363SIlia Diachkov #include "llvm/ADT/APFloat.h" 25ba572abeSSteven Perron #include "llvm/ADT/StringExtras.h" 261fe7d9c7Spvanhout #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h" 277c760b22SSameer Sahasrabuddhe #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 28eab7d363SIlia Diachkov #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" 29eab7d363SIlia Diachkov #include "llvm/CodeGen/MachineInstrBuilder.h" 30c2483ed5SVyacheslav Levytskyy #include "llvm/CodeGen/MachineModuleInfoImpls.h" 31eab7d363SIlia Diachkov #include "llvm/CodeGen/MachineRegisterInfo.h" 32a9a5a18aSTim Gymnich #include "llvm/CodeGen/Register.h" 3305093e24SFarzon Lotfi #include "llvm/CodeGen/TargetOpcodes.h" 340098f2aeSIlia Diachkov #include "llvm/IR/IntrinsicsSPIRV.h" 35eab7d363SIlia Diachkov #include "llvm/Support/Debug.h" 36380bb51bSjoaosaffran #include "llvm/Support/ErrorHandling.h" 37eab7d363SIlia Diachkov 38eab7d363SIlia Diachkov #define DEBUG_TYPE "spirv-isel" 39eab7d363SIlia Diachkov 40eab7d363SIlia Diachkov using namespace llvm; 41698c8001SIlia Diachkov namespace CL = SPIRV::OpenCLExtInst; 42698c8001SIlia Diachkov namespace GL = SPIRV::GLSLExtInst; 43698c8001SIlia Diachkov 44698c8001SIlia Diachkov using ExtInstList = 45698c8001SIlia Diachkov std::vector<std::pair<SPIRV::InstructionSet::InstructionSet, uint32_t>>; 46eab7d363SIlia Diachkov 47eab7d363SIlia Diachkov namespace { 48eab7d363SIlia Diachkov 49380bb51bSjoaosaffran llvm::SPIRV::SelectionControl::SelectionControl 50380bb51bSjoaosaffran getSelectionOperandForImm(int Imm) { 51380bb51bSjoaosaffran if (Imm == 2) 52380bb51bSjoaosaffran return SPIRV::SelectionControl::Flatten; 53380bb51bSjoaosaffran if (Imm == 1) 54380bb51bSjoaosaffran return SPIRV::SelectionControl::DontFlatten; 55380bb51bSjoaosaffran if (Imm == 0) 56380bb51bSjoaosaffran return SPIRV::SelectionControl::None; 57380bb51bSjoaosaffran llvm_unreachable("Invalid immediate"); 58380bb51bSjoaosaffran } 59380bb51bSjoaosaffran 60eab7d363SIlia Diachkov #define GET_GLOBALISEL_PREDICATE_BITSET 61eab7d363SIlia Diachkov #include "SPIRVGenGlobalISel.inc" 62eab7d363SIlia Diachkov #undef GET_GLOBALISEL_PREDICATE_BITSET 63eab7d363SIlia Diachkov 64eab7d363SIlia Diachkov class SPIRVInstructionSelector : public InstructionSelector { 65eab7d363SIlia Diachkov const SPIRVSubtarget &STI; 66eab7d363SIlia Diachkov const SPIRVInstrInfo &TII; 67eab7d363SIlia Diachkov const SPIRVRegisterInfo &TRI; 68eab7d363SIlia Diachkov const RegisterBankInfo &RBI; 69eab7d363SIlia Diachkov SPIRVGlobalRegistry &GR; 70eab7d363SIlia Diachkov MachineRegisterInfo *MRI; 71f9c98068SVyacheslav Levytskyy MachineFunction *HasVRegsReset = nullptr; 72eab7d363SIlia Diachkov 73b9d62310SVyacheslav Levytskyy /// We need to keep track of the number we give to anonymous global values to 74b9d62310SVyacheslav Levytskyy /// generate the same name every time when this is needed. 75b9d62310SVyacheslav Levytskyy mutable DenseMap<const GlobalValue *, unsigned> UnnamedGlobalIDs; 76978de2d6SVyacheslav Levytskyy SmallPtrSet<MachineInstr *, 8> DeadMIs; 77b9d62310SVyacheslav Levytskyy 78eab7d363SIlia Diachkov public: 79eab7d363SIlia Diachkov SPIRVInstructionSelector(const SPIRVTargetMachine &TM, 80eab7d363SIlia Diachkov const SPIRVSubtarget &ST, 81eab7d363SIlia Diachkov const RegisterBankInfo &RBI); 82eab7d363SIlia Diachkov void setupMF(MachineFunction &MF, GISelKnownBits *KB, 838444038dSpvanhout CodeGenCoverage *CoverageInfo, ProfileSummaryInfo *PSI, 84eab7d363SIlia Diachkov BlockFrequencyInfo *BFI) override; 85eab7d363SIlia Diachkov // Common selection code. Instruction-specific selection occurs in spvSelect. 86eab7d363SIlia Diachkov bool select(MachineInstr &I) override; 87eab7d363SIlia Diachkov static const char *getName() { return DEBUG_TYPE; } 88eab7d363SIlia Diachkov 89eab7d363SIlia Diachkov #define GET_GLOBALISEL_PREDICATES_DECL 90eab7d363SIlia Diachkov #include "SPIRVGenGlobalISel.inc" 91eab7d363SIlia Diachkov #undef GET_GLOBALISEL_PREDICATES_DECL 92eab7d363SIlia Diachkov 93eab7d363SIlia Diachkov #define GET_GLOBALISEL_TEMPORARIES_DECL 94eab7d363SIlia Diachkov #include "SPIRVGenGlobalISel.inc" 95eab7d363SIlia Diachkov #undef GET_GLOBALISEL_TEMPORARIES_DECL 96eab7d363SIlia Diachkov 97eab7d363SIlia Diachkov private: 98f9c98068SVyacheslav Levytskyy void resetVRegsType(MachineFunction &MF); 99f9c98068SVyacheslav Levytskyy 100eab7d363SIlia Diachkov // tblgen-erated 'select' implementation, used as the initial selector for 101eab7d363SIlia Diachkov // the patterns that don't require complex C++. 102eab7d363SIlia Diachkov bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; 103eab7d363SIlia Diachkov 104eab7d363SIlia Diachkov // All instruction-specific selection that didn't happen in "select()". 105eab7d363SIlia Diachkov // Is basically a large Switch/Case delegating to all other select method. 106eab7d363SIlia Diachkov bool spvSelect(Register ResVReg, const SPIRVType *ResType, 107eab7d363SIlia Diachkov MachineInstr &I) const; 108eab7d363SIlia Diachkov 109fb90733eSSarah Spall bool selectFirstBitHigh(Register ResVReg, const SPIRVType *ResType, 110fb90733eSSarah Spall MachineInstr &I, bool IsSigned) const; 111fb90733eSSarah Spall 1124f48abffSAshley Coleman bool selectFirstBitLow(Register ResVReg, const SPIRVType *ResType, 1134f48abffSAshley Coleman MachineInstr &I) const; 114fb90733eSSarah Spall 1154f48abffSAshley Coleman bool selectFirstBitSet16(Register ResVReg, const SPIRVType *ResType, 1164f48abffSAshley Coleman MachineInstr &I, unsigned ExtendOpcode, 1174f48abffSAshley Coleman unsigned BitSetOpcode) const; 1184f48abffSAshley Coleman 1194f48abffSAshley Coleman bool selectFirstBitSet32(Register ResVReg, const SPIRVType *ResType, 120fb90733eSSarah Spall MachineInstr &I, Register SrcReg, 1214f48abffSAshley Coleman unsigned BitSetOpcode) const; 122fb90733eSSarah Spall 1234f48abffSAshley Coleman bool selectFirstBitSet64(Register ResVReg, const SPIRVType *ResType, 1244f48abffSAshley Coleman MachineInstr &I, Register SrcReg, 1254f48abffSAshley Coleman unsigned BitSetOpcode, bool SwapPrimarySide) const; 1264f48abffSAshley Coleman 1274f48abffSAshley Coleman bool selectFirstBitSet64Overflow(Register ResVReg, const SPIRVType *ResType, 1284f48abffSAshley Coleman MachineInstr &I, Register SrcReg, 1294f48abffSAshley Coleman unsigned BitSetOpcode, 1304f48abffSAshley Coleman bool SwapPrimarySide) const; 131fb90733eSSarah Spall 132eab7d363SIlia Diachkov bool selectGlobalValue(Register ResVReg, MachineInstr &I, 133eab7d363SIlia Diachkov const MachineInstr *Init = nullptr) const; 134eab7d363SIlia Diachkov 1355889f684SAshley Coleman bool selectOpWithSrcs(Register ResVReg, const SPIRVType *ResType, 136fb90733eSSarah Spall MachineInstr &I, std::vector<Register> SrcRegs, 137fb90733eSSarah Spall unsigned Opcode) const; 138fb90733eSSarah Spall 139eab7d363SIlia Diachkov bool selectUnOp(Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 140eab7d363SIlia Diachkov unsigned Opcode) const; 141eab7d363SIlia Diachkov 142ecc3bdaaSVyacheslav Levytskyy bool selectBitcast(Register ResVReg, const SPIRVType *ResType, 143ecc3bdaaSVyacheslav Levytskyy MachineInstr &I) const; 144ecc3bdaaSVyacheslav Levytskyy 145eab7d363SIlia Diachkov bool selectLoad(Register ResVReg, const SPIRVType *ResType, 146eab7d363SIlia Diachkov MachineInstr &I) const; 147eab7d363SIlia Diachkov bool selectStore(MachineInstr &I) const; 148eab7d363SIlia Diachkov 149ada70f50SVyacheslav Levytskyy bool selectStackSave(Register ResVReg, const SPIRVType *ResType, 150ada70f50SVyacheslav Levytskyy MachineInstr &I) const; 151ada70f50SVyacheslav Levytskyy bool selectStackRestore(MachineInstr &I) const; 152ada70f50SVyacheslav Levytskyy 153eab7d363SIlia Diachkov bool selectMemOperation(Register ResVReg, MachineInstr &I) const; 154eab7d363SIlia Diachkov 155eab7d363SIlia Diachkov bool selectAtomicRMW(Register ResVReg, const SPIRVType *ResType, 156925768eeSVyacheslav Levytskyy MachineInstr &I, unsigned NewOpcode, 157925768eeSVyacheslav Levytskyy unsigned NegateOpcode = 0) const; 158eab7d363SIlia Diachkov 159eab7d363SIlia Diachkov bool selectAtomicCmpXchg(Register ResVReg, const SPIRVType *ResType, 160eab7d363SIlia Diachkov MachineInstr &I) const; 161eab7d363SIlia Diachkov 162eab7d363SIlia Diachkov bool selectFence(MachineInstr &I) const; 163eab7d363SIlia Diachkov 164eab7d363SIlia Diachkov bool selectAddrSpaceCast(Register ResVReg, const SPIRVType *ResType, 165eab7d363SIlia Diachkov MachineInstr &I) const; 166eab7d363SIlia Diachkov 167105dcc88SFarzon Lotfi bool selectAnyOrAll(Register ResVReg, const SPIRVType *ResType, 168105dcc88SFarzon Lotfi MachineInstr &I, unsigned OpType) const; 169105dcc88SFarzon Lotfi 17005093e24SFarzon Lotfi bool selectAll(Register ResVReg, const SPIRVType *ResType, 17105093e24SFarzon Lotfi MachineInstr &I) const; 17205093e24SFarzon Lotfi 173105dcc88SFarzon Lotfi bool selectAny(Register ResVReg, const SPIRVType *ResType, 174105dcc88SFarzon Lotfi MachineInstr &I) const; 175105dcc88SFarzon Lotfi 176eab7d363SIlia Diachkov bool selectBitreverse(Register ResVReg, const SPIRVType *ResType, 177eab7d363SIlia Diachkov MachineInstr &I) const; 178eab7d363SIlia Diachkov 1792fc7a727SVyacheslav Levytskyy bool selectBuildVector(Register ResVReg, const SPIRVType *ResType, 180eab7d363SIlia Diachkov MachineInstr &I) const; 1810a443f13SVyacheslav Levytskyy bool selectSplatVector(Register ResVReg, const SPIRVType *ResType, 1820a443f13SVyacheslav Levytskyy MachineInstr &I) const; 183eab7d363SIlia Diachkov 184eab7d363SIlia Diachkov bool selectCmp(Register ResVReg, const SPIRVType *ResType, 185eab7d363SIlia Diachkov unsigned comparisonOpcode, MachineInstr &I) const; 186c098435eSJoshua Batista bool selectCross(Register ResVReg, const SPIRVType *ResType, 187c098435eSJoshua Batista MachineInstr &I) const; 188bc6c0681Sjoaosaffran bool selectDiscard(Register ResVReg, const SPIRVType *ResType, 189bc6c0681Sjoaosaffran MachineInstr &I) const; 190bc6c0681Sjoaosaffran 191eab7d363SIlia Diachkov bool selectICmp(Register ResVReg, const SPIRVType *ResType, 192eab7d363SIlia Diachkov MachineInstr &I) const; 193eab7d363SIlia Diachkov bool selectFCmp(Register ResVReg, const SPIRVType *ResType, 194eab7d363SIlia Diachkov MachineInstr &I) const; 195eab7d363SIlia Diachkov 196a9a5a18aSTim Gymnich bool selectSign(Register ResVReg, const SPIRVType *ResType, 197a9a5a18aSTim Gymnich MachineInstr &I) const; 198a9a5a18aSTim Gymnich 199319c7a42SGreg Roth bool selectFloatDot(Register ResVReg, const SPIRVType *ResType, 200319c7a42SGreg Roth MachineInstr &I) const; 201319c7a42SGreg Roth 202a059b299SVyacheslav Levytskyy bool selectOverflowArith(Register ResVReg, const SPIRVType *ResType, 203a059b299SVyacheslav Levytskyy MachineInstr &I, unsigned Opcode) const; 204a059b299SVyacheslav Levytskyy 205319c7a42SGreg Roth bool selectIntegerDot(Register ResVReg, const SPIRVType *ResType, 206dcd69ddeSFinn Plummer MachineInstr &I, bool Signed) const; 207dcd69ddeSFinn Plummer 208dcd69ddeSFinn Plummer bool selectIntegerDotExpansion(Register ResVReg, const SPIRVType *ResType, 209319c7a42SGreg Roth MachineInstr &I) const; 210319c7a42SGreg Roth 2113cdac067SFinn Plummer template <bool Signed> 2123cdac067SFinn Plummer bool selectDot4AddPacked(Register ResVReg, const SPIRVType *ResType, 2133cdac067SFinn Plummer MachineInstr &I) const; 2143cdac067SFinn Plummer template <bool Signed> 2153cdac067SFinn Plummer bool selectDot4AddPackedExpansion(Register ResVReg, const SPIRVType *ResType, 2163cdac067SFinn Plummer MachineInstr &I) const; 2173cdac067SFinn Plummer 218*aab25f20SAdam Yang bool selectWaveReduceMax(Register ResVReg, const SPIRVType *ResType, 219*aab25f20SAdam Yang MachineInstr &I, bool IsUnsigned) const; 220*aab25f20SAdam Yang 2214446a984SAdam Yang bool selectWaveReduceSum(Register ResVReg, const SPIRVType *ResType, 2224446a984SAdam Yang MachineInstr &I) const; 2234446a984SAdam Yang 224eab7d363SIlia Diachkov void renderImm32(MachineInstrBuilder &MIB, const MachineInstr &I, 225eab7d363SIlia Diachkov int OpIdx) const; 22667d3ef74SVyacheslav Levytskyy void renderFImm64(MachineInstrBuilder &MIB, const MachineInstr &I, 227eab7d363SIlia Diachkov int OpIdx) const; 228eab7d363SIlia Diachkov 229eab7d363SIlia Diachkov bool selectConst(Register ResVReg, const SPIRVType *ResType, const APInt &Imm, 230eab7d363SIlia Diachkov MachineInstr &I) const; 231eab7d363SIlia Diachkov 232eab7d363SIlia Diachkov bool selectSelect(Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 233eab7d363SIlia Diachkov bool IsSigned) const; 234eab7d363SIlia Diachkov bool selectIToF(Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 235eab7d363SIlia Diachkov bool IsSigned, unsigned Opcode) const; 236eab7d363SIlia Diachkov bool selectExt(Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 237eab7d363SIlia Diachkov bool IsSigned) const; 238eab7d363SIlia Diachkov 239eab7d363SIlia Diachkov bool selectTrunc(Register ResVReg, const SPIRVType *ResType, 240eab7d363SIlia Diachkov MachineInstr &I) const; 241eab7d363SIlia Diachkov 2420f131704SVyacheslav Levytskyy bool selectSUCmp(Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 2430f131704SVyacheslav Levytskyy bool IsSigned) const; 2440f131704SVyacheslav Levytskyy 245698c8001SIlia Diachkov bool selectIntToBool(Register IntReg, Register ResVReg, MachineInstr &I, 246698c8001SIlia Diachkov const SPIRVType *intTy, const SPIRVType *boolTy) const; 247eab7d363SIlia Diachkov 248eab7d363SIlia Diachkov bool selectOpUndef(Register ResVReg, const SPIRVType *ResType, 249eab7d363SIlia Diachkov MachineInstr &I) const; 2509796b0e9SVyacheslav Levytskyy bool selectFreeze(Register ResVReg, const SPIRVType *ResType, 2519796b0e9SVyacheslav Levytskyy MachineInstr &I) const; 252eab7d363SIlia Diachkov bool selectIntrinsic(Register ResVReg, const SPIRVType *ResType, 253eab7d363SIlia Diachkov MachineInstr &I) const; 2540098f2aeSIlia Diachkov bool selectExtractVal(Register ResVReg, const SPIRVType *ResType, 2550098f2aeSIlia Diachkov MachineInstr &I) const; 2560098f2aeSIlia Diachkov bool selectInsertVal(Register ResVReg, const SPIRVType *ResType, 2570098f2aeSIlia Diachkov MachineInstr &I) const; 2580098f2aeSIlia Diachkov bool selectExtractElt(Register ResVReg, const SPIRVType *ResType, 2590098f2aeSIlia Diachkov MachineInstr &I) const; 2600098f2aeSIlia Diachkov bool selectInsertElt(Register ResVReg, const SPIRVType *ResType, 2610098f2aeSIlia Diachkov MachineInstr &I) const; 2620098f2aeSIlia Diachkov bool selectGEP(Register ResVReg, const SPIRVType *ResType, 2630098f2aeSIlia Diachkov MachineInstr &I) const; 264eab7d363SIlia Diachkov 265eab7d363SIlia Diachkov bool selectFrameIndex(Register ResVReg, const SPIRVType *ResType, 266eab7d363SIlia Diachkov MachineInstr &I) const; 267ada70f50SVyacheslav Levytskyy bool selectAllocaArray(Register ResVReg, const SPIRVType *ResType, 268ada70f50SVyacheslav Levytskyy MachineInstr &I) const; 269eab7d363SIlia Diachkov 270eab7d363SIlia Diachkov bool selectBranch(MachineInstr &I) const; 271eab7d363SIlia Diachkov bool selectBranchCond(MachineInstr &I) const; 272eab7d363SIlia Diachkov 273eab7d363SIlia Diachkov bool selectPhi(Register ResVReg, const SPIRVType *ResType, 274eab7d363SIlia Diachkov MachineInstr &I) const; 275eab7d363SIlia Diachkov 2760fe8e70cSFinn Plummer [[maybe_unused]] bool selectExtInst(Register ResVReg, 2770fe8e70cSFinn Plummer const SPIRVType *RestType, 2780fe8e70cSFinn Plummer MachineInstr &I, 2790fe8e70cSFinn Plummer GL::GLSLExtInst GLInst) const; 280698c8001SIlia Diachkov bool selectExtInst(Register ResVReg, const SPIRVType *ResType, 281698c8001SIlia Diachkov MachineInstr &I, CL::OpenCLExtInst CLInst) const; 282698c8001SIlia Diachkov bool selectExtInst(Register ResVReg, const SPIRVType *ResType, 283698c8001SIlia Diachkov MachineInstr &I, CL::OpenCLExtInst CLInst, 284698c8001SIlia Diachkov GL::GLSLExtInst GLInst) const; 285698c8001SIlia Diachkov bool selectExtInst(Register ResVReg, const SPIRVType *ResType, 286698c8001SIlia Diachkov MachineInstr &I, const ExtInstList &ExtInsts) const; 287698c8001SIlia Diachkov 2880a2aaab5SNatalie Chouinard bool selectLog10(Register ResVReg, const SPIRVType *ResType, 2890a2aaab5SNatalie Chouinard MachineInstr &I) const; 2900a2aaab5SNatalie Chouinard 2916a38e19cSS. Bharadwaj Yadavalli bool selectSaturate(Register ResVReg, const SPIRVType *ResType, 2926a38e19cSS. Bharadwaj Yadavalli MachineInstr &I) const; 2936a38e19cSS. Bharadwaj Yadavalli 2946735c5ebSAshley Coleman bool selectWaveOpInst(Register ResVReg, const SPIRVType *ResType, 2956735c5ebSAshley Coleman MachineInstr &I, unsigned Opcode) const; 296e520b283SFinn Plummer 2976735c5ebSAshley Coleman bool selectWaveActiveCountBits(Register ResVReg, const SPIRVType *ResType, 2986d13cc94SFinn Plummer MachineInstr &I) const; 2996d13cc94SFinn Plummer 300540d2551SVyacheslav Levytskyy bool selectUnmergeValues(MachineInstr &I) const; 301540d2551SVyacheslav Levytskyy 302a93cbd4eSFinn Plummer bool selectHandleFromBinding(Register &ResVReg, const SPIRVType *ResType, 3035af7ae50SSteven Perron MachineInstr &I) const; 3045af7ae50SSteven Perron 30534ba84feSSteven Perron bool selectReadImageIntrinsic(Register &ResVReg, const SPIRVType *ResType, 306ba572abeSSteven Perron MachineInstr &I) const; 30734ba84feSSteven Perron bool selectImageWriteIntrinsic(MachineInstr &I) const; 3084b692a95SSteven Perron bool selectResourceGetPointer(Register &ResVReg, const SPIRVType *ResType, 3094b692a95SSteven Perron MachineInstr &I) const; 310756fe54dSSteven Perron 3113e79c7feSVyacheslav Levytskyy // Utilities 312a93cbd4eSFinn Plummer std::pair<Register, bool> 313a93cbd4eSFinn Plummer buildI32Constant(uint32_t Val, MachineInstr &I, 314eab7d363SIlia Diachkov const SPIRVType *ResType = nullptr) const; 315eab7d363SIlia Diachkov 316eab7d363SIlia Diachkov Register buildZerosVal(const SPIRVType *ResType, MachineInstr &I) const; 31705093e24SFarzon Lotfi Register buildZerosValF(const SPIRVType *ResType, MachineInstr &I) const; 318eab7d363SIlia Diachkov Register buildOnesVal(bool AllOnes, const SPIRVType *ResType, 319eab7d363SIlia Diachkov MachineInstr &I) const; 3206a38e19cSS. Bharadwaj Yadavalli Register buildOnesValF(const SPIRVType *ResType, MachineInstr &I) const; 321b0d03cccSVyacheslav Levytskyy 322b0d03cccSVyacheslav Levytskyy bool wrapIntoSpecConstantOp(MachineInstr &I, 323b0d03cccSVyacheslav Levytskyy SmallVector<Register> &CompositeArgs) const; 3243e79c7feSVyacheslav Levytskyy 3253e79c7feSVyacheslav Levytskyy Register getUcharPtrTypeReg(MachineInstr &I, 3263e79c7feSVyacheslav Levytskyy SPIRV::StorageClass::StorageClass SC) const; 3273e79c7feSVyacheslav Levytskyy MachineInstrBuilder buildSpecConstantOp(MachineInstr &I, Register Dest, 3283e79c7feSVyacheslav Levytskyy Register Src, Register DestType, 3293e79c7feSVyacheslav Levytskyy uint32_t Opcode) const; 3303e79c7feSVyacheslav Levytskyy MachineInstrBuilder buildConstGenericPtr(MachineInstr &I, Register SrcPtr, 3313e79c7feSVyacheslav Levytskyy SPIRVType *SrcPtrTy) const; 3325af7ae50SSteven Perron Register buildPointerToResource(const SPIRVType *ResType, uint32_t Set, 3335af7ae50SSteven Perron uint32_t Binding, uint32_t ArraySize, 334d8295e2eSSteven Perron Register IndexReg, bool IsNonUniform, 3355af7ae50SSteven Perron MachineIRBuilder MIRBuilder) const; 336ba572abeSSteven Perron SPIRVType *widenTypeToVec4(const SPIRVType *Type, MachineInstr &I) const; 33734ba84feSSteven Perron bool extractSubvector(Register &ResVReg, const SPIRVType *ResType, 338ba572abeSSteven Perron Register &ReadReg, MachineInstr &InsertionPoint) const; 3394b692a95SSteven Perron bool generateImageRead(Register &ResVReg, const SPIRVType *ResType, 3404b692a95SSteven Perron Register ImageReg, Register IdxReg, DebugLoc Loc, 3414b692a95SSteven Perron MachineInstr &Pos) const; 34242633cf2SVyacheslav Levytskyy bool BuildCOPY(Register DestReg, Register SrcReg, MachineInstr &I) const; 343951a284fSZhengxing li bool loadVec3BuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue, 344951a284fSZhengxing li Register ResVReg, const SPIRVType *ResType, 345951a284fSZhengxing li MachineInstr &I) const; 3464b692a95SSteven Perron bool loadHandleBeforePosition(Register &HandleReg, const SPIRVType *ResType, 3474b692a95SSteven Perron GIntrinsic &HandleDef, MachineInstr &Pos) const; 348eab7d363SIlia Diachkov }; 349eab7d363SIlia Diachkov 350eab7d363SIlia Diachkov } // end anonymous namespace 351eab7d363SIlia Diachkov 352eab7d363SIlia Diachkov #define GET_GLOBALISEL_IMPL 353eab7d363SIlia Diachkov #include "SPIRVGenGlobalISel.inc" 354eab7d363SIlia Diachkov #undef GET_GLOBALISEL_IMPL 355eab7d363SIlia Diachkov 356eab7d363SIlia Diachkov SPIRVInstructionSelector::SPIRVInstructionSelector(const SPIRVTargetMachine &TM, 357eab7d363SIlia Diachkov const SPIRVSubtarget &ST, 358eab7d363SIlia Diachkov const RegisterBankInfo &RBI) 359eab7d363SIlia Diachkov : InstructionSelector(), STI(ST), TII(*ST.getInstrInfo()), 360eab7d363SIlia Diachkov TRI(*ST.getRegisterInfo()), RBI(RBI), GR(*ST.getSPIRVGlobalRegistry()), 361eab7d363SIlia Diachkov #define GET_GLOBALISEL_PREDICATES_INIT 362eab7d363SIlia Diachkov #include "SPIRVGenGlobalISel.inc" 363eab7d363SIlia Diachkov #undef GET_GLOBALISEL_PREDICATES_INIT 364eab7d363SIlia Diachkov #define GET_GLOBALISEL_TEMPORARIES_INIT 365eab7d363SIlia Diachkov #include "SPIRVGenGlobalISel.inc" 366eab7d363SIlia Diachkov #undef GET_GLOBALISEL_TEMPORARIES_INIT 367eab7d363SIlia Diachkov { 368eab7d363SIlia Diachkov } 369eab7d363SIlia Diachkov 370eab7d363SIlia Diachkov void SPIRVInstructionSelector::setupMF(MachineFunction &MF, GISelKnownBits *KB, 371cc3af053SFangrui Song CodeGenCoverage *CoverageInfo, 372eab7d363SIlia Diachkov ProfileSummaryInfo *PSI, 373eab7d363SIlia Diachkov BlockFrequencyInfo *BFI) { 374eab7d363SIlia Diachkov MRI = &MF.getRegInfo(); 375eab7d363SIlia Diachkov GR.setCurrentFunc(MF); 376eab7d363SIlia Diachkov InstructionSelector::setupMF(MF, KB, CoverageInfo, PSI, BFI); 377eab7d363SIlia Diachkov } 378eab7d363SIlia Diachkov 379f9c98068SVyacheslav Levytskyy // Ensure that register classes correspond to pattern matching rules. 380f9c98068SVyacheslav Levytskyy void SPIRVInstructionSelector::resetVRegsType(MachineFunction &MF) { 381f9c98068SVyacheslav Levytskyy if (HasVRegsReset == &MF) 382f9c98068SVyacheslav Levytskyy return; 383f9c98068SVyacheslav Levytskyy HasVRegsReset = &MF; 384f9c98068SVyacheslav Levytskyy 385f9c98068SVyacheslav Levytskyy MachineRegisterInfo &MRI = MF.getRegInfo(); 386f9c98068SVyacheslav Levytskyy for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { 387f9c98068SVyacheslav Levytskyy Register Reg = Register::index2VirtReg(I); 38867d3ef74SVyacheslav Levytskyy LLT RegType = MRI.getType(Reg); 38967d3ef74SVyacheslav Levytskyy if (RegType.isScalar()) 39067d3ef74SVyacheslav Levytskyy MRI.setType(Reg, LLT::scalar(64)); 39167d3ef74SVyacheslav Levytskyy else if (RegType.isPointer()) 39267d3ef74SVyacheslav Levytskyy MRI.setType(Reg, LLT::pointer(0, 64)); 39367d3ef74SVyacheslav Levytskyy else if (RegType.isVector()) 39467d3ef74SVyacheslav Levytskyy MRI.setType(Reg, LLT::fixed_vector(2, LLT::scalar(64))); 395f9c98068SVyacheslav Levytskyy } 396f9c98068SVyacheslav Levytskyy for (const auto &MBB : MF) { 397f9c98068SVyacheslav Levytskyy for (const auto &MI : MBB) { 398f9c98068SVyacheslav Levytskyy if (MI.getOpcode() != SPIRV::ASSIGN_TYPE) 399f9c98068SVyacheslav Levytskyy continue; 400f9c98068SVyacheslav Levytskyy Register DstReg = MI.getOperand(0).getReg(); 401f9c98068SVyacheslav Levytskyy LLT DstType = MRI.getType(DstReg); 402f9c98068SVyacheslav Levytskyy Register SrcReg = MI.getOperand(1).getReg(); 403f9c98068SVyacheslav Levytskyy LLT SrcType = MRI.getType(SrcReg); 404f9c98068SVyacheslav Levytskyy if (DstType != SrcType) 405f9c98068SVyacheslav Levytskyy MRI.setType(DstReg, MRI.getType(SrcReg)); 406f9c98068SVyacheslav Levytskyy 407f9c98068SVyacheslav Levytskyy const TargetRegisterClass *DstRC = MRI.getRegClassOrNull(DstReg); 408f9c98068SVyacheslav Levytskyy const TargetRegisterClass *SrcRC = MRI.getRegClassOrNull(SrcReg); 409f9c98068SVyacheslav Levytskyy if (DstRC != SrcRC && SrcRC) 410f9c98068SVyacheslav Levytskyy MRI.setRegClass(DstReg, SrcRC); 411f9c98068SVyacheslav Levytskyy } 412f9c98068SVyacheslav Levytskyy } 413f9c98068SVyacheslav Levytskyy } 414f9c98068SVyacheslav Levytskyy 415b8e1544bSIlia Diachkov static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI); 416b8e1544bSIlia Diachkov 417eab7d363SIlia Diachkov // Defined in SPIRVLegalizerInfo.cpp. 418eab7d363SIlia Diachkov extern bool isTypeFoldingSupported(unsigned Opcode); 419eab7d363SIlia Diachkov 420978de2d6SVyacheslav Levytskyy bool isDead(const MachineInstr &MI, const MachineRegisterInfo &MRI) { 421978de2d6SVyacheslav Levytskyy for (const auto &MO : MI.all_defs()) { 422978de2d6SVyacheslav Levytskyy Register Reg = MO.getReg(); 423978de2d6SVyacheslav Levytskyy if (Reg.isPhysical() || !MRI.use_nodbg_empty(Reg)) 424978de2d6SVyacheslav Levytskyy return false; 425978de2d6SVyacheslav Levytskyy } 426978de2d6SVyacheslav Levytskyy if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE || MI.isFakeUse() || 427978de2d6SVyacheslav Levytskyy MI.isLifetimeMarker()) 428978de2d6SVyacheslav Levytskyy return false; 429978de2d6SVyacheslav Levytskyy if (MI.isPHI()) 430978de2d6SVyacheslav Levytskyy return true; 431978de2d6SVyacheslav Levytskyy if (MI.mayStore() || MI.isCall() || 432978de2d6SVyacheslav Levytskyy (MI.mayLoad() && MI.hasOrderedMemoryRef()) || MI.isPosition() || 433978de2d6SVyacheslav Levytskyy MI.isDebugInstr() || MI.isTerminator() || MI.isJumpTableDebugInfo()) 434978de2d6SVyacheslav Levytskyy return false; 435978de2d6SVyacheslav Levytskyy return true; 436978de2d6SVyacheslav Levytskyy } 437978de2d6SVyacheslav Levytskyy 438eab7d363SIlia Diachkov bool SPIRVInstructionSelector::select(MachineInstr &I) { 439f9c98068SVyacheslav Levytskyy resetVRegsType(*I.getParent()->getParent()); 440f9c98068SVyacheslav Levytskyy 441eab7d363SIlia Diachkov assert(I.getParent() && "Instruction should be in a basic block!"); 442eab7d363SIlia Diachkov assert(I.getParent()->getParent() && "Instruction should be in a function!"); 443eab7d363SIlia Diachkov 444eab7d363SIlia Diachkov Register Opcode = I.getOpcode(); 445eab7d363SIlia Diachkov // If it's not a GMIR instruction, we've selected it already. 446eab7d363SIlia Diachkov if (!isPreISelGenericOpcode(Opcode)) { 447eab7d363SIlia Diachkov if (Opcode == SPIRV::ASSIGN_TYPE) { // These pseudos aren't needed any more. 448b512df66SVyacheslav Levytskyy Register DstReg = I.getOperand(0).getReg(); 449b512df66SVyacheslav Levytskyy Register SrcReg = I.getOperand(1).getReg(); 450b512df66SVyacheslav Levytskyy auto *Def = MRI->getVRegDef(SrcReg); 451eab7d363SIlia Diachkov if (isTypeFoldingSupported(Def->getOpcode())) { 452540d2551SVyacheslav Levytskyy bool Res = selectImpl(I, *CoverageInfo); 45367d3ef74SVyacheslav Levytskyy LLVM_DEBUG({ 45467d3ef74SVyacheslav Levytskyy if (!Res && Def->getOpcode() != TargetOpcode::G_CONSTANT) { 45567d3ef74SVyacheslav Levytskyy dbgs() << "Unexpected pattern in ASSIGN_TYPE.\nInstruction: "; 45667d3ef74SVyacheslav Levytskyy I.print(dbgs()); 45767d3ef74SVyacheslav Levytskyy } 45867d3ef74SVyacheslav Levytskyy }); 459eab7d363SIlia Diachkov assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT); 460978de2d6SVyacheslav Levytskyy if (Res) { 461978de2d6SVyacheslav Levytskyy if (!isTriviallyDead(*Def, *MRI) && isDead(*Def, *MRI)) 462978de2d6SVyacheslav Levytskyy DeadMIs.insert(Def); 463eab7d363SIlia Diachkov return Res; 464eab7d363SIlia Diachkov } 465978de2d6SVyacheslav Levytskyy } 46667d3ef74SVyacheslav Levytskyy MRI->setRegClass(SrcReg, MRI->getRegClass(DstReg)); 467b512df66SVyacheslav Levytskyy MRI->replaceRegWith(SrcReg, DstReg); 4683ed2a813SVyacheslav Levytskyy GR.invalidateMachineInstr(&I); 469eab7d363SIlia Diachkov I.removeFromParent(); 470f61eb416SIlia Diachkov return true; 471eab7d363SIlia Diachkov } else if (I.getNumDefs() == 1) { 47267d3ef74SVyacheslav Levytskyy // Make all vregs 64 bits (for SPIR-V IDs). 47367d3ef74SVyacheslav Levytskyy MRI->setType(I.getOperand(0).getReg(), LLT::scalar(64)); 474eab7d363SIlia Diachkov } 475f61eb416SIlia Diachkov return constrainSelectedInstRegOperands(I, TII, TRI, RBI); 476eab7d363SIlia Diachkov } 477eab7d363SIlia Diachkov 478978de2d6SVyacheslav Levytskyy if (DeadMIs.contains(&I)) { 479978de2d6SVyacheslav Levytskyy // if the instruction has been already made dead by folding it away 480978de2d6SVyacheslav Levytskyy // erase it 481978de2d6SVyacheslav Levytskyy LLVM_DEBUG(dbgs() << "Instruction is folded and dead.\n"); 482978de2d6SVyacheslav Levytskyy salvageDebugInfo(*MRI, I); 4833ed2a813SVyacheslav Levytskyy GR.invalidateMachineInstr(&I); 484978de2d6SVyacheslav Levytskyy I.eraseFromParent(); 485978de2d6SVyacheslav Levytskyy return true; 486978de2d6SVyacheslav Levytskyy } 487978de2d6SVyacheslav Levytskyy 488eab7d363SIlia Diachkov if (I.getNumOperands() != I.getNumExplicitOperands()) { 489eab7d363SIlia Diachkov LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n"); 490eab7d363SIlia Diachkov return false; 491eab7d363SIlia Diachkov } 492eab7d363SIlia Diachkov 493eab7d363SIlia Diachkov // Common code for getting return reg+type, and removing selected instr 494eab7d363SIlia Diachkov // from parent occurs here. Instr-specific selection happens in spvSelect(). 495eab7d363SIlia Diachkov bool HasDefs = I.getNumDefs() > 0; 496eab7d363SIlia Diachkov Register ResVReg = HasDefs ? I.getOperand(0).getReg() : Register(0); 497eab7d363SIlia Diachkov SPIRVType *ResType = HasDefs ? GR.getSPIRVTypeForVReg(ResVReg) : nullptr; 498eab7d363SIlia Diachkov assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE); 499eab7d363SIlia Diachkov if (spvSelect(ResVReg, ResType, I)) { 50067d3ef74SVyacheslav Levytskyy if (HasDefs) // Make all vregs 64 bits (for SPIR-V IDs). 501540d2551SVyacheslav Levytskyy for (unsigned i = 0; i < I.getNumDefs(); ++i) 50267d3ef74SVyacheslav Levytskyy MRI->setType(I.getOperand(i).getReg(), LLT::scalar(64)); 5033ed2a813SVyacheslav Levytskyy GR.invalidateMachineInstr(&I); 504eab7d363SIlia Diachkov I.removeFromParent(); 505eab7d363SIlia Diachkov return true; 506eab7d363SIlia Diachkov } 507eab7d363SIlia Diachkov return false; 508eab7d363SIlia Diachkov } 509eab7d363SIlia Diachkov 510a059b299SVyacheslav Levytskyy static bool mayApplyGenericSelection(unsigned Opcode) { 511a059b299SVyacheslav Levytskyy switch (Opcode) { 512a059b299SVyacheslav Levytskyy case TargetOpcode::G_CONSTANT: 513a059b299SVyacheslav Levytskyy return false; 514a059b299SVyacheslav Levytskyy case TargetOpcode::G_SADDO: 515a059b299SVyacheslav Levytskyy case TargetOpcode::G_SSUBO: 516a059b299SVyacheslav Levytskyy return true; 517a059b299SVyacheslav Levytskyy } 518a059b299SVyacheslav Levytskyy return isTypeFoldingSupported(Opcode); 519a059b299SVyacheslav Levytskyy } 520a059b299SVyacheslav Levytskyy 52142633cf2SVyacheslav Levytskyy bool SPIRVInstructionSelector::BuildCOPY(Register DestReg, Register SrcReg, 52242633cf2SVyacheslav Levytskyy MachineInstr &I) const { 52342633cf2SVyacheslav Levytskyy const TargetRegisterClass *DstRC = MRI->getRegClassOrNull(DestReg); 52442633cf2SVyacheslav Levytskyy const TargetRegisterClass *SrcRC = MRI->getRegClassOrNull(SrcReg); 52542633cf2SVyacheslav Levytskyy if (DstRC != SrcRC && SrcRC) 52642633cf2SVyacheslav Levytskyy MRI->setRegClass(DestReg, SrcRC); 52742633cf2SVyacheslav Levytskyy return BuildMI(*I.getParent(), I, I.getDebugLoc(), 52842633cf2SVyacheslav Levytskyy TII.get(TargetOpcode::COPY)) 52942633cf2SVyacheslav Levytskyy .addDef(DestReg) 53042633cf2SVyacheslav Levytskyy .addUse(SrcReg) 53142633cf2SVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 53242633cf2SVyacheslav Levytskyy } 53342633cf2SVyacheslav Levytskyy 534eab7d363SIlia Diachkov bool SPIRVInstructionSelector::spvSelect(Register ResVReg, 535eab7d363SIlia Diachkov const SPIRVType *ResType, 536eab7d363SIlia Diachkov MachineInstr &I) const { 537eab7d363SIlia Diachkov const unsigned Opcode = I.getOpcode(); 538a059b299SVyacheslav Levytskyy if (mayApplyGenericSelection(Opcode)) 539540d2551SVyacheslav Levytskyy return selectImpl(I, *CoverageInfo); 540eab7d363SIlia Diachkov switch (Opcode) { 541eab7d363SIlia Diachkov case TargetOpcode::G_CONSTANT: 542eab7d363SIlia Diachkov return selectConst(ResVReg, ResType, I.getOperand(1).getCImm()->getValue(), 543eab7d363SIlia Diachkov I); 544eab7d363SIlia Diachkov case TargetOpcode::G_GLOBAL_VALUE: 545eab7d363SIlia Diachkov return selectGlobalValue(ResVReg, I); 546eab7d363SIlia Diachkov case TargetOpcode::G_IMPLICIT_DEF: 547eab7d363SIlia Diachkov return selectOpUndef(ResVReg, ResType, I); 5489796b0e9SVyacheslav Levytskyy case TargetOpcode::G_FREEZE: 5499796b0e9SVyacheslav Levytskyy return selectFreeze(ResVReg, ResType, I); 550eab7d363SIlia Diachkov 5516325dd57SNatalie Chouinard case TargetOpcode::G_INTRINSIC: 552eab7d363SIlia Diachkov case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: 5536d13cc94SFinn Plummer case TargetOpcode::G_INTRINSIC_CONVERGENT: 554d9847cdeSSameer Sahasrabuddhe case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 555eab7d363SIlia Diachkov return selectIntrinsic(ResVReg, ResType, I); 556eab7d363SIlia Diachkov case TargetOpcode::G_BITREVERSE: 557eab7d363SIlia Diachkov return selectBitreverse(ResVReg, ResType, I); 558eab7d363SIlia Diachkov 559eab7d363SIlia Diachkov case TargetOpcode::G_BUILD_VECTOR: 5602fc7a727SVyacheslav Levytskyy return selectBuildVector(ResVReg, ResType, I); 5610a443f13SVyacheslav Levytskyy case TargetOpcode::G_SPLAT_VECTOR: 5620a443f13SVyacheslav Levytskyy return selectSplatVector(ResVReg, ResType, I); 563eab7d363SIlia Diachkov 564eab7d363SIlia Diachkov case TargetOpcode::G_SHUFFLE_VECTOR: { 565eab7d363SIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 566eab7d363SIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorShuffle)) 567eab7d363SIlia Diachkov .addDef(ResVReg) 568eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 569eab7d363SIlia Diachkov .addUse(I.getOperand(1).getReg()) 570eab7d363SIlia Diachkov .addUse(I.getOperand(2).getReg()); 571eab7d363SIlia Diachkov for (auto V : I.getOperand(3).getShuffleMask()) 572eab7d363SIlia Diachkov MIB.addImm(V); 573eab7d363SIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 574eab7d363SIlia Diachkov } 575eab7d363SIlia Diachkov case TargetOpcode::G_MEMMOVE: 576eab7d363SIlia Diachkov case TargetOpcode::G_MEMCPY: 577698c8001SIlia Diachkov case TargetOpcode::G_MEMSET: 578eab7d363SIlia Diachkov return selectMemOperation(ResVReg, I); 579eab7d363SIlia Diachkov 580eab7d363SIlia Diachkov case TargetOpcode::G_ICMP: 581eab7d363SIlia Diachkov return selectICmp(ResVReg, ResType, I); 582eab7d363SIlia Diachkov case TargetOpcode::G_FCMP: 583eab7d363SIlia Diachkov return selectFCmp(ResVReg, ResType, I); 584eab7d363SIlia Diachkov 585eab7d363SIlia Diachkov case TargetOpcode::G_FRAME_INDEX: 586eab7d363SIlia Diachkov return selectFrameIndex(ResVReg, ResType, I); 587eab7d363SIlia Diachkov 588eab7d363SIlia Diachkov case TargetOpcode::G_LOAD: 589eab7d363SIlia Diachkov return selectLoad(ResVReg, ResType, I); 590eab7d363SIlia Diachkov case TargetOpcode::G_STORE: 591eab7d363SIlia Diachkov return selectStore(I); 592eab7d363SIlia Diachkov 593eab7d363SIlia Diachkov case TargetOpcode::G_BR: 594eab7d363SIlia Diachkov return selectBranch(I); 595eab7d363SIlia Diachkov case TargetOpcode::G_BRCOND: 596eab7d363SIlia Diachkov return selectBranchCond(I); 597eab7d363SIlia Diachkov 598eab7d363SIlia Diachkov case TargetOpcode::G_PHI: 599eab7d363SIlia Diachkov return selectPhi(ResVReg, ResType, I); 600eab7d363SIlia Diachkov 601eab7d363SIlia Diachkov case TargetOpcode::G_FPTOSI: 602eab7d363SIlia Diachkov return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToS); 603eab7d363SIlia Diachkov case TargetOpcode::G_FPTOUI: 604eab7d363SIlia Diachkov return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertFToU); 605eab7d363SIlia Diachkov 606eab7d363SIlia Diachkov case TargetOpcode::G_SITOFP: 607eab7d363SIlia Diachkov return selectIToF(ResVReg, ResType, I, true, SPIRV::OpConvertSToF); 608eab7d363SIlia Diachkov case TargetOpcode::G_UITOFP: 609eab7d363SIlia Diachkov return selectIToF(ResVReg, ResType, I, false, SPIRV::OpConvertUToF); 610eab7d363SIlia Diachkov 611eab7d363SIlia Diachkov case TargetOpcode::G_CTPOP: 612eab7d363SIlia Diachkov return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitCount); 613698c8001SIlia Diachkov case TargetOpcode::G_SMIN: 614698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::s_min, GL::SMin); 615698c8001SIlia Diachkov case TargetOpcode::G_UMIN: 616698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::u_min, GL::UMin); 617698c8001SIlia Diachkov 618698c8001SIlia Diachkov case TargetOpcode::G_SMAX: 619698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::s_max, GL::SMax); 620698c8001SIlia Diachkov case TargetOpcode::G_UMAX: 621698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::u_max, GL::UMax); 622698c8001SIlia Diachkov 6230f131704SVyacheslav Levytskyy case TargetOpcode::G_SCMP: 6240f131704SVyacheslav Levytskyy return selectSUCmp(ResVReg, ResType, I, true); 6250f131704SVyacheslav Levytskyy case TargetOpcode::G_UCMP: 6260f131704SVyacheslav Levytskyy return selectSUCmp(ResVReg, ResType, I, false); 6270f131704SVyacheslav Levytskyy 628978de2d6SVyacheslav Levytskyy case TargetOpcode::G_STRICT_FMA: 629698c8001SIlia Diachkov case TargetOpcode::G_FMA: 630698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma); 631698c8001SIlia Diachkov 632978de2d6SVyacheslav Levytskyy case TargetOpcode::G_STRICT_FLDEXP: 633978de2d6SVyacheslav Levytskyy return selectExtInst(ResVReg, ResType, I, CL::ldexp); 634978de2d6SVyacheslav Levytskyy 635698c8001SIlia Diachkov case TargetOpcode::G_FPOW: 636698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::pow, GL::Pow); 637698c8001SIlia Diachkov case TargetOpcode::G_FPOWI: 638698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::pown); 639698c8001SIlia Diachkov 640698c8001SIlia Diachkov case TargetOpcode::G_FEXP: 641698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::exp, GL::Exp); 642698c8001SIlia Diachkov case TargetOpcode::G_FEXP2: 643698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::exp2, GL::Exp2); 644698c8001SIlia Diachkov 645698c8001SIlia Diachkov case TargetOpcode::G_FLOG: 646698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::log, GL::Log); 647698c8001SIlia Diachkov case TargetOpcode::G_FLOG2: 648698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::log2, GL::Log2); 649698c8001SIlia Diachkov case TargetOpcode::G_FLOG10: 6500a2aaab5SNatalie Chouinard return selectLog10(ResVReg, ResType, I); 651698c8001SIlia Diachkov 652698c8001SIlia Diachkov case TargetOpcode::G_FABS: 653698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::fabs, GL::FAbs); 654698c8001SIlia Diachkov case TargetOpcode::G_ABS: 655698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::s_abs, GL::SAbs); 656698c8001SIlia Diachkov 657698c8001SIlia Diachkov case TargetOpcode::G_FMINNUM: 658698c8001SIlia Diachkov case TargetOpcode::G_FMINIMUM: 6591e44d9acSNatalie Chouinard return selectExtInst(ResVReg, ResType, I, CL::fmin, GL::NMin); 660698c8001SIlia Diachkov case TargetOpcode::G_FMAXNUM: 661698c8001SIlia Diachkov case TargetOpcode::G_FMAXIMUM: 6621e44d9acSNatalie Chouinard return selectExtInst(ResVReg, ResType, I, CL::fmax, GL::NMax); 663698c8001SIlia Diachkov 664698c8001SIlia Diachkov case TargetOpcode::G_FCOPYSIGN: 665698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::copysign); 666698c8001SIlia Diachkov 667698c8001SIlia Diachkov case TargetOpcode::G_FCEIL: 668698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::ceil, GL::Ceil); 669698c8001SIlia Diachkov case TargetOpcode::G_FFLOOR: 670698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::floor, GL::Floor); 671698c8001SIlia Diachkov 672698c8001SIlia Diachkov case TargetOpcode::G_FCOS: 673698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::cos, GL::Cos); 674698c8001SIlia Diachkov case TargetOpcode::G_FSIN: 675698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::sin, GL::Sin); 6763e82442fSFarzon Lotfi case TargetOpcode::G_FTAN: 6773e82442fSFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::tan, GL::Tan); 6782ae6889dSFarzon Lotfi case TargetOpcode::G_FACOS: 6792ae6889dSFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::acos, GL::Acos); 6802ae6889dSFarzon Lotfi case TargetOpcode::G_FASIN: 6812ae6889dSFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::asin, GL::Asin); 6822ae6889dSFarzon Lotfi case TargetOpcode::G_FATAN: 6832ae6889dSFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::atan, GL::Atan); 684139688a6STex Riddell case TargetOpcode::G_FATAN2: 685139688a6STex Riddell return selectExtInst(ResVReg, ResType, I, CL::atan2, GL::Atan2); 6862ae6889dSFarzon Lotfi case TargetOpcode::G_FCOSH: 6872ae6889dSFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::cosh, GL::Cosh); 6882ae6889dSFarzon Lotfi case TargetOpcode::G_FSINH: 6892ae6889dSFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::sinh, GL::Sinh); 6902ae6889dSFarzon Lotfi case TargetOpcode::G_FTANH: 6912ae6889dSFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::tanh, GL::Tanh); 692698c8001SIlia Diachkov 693978de2d6SVyacheslav Levytskyy case TargetOpcode::G_STRICT_FSQRT: 694698c8001SIlia Diachkov case TargetOpcode::G_FSQRT: 695698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::sqrt, GL::Sqrt); 696698c8001SIlia Diachkov 697698c8001SIlia Diachkov case TargetOpcode::G_CTTZ: 698698c8001SIlia Diachkov case TargetOpcode::G_CTTZ_ZERO_UNDEF: 699698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::ctz); 700698c8001SIlia Diachkov case TargetOpcode::G_CTLZ: 701698c8001SIlia Diachkov case TargetOpcode::G_CTLZ_ZERO_UNDEF: 702698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::clz); 703698c8001SIlia Diachkov 704698c8001SIlia Diachkov case TargetOpcode::G_INTRINSIC_ROUND: 705698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::round, GL::Round); 706698c8001SIlia Diachkov case TargetOpcode::G_INTRINSIC_ROUNDEVEN: 707698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven); 708698c8001SIlia Diachkov case TargetOpcode::G_INTRINSIC_TRUNC: 709698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::trunc, GL::Trunc); 710698c8001SIlia Diachkov case TargetOpcode::G_FRINT: 711698c8001SIlia Diachkov case TargetOpcode::G_FNEARBYINT: 712698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::rint, GL::RoundEven); 713698c8001SIlia Diachkov 714698c8001SIlia Diachkov case TargetOpcode::G_SMULH: 715698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::s_mul_hi); 716698c8001SIlia Diachkov case TargetOpcode::G_UMULH: 717698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, CL::u_mul_hi); 718eab7d363SIlia Diachkov 719cf9a5a16SVyacheslav Levytskyy case TargetOpcode::G_SADDSAT: 720cf9a5a16SVyacheslav Levytskyy return selectExtInst(ResVReg, ResType, I, CL::s_add_sat); 721cf9a5a16SVyacheslav Levytskyy case TargetOpcode::G_UADDSAT: 722cf9a5a16SVyacheslav Levytskyy return selectExtInst(ResVReg, ResType, I, CL::u_add_sat); 723cf9a5a16SVyacheslav Levytskyy case TargetOpcode::G_SSUBSAT: 724cf9a5a16SVyacheslav Levytskyy return selectExtInst(ResVReg, ResType, I, CL::s_sub_sat); 725cf9a5a16SVyacheslav Levytskyy case TargetOpcode::G_USUBSAT: 726cf9a5a16SVyacheslav Levytskyy return selectExtInst(ResVReg, ResType, I, CL::u_sub_sat); 727cf9a5a16SVyacheslav Levytskyy 728a059b299SVyacheslav Levytskyy case TargetOpcode::G_UADDO: 729a059b299SVyacheslav Levytskyy return selectOverflowArith(ResVReg, ResType, I, 730a059b299SVyacheslav Levytskyy ResType->getOpcode() == SPIRV::OpTypeVector 731a059b299SVyacheslav Levytskyy ? SPIRV::OpIAddCarryV 732a059b299SVyacheslav Levytskyy : SPIRV::OpIAddCarryS); 733a059b299SVyacheslav Levytskyy case TargetOpcode::G_USUBO: 734a059b299SVyacheslav Levytskyy return selectOverflowArith(ResVReg, ResType, I, 735a059b299SVyacheslav Levytskyy ResType->getOpcode() == SPIRV::OpTypeVector 736a059b299SVyacheslav Levytskyy ? SPIRV::OpISubBorrowV 737a059b299SVyacheslav Levytskyy : SPIRV::OpISubBorrowS); 738a059b299SVyacheslav Levytskyy case TargetOpcode::G_UMULO: 739a059b299SVyacheslav Levytskyy return selectOverflowArith(ResVReg, ResType, I, SPIRV::OpUMulExtended); 740a059b299SVyacheslav Levytskyy case TargetOpcode::G_SMULO: 741a059b299SVyacheslav Levytskyy return selectOverflowArith(ResVReg, ResType, I, SPIRV::OpSMulExtended); 742a059b299SVyacheslav Levytskyy 743eab7d363SIlia Diachkov case TargetOpcode::G_SEXT: 744eab7d363SIlia Diachkov return selectExt(ResVReg, ResType, I, true); 745eab7d363SIlia Diachkov case TargetOpcode::G_ANYEXT: 746eab7d363SIlia Diachkov case TargetOpcode::G_ZEXT: 747eab7d363SIlia Diachkov return selectExt(ResVReg, ResType, I, false); 748eab7d363SIlia Diachkov case TargetOpcode::G_TRUNC: 749eab7d363SIlia Diachkov return selectTrunc(ResVReg, ResType, I); 750eab7d363SIlia Diachkov case TargetOpcode::G_FPTRUNC: 751eab7d363SIlia Diachkov case TargetOpcode::G_FPEXT: 752eab7d363SIlia Diachkov return selectUnOp(ResVReg, ResType, I, SPIRV::OpFConvert); 753eab7d363SIlia Diachkov 754eab7d363SIlia Diachkov case TargetOpcode::G_PTRTOINT: 755eab7d363SIlia Diachkov return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertPtrToU); 756eab7d363SIlia Diachkov case TargetOpcode::G_INTTOPTR: 757eab7d363SIlia Diachkov return selectUnOp(ResVReg, ResType, I, SPIRV::OpConvertUToPtr); 758eab7d363SIlia Diachkov case TargetOpcode::G_BITCAST: 759ecc3bdaaSVyacheslav Levytskyy return selectBitcast(ResVReg, ResType, I); 760eab7d363SIlia Diachkov case TargetOpcode::G_ADDRSPACE_CAST: 761eab7d363SIlia Diachkov return selectAddrSpaceCast(ResVReg, ResType, I); 762b8e1544bSIlia Diachkov case TargetOpcode::G_PTR_ADD: { 763ed22029eSVyacheslav Levytskyy // Currently, we get G_PTR_ADD only applied to global variables. 764b8e1544bSIlia Diachkov assert(I.getOperand(1).isReg() && I.getOperand(2).isReg()); 765b8e1544bSIlia Diachkov Register GV = I.getOperand(1).getReg(); 766b8e1544bSIlia Diachkov MachineRegisterInfo::def_instr_iterator II = MRI->def_instr_begin(GV); 7671d250d90SVyacheslav Levytskyy (void)II; 768b8e1544bSIlia Diachkov assert(((*II).getOpcode() == TargetOpcode::G_GLOBAL_VALUE || 769b8e1544bSIlia Diachkov (*II).getOpcode() == TargetOpcode::COPY || 770b8e1544bSIlia Diachkov (*II).getOpcode() == SPIRV::OpVariable) && 771b8e1544bSIlia Diachkov isImm(I.getOperand(2), MRI)); 772ed22029eSVyacheslav Levytskyy // It may be the initialization of a global variable. 773ed22029eSVyacheslav Levytskyy bool IsGVInit = false; 774ed22029eSVyacheslav Levytskyy for (MachineRegisterInfo::use_instr_iterator 775ed22029eSVyacheslav Levytskyy UseIt = MRI->use_instr_begin(I.getOperand(0).getReg()), 776ed22029eSVyacheslav Levytskyy UseEnd = MRI->use_instr_end(); 777ed22029eSVyacheslav Levytskyy UseIt != UseEnd; UseIt = std::next(UseIt)) { 778ed22029eSVyacheslav Levytskyy if ((*UseIt).getOpcode() == TargetOpcode::G_GLOBAL_VALUE || 779ed22029eSVyacheslav Levytskyy (*UseIt).getOpcode() == SPIRV::OpVariable) { 780ed22029eSVyacheslav Levytskyy IsGVInit = true; 781ed22029eSVyacheslav Levytskyy break; 782ed22029eSVyacheslav Levytskyy } 783ed22029eSVyacheslav Levytskyy } 784b8e1544bSIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 785ed22029eSVyacheslav Levytskyy if (!IsGVInit) { 786ed22029eSVyacheslav Levytskyy SPIRVType *GVType = GR.getSPIRVTypeForVReg(GV); 787ed22029eSVyacheslav Levytskyy SPIRVType *GVPointeeType = GR.getPointeeType(GVType); 788ed22029eSVyacheslav Levytskyy SPIRVType *ResPointeeType = GR.getPointeeType(ResType); 789ed22029eSVyacheslav Levytskyy if (GVPointeeType && ResPointeeType && GVPointeeType != ResPointeeType) { 790ed22029eSVyacheslav Levytskyy // Build a new virtual register that is associated with the required 791ed22029eSVyacheslav Levytskyy // data type. 792ed22029eSVyacheslav Levytskyy Register NewVReg = MRI->createGenericVirtualRegister(MRI->getType(GV)); 793ed22029eSVyacheslav Levytskyy MRI->setRegClass(NewVReg, MRI->getRegClass(GV)); 794ed22029eSVyacheslav Levytskyy // Having a correctly typed base we are ready to build the actually 795ed22029eSVyacheslav Levytskyy // required GEP. It may not be a constant though, because all Operands 796ed22029eSVyacheslav Levytskyy // of OpSpecConstantOp is to originate from other const instructions, 797ed22029eSVyacheslav Levytskyy // and only the AccessChain named opcodes accept a global OpVariable 798ed22029eSVyacheslav Levytskyy // instruction. We can't use an AccessChain opcode because of the type 799ed22029eSVyacheslav Levytskyy // mismatch between result and base types. 800ed22029eSVyacheslav Levytskyy if (!GR.isBitcastCompatible(ResType, GVType)) 801ed22029eSVyacheslav Levytskyy report_fatal_error( 802ed22029eSVyacheslav Levytskyy "incompatible result and operand types in a bitcast"); 803ed22029eSVyacheslav Levytskyy Register ResTypeReg = GR.getSPIRVTypeID(ResType); 804ed22029eSVyacheslav Levytskyy MachineInstrBuilder MIB = 805ed22029eSVyacheslav Levytskyy BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitcast)) 806ed22029eSVyacheslav Levytskyy .addDef(NewVReg) 807ed22029eSVyacheslav Levytskyy .addUse(ResTypeReg) 808ed22029eSVyacheslav Levytskyy .addUse(GV); 809ed22029eSVyacheslav Levytskyy return MIB.constrainAllUses(TII, TRI, RBI) && 810ed22029eSVyacheslav Levytskyy BuildMI(BB, I, I.getDebugLoc(), 811ed22029eSVyacheslav Levytskyy TII.get(STI.isVulkanEnv() 812ed22029eSVyacheslav Levytskyy ? SPIRV::OpInBoundsAccessChain 813ed22029eSVyacheslav Levytskyy : SPIRV::OpInBoundsPtrAccessChain)) 814ed22029eSVyacheslav Levytskyy .addDef(ResVReg) 815ed22029eSVyacheslav Levytskyy .addUse(ResTypeReg) 816ed22029eSVyacheslav Levytskyy .addUse(NewVReg) 817ed22029eSVyacheslav Levytskyy .addUse(I.getOperand(2).getReg()) 818ed22029eSVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 819ed22029eSVyacheslav Levytskyy } else { 820ed22029eSVyacheslav Levytskyy return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp)) 821ed22029eSVyacheslav Levytskyy .addDef(ResVReg) 822ed22029eSVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(ResType)) 823ed22029eSVyacheslav Levytskyy .addImm( 824ed22029eSVyacheslav Levytskyy static_cast<uint32_t>(SPIRV::Opcode::InBoundsPtrAccessChain)) 825ed22029eSVyacheslav Levytskyy .addUse(GV) 826ed22029eSVyacheslav Levytskyy .addUse(I.getOperand(2).getReg()) 827ed22029eSVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 828ed22029eSVyacheslav Levytskyy } 829ed22029eSVyacheslav Levytskyy } 830ed22029eSVyacheslav Levytskyy // It's possible to translate G_PTR_ADD to OpSpecConstantOp: either to 831ed22029eSVyacheslav Levytskyy // initialize a global variable with a constant expression (e.g., the test 832ed22029eSVyacheslav Levytskyy // case opencl/basic/progvar_prog_scope_init.ll), or for another use case 833ed22029eSVyacheslav Levytskyy Register Idx = buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I); 834b8e1544bSIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp)) 835b8e1544bSIlia Diachkov .addDef(ResVReg) 836b8e1544bSIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 837b8e1544bSIlia Diachkov .addImm(static_cast<uint32_t>( 838b8e1544bSIlia Diachkov SPIRV::Opcode::InBoundsPtrAccessChain)) 839b8e1544bSIlia Diachkov .addUse(GV) 840b8e1544bSIlia Diachkov .addUse(Idx) 841b8e1544bSIlia Diachkov .addUse(I.getOperand(2).getReg()); 842b8e1544bSIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 843b8e1544bSIlia Diachkov } 844eab7d363SIlia Diachkov 845eab7d363SIlia Diachkov case TargetOpcode::G_ATOMICRMW_OR: 846eab7d363SIlia Diachkov return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicOr); 847eab7d363SIlia Diachkov case TargetOpcode::G_ATOMICRMW_ADD: 848eab7d363SIlia Diachkov return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicIAdd); 849eab7d363SIlia Diachkov case TargetOpcode::G_ATOMICRMW_AND: 850eab7d363SIlia Diachkov return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicAnd); 851eab7d363SIlia Diachkov case TargetOpcode::G_ATOMICRMW_MAX: 852eab7d363SIlia Diachkov return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMax); 853eab7d363SIlia Diachkov case TargetOpcode::G_ATOMICRMW_MIN: 854eab7d363SIlia Diachkov return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicSMin); 855eab7d363SIlia Diachkov case TargetOpcode::G_ATOMICRMW_SUB: 856eab7d363SIlia Diachkov return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicISub); 857eab7d363SIlia Diachkov case TargetOpcode::G_ATOMICRMW_XOR: 858eab7d363SIlia Diachkov return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicXor); 859eab7d363SIlia Diachkov case TargetOpcode::G_ATOMICRMW_UMAX: 860eab7d363SIlia Diachkov return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMax); 861eab7d363SIlia Diachkov case TargetOpcode::G_ATOMICRMW_UMIN: 862eab7d363SIlia Diachkov return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicUMin); 863eab7d363SIlia Diachkov case TargetOpcode::G_ATOMICRMW_XCHG: 864eab7d363SIlia Diachkov return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicExchange); 865eab7d363SIlia Diachkov case TargetOpcode::G_ATOMIC_CMPXCHG: 866eab7d363SIlia Diachkov return selectAtomicCmpXchg(ResVReg, ResType, I); 867eab7d363SIlia Diachkov 868925768eeSVyacheslav Levytskyy case TargetOpcode::G_ATOMICRMW_FADD: 869925768eeSVyacheslav Levytskyy return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFAddEXT); 870925768eeSVyacheslav Levytskyy case TargetOpcode::G_ATOMICRMW_FSUB: 871925768eeSVyacheslav Levytskyy // Translate G_ATOMICRMW_FSUB to OpAtomicFAddEXT with negative value operand 872925768eeSVyacheslav Levytskyy return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFAddEXT, 873925768eeSVyacheslav Levytskyy SPIRV::OpFNegate); 874925768eeSVyacheslav Levytskyy case TargetOpcode::G_ATOMICRMW_FMIN: 875925768eeSVyacheslav Levytskyy return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFMinEXT); 876925768eeSVyacheslav Levytskyy case TargetOpcode::G_ATOMICRMW_FMAX: 877925768eeSVyacheslav Levytskyy return selectAtomicRMW(ResVReg, ResType, I, SPIRV::OpAtomicFMaxEXT); 878925768eeSVyacheslav Levytskyy 879eab7d363SIlia Diachkov case TargetOpcode::G_FENCE: 880eab7d363SIlia Diachkov return selectFence(I); 881eab7d363SIlia Diachkov 882ada70f50SVyacheslav Levytskyy case TargetOpcode::G_STACKSAVE: 883ada70f50SVyacheslav Levytskyy return selectStackSave(ResVReg, ResType, I); 884ada70f50SVyacheslav Levytskyy case TargetOpcode::G_STACKRESTORE: 885ada70f50SVyacheslav Levytskyy return selectStackRestore(I); 886ada70f50SVyacheslav Levytskyy 887540d2551SVyacheslav Levytskyy case TargetOpcode::G_UNMERGE_VALUES: 888540d2551SVyacheslav Levytskyy return selectUnmergeValues(I); 889540d2551SVyacheslav Levytskyy 890c538d5c8SVyacheslav Levytskyy // Discard gen opcodes for intrinsics which we do not expect to actually 891c538d5c8SVyacheslav Levytskyy // represent code after lowering or intrinsics which are not implemented but 892c538d5c8SVyacheslav Levytskyy // should not crash when found in a customer's LLVM IR input. 893c538d5c8SVyacheslav Levytskyy case TargetOpcode::G_TRAP: 894c538d5c8SVyacheslav Levytskyy case TargetOpcode::G_DEBUGTRAP: 895c538d5c8SVyacheslav Levytskyy case TargetOpcode::G_UBSANTRAP: 896c538d5c8SVyacheslav Levytskyy case TargetOpcode::DBG_LABEL: 897c538d5c8SVyacheslav Levytskyy return true; 898c538d5c8SVyacheslav Levytskyy 899eab7d363SIlia Diachkov default: 900eab7d363SIlia Diachkov return false; 901eab7d363SIlia Diachkov } 902eab7d363SIlia Diachkov } 903eab7d363SIlia Diachkov 904698c8001SIlia Diachkov bool SPIRVInstructionSelector::selectExtInst(Register ResVReg, 905698c8001SIlia Diachkov const SPIRVType *ResType, 906698c8001SIlia Diachkov MachineInstr &I, 907fb90733eSSarah Spall GL::GLSLExtInst GLInst) const { 908fb90733eSSarah Spall return selectExtInst(ResVReg, ResType, I, 909fb90733eSSarah Spall {{SPIRV::InstructionSet::GLSL_std_450, GLInst}}); 910fb90733eSSarah Spall } 911fb90733eSSarah Spall 912fb90733eSSarah Spall bool SPIRVInstructionSelector::selectExtInst(Register ResVReg, 913fb90733eSSarah Spall const SPIRVType *ResType, 914fb90733eSSarah Spall MachineInstr &I, 915698c8001SIlia Diachkov CL::OpenCLExtInst CLInst) const { 916698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, 917698c8001SIlia Diachkov {{SPIRV::InstructionSet::OpenCL_std, CLInst}}); 918698c8001SIlia Diachkov } 919698c8001SIlia Diachkov 920698c8001SIlia Diachkov bool SPIRVInstructionSelector::selectExtInst(Register ResVReg, 921698c8001SIlia Diachkov const SPIRVType *ResType, 922698c8001SIlia Diachkov MachineInstr &I, 923698c8001SIlia Diachkov CL::OpenCLExtInst CLInst, 924698c8001SIlia Diachkov GL::GLSLExtInst GLInst) const { 925698c8001SIlia Diachkov ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst}, 926698c8001SIlia Diachkov {SPIRV::InstructionSet::GLSL_std_450, GLInst}}; 927698c8001SIlia Diachkov return selectExtInst(ResVReg, ResType, I, ExtInsts); 928698c8001SIlia Diachkov } 929698c8001SIlia Diachkov 930698c8001SIlia Diachkov bool SPIRVInstructionSelector::selectExtInst(Register ResVReg, 931698c8001SIlia Diachkov const SPIRVType *ResType, 932698c8001SIlia Diachkov MachineInstr &I, 933698c8001SIlia Diachkov const ExtInstList &Insts) const { 934698c8001SIlia Diachkov 935698c8001SIlia Diachkov for (const auto &Ex : Insts) { 936698c8001SIlia Diachkov SPIRV::InstructionSet::InstructionSet Set = Ex.first; 937698c8001SIlia Diachkov uint32_t Opcode = Ex.second; 938698c8001SIlia Diachkov if (STI.canUseExtInstSet(Set)) { 939698c8001SIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 940698c8001SIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) 941698c8001SIlia Diachkov .addDef(ResVReg) 942698c8001SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 943698c8001SIlia Diachkov .addImm(static_cast<uint32_t>(Set)) 944698c8001SIlia Diachkov .addImm(Opcode); 945698c8001SIlia Diachkov const unsigned NumOps = I.getNumOperands(); 946add6b2f3SFarzon Lotfi unsigned Index = 1; 947add6b2f3SFarzon Lotfi if (Index < NumOps && 948add6b2f3SFarzon Lotfi I.getOperand(Index).getType() == 949add6b2f3SFarzon Lotfi MachineOperand::MachineOperandType::MO_IntrinsicID) 950add6b2f3SFarzon Lotfi Index = 2; 951add6b2f3SFarzon Lotfi for (; Index < NumOps; ++Index) 952add6b2f3SFarzon Lotfi MIB.add(I.getOperand(Index)); 953698c8001SIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 954698c8001SIlia Diachkov } 955698c8001SIlia Diachkov } 956698c8001SIlia Diachkov return false; 957698c8001SIlia Diachkov } 958698c8001SIlia Diachkov 9595889f684SAshley Coleman bool SPIRVInstructionSelector::selectOpWithSrcs(Register ResVReg, 960fb90733eSSarah Spall const SPIRVType *ResType, 961fb90733eSSarah Spall MachineInstr &I, 962fb90733eSSarah Spall std::vector<Register> Srcs, 963fb90733eSSarah Spall unsigned Opcode) const { 964fb90733eSSarah Spall auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode)) 965fb90733eSSarah Spall .addDef(ResVReg) 966fb90733eSSarah Spall .addUse(GR.getSPIRVTypeID(ResType)); 967fb90733eSSarah Spall for (Register SReg : Srcs) { 968fb90733eSSarah Spall MIB.addUse(SReg); 969fb90733eSSarah Spall } 970fb90733eSSarah Spall return MIB.constrainAllUses(TII, TRI, RBI); 971fb90733eSSarah Spall } 972fb90733eSSarah Spall 973eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectUnOp(Register ResVReg, 974eab7d363SIlia Diachkov const SPIRVType *ResType, 975eab7d363SIlia Diachkov MachineInstr &I, 976eab7d363SIlia Diachkov unsigned Opcode) const { 977486ea1ecSVyacheslav Levytskyy if (STI.isOpenCLEnv() && I.getOperand(1).isReg()) { 978486ea1ecSVyacheslav Levytskyy Register SrcReg = I.getOperand(1).getReg(); 979486ea1ecSVyacheslav Levytskyy bool IsGV = false; 980486ea1ecSVyacheslav Levytskyy for (MachineRegisterInfo::def_instr_iterator DefIt = 981486ea1ecSVyacheslav Levytskyy MRI->def_instr_begin(SrcReg); 982486ea1ecSVyacheslav Levytskyy DefIt != MRI->def_instr_end(); DefIt = std::next(DefIt)) { 983486ea1ecSVyacheslav Levytskyy if ((*DefIt).getOpcode() == TargetOpcode::G_GLOBAL_VALUE) { 984486ea1ecSVyacheslav Levytskyy IsGV = true; 985486ea1ecSVyacheslav Levytskyy break; 986486ea1ecSVyacheslav Levytskyy } 987486ea1ecSVyacheslav Levytskyy } 988486ea1ecSVyacheslav Levytskyy if (IsGV) { 989486ea1ecSVyacheslav Levytskyy uint32_t SpecOpcode = 0; 990486ea1ecSVyacheslav Levytskyy switch (Opcode) { 991486ea1ecSVyacheslav Levytskyy case SPIRV::OpConvertPtrToU: 992486ea1ecSVyacheslav Levytskyy SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertPtrToU); 993486ea1ecSVyacheslav Levytskyy break; 994486ea1ecSVyacheslav Levytskyy case SPIRV::OpConvertUToPtr: 995486ea1ecSVyacheslav Levytskyy SpecOpcode = static_cast<uint32_t>(SPIRV::Opcode::ConvertUToPtr); 996486ea1ecSVyacheslav Levytskyy break; 997486ea1ecSVyacheslav Levytskyy } 998486ea1ecSVyacheslav Levytskyy if (SpecOpcode) 999486ea1ecSVyacheslav Levytskyy return BuildMI(*I.getParent(), I, I.getDebugLoc(), 1000486ea1ecSVyacheslav Levytskyy TII.get(SPIRV::OpSpecConstantOp)) 1001486ea1ecSVyacheslav Levytskyy .addDef(ResVReg) 1002486ea1ecSVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(ResType)) 1003486ea1ecSVyacheslav Levytskyy .addImm(SpecOpcode) 1004486ea1ecSVyacheslav Levytskyy .addUse(SrcReg) 1005486ea1ecSVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 1006486ea1ecSVyacheslav Levytskyy } 1007486ea1ecSVyacheslav Levytskyy } 10085889f684SAshley Coleman return selectOpWithSrcs(ResVReg, ResType, I, {I.getOperand(1).getReg()}, 1009eab7d363SIlia Diachkov Opcode); 1010eab7d363SIlia Diachkov } 1011eab7d363SIlia Diachkov 1012ecc3bdaaSVyacheslav Levytskyy bool SPIRVInstructionSelector::selectBitcast(Register ResVReg, 1013ecc3bdaaSVyacheslav Levytskyy const SPIRVType *ResType, 1014ecc3bdaaSVyacheslav Levytskyy MachineInstr &I) const { 1015ecc3bdaaSVyacheslav Levytskyy Register OpReg = I.getOperand(1).getReg(); 1016ecc3bdaaSVyacheslav Levytskyy SPIRVType *OpType = OpReg.isValid() ? GR.getSPIRVTypeForVReg(OpReg) : nullptr; 1017ecc3bdaaSVyacheslav Levytskyy if (!GR.isBitcastCompatible(ResType, OpType)) 1018ecc3bdaaSVyacheslav Levytskyy report_fatal_error("incompatible result and operand types in a bitcast"); 1019ecc3bdaaSVyacheslav Levytskyy return selectUnOp(ResVReg, ResType, I, SPIRV::OpBitcast); 1020ecc3bdaaSVyacheslav Levytskyy } 1021ecc3bdaaSVyacheslav Levytskyy 1022eab7d363SIlia Diachkov static void addMemoryOperands(MachineMemOperand *MemOp, 1023eab7d363SIlia Diachkov MachineInstrBuilder &MIB) { 1024eab7d363SIlia Diachkov uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None); 1025eab7d363SIlia Diachkov if (MemOp->isVolatile()) 1026eab7d363SIlia Diachkov SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile); 1027eab7d363SIlia Diachkov if (MemOp->isNonTemporal()) 1028eab7d363SIlia Diachkov SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal); 1029eab7d363SIlia Diachkov if (MemOp->getAlign().value()) 1030eab7d363SIlia Diachkov SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned); 1031eab7d363SIlia Diachkov 1032eab7d363SIlia Diachkov if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) { 1033eab7d363SIlia Diachkov MIB.addImm(SpvMemOp); 1034eab7d363SIlia Diachkov if (SpvMemOp & static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned)) 1035eab7d363SIlia Diachkov MIB.addImm(MemOp->getAlign().value()); 1036eab7d363SIlia Diachkov } 1037eab7d363SIlia Diachkov } 1038eab7d363SIlia Diachkov 1039eab7d363SIlia Diachkov static void addMemoryOperands(uint64_t Flags, MachineInstrBuilder &MIB) { 1040eab7d363SIlia Diachkov uint32_t SpvMemOp = static_cast<uint32_t>(SPIRV::MemoryOperand::None); 1041eab7d363SIlia Diachkov if (Flags & MachineMemOperand::Flags::MOVolatile) 1042eab7d363SIlia Diachkov SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile); 1043eab7d363SIlia Diachkov if (Flags & MachineMemOperand::Flags::MONonTemporal) 1044eab7d363SIlia Diachkov SpvMemOp |= static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal); 1045eab7d363SIlia Diachkov 1046eab7d363SIlia Diachkov if (SpvMemOp != static_cast<uint32_t>(SPIRV::MemoryOperand::None)) 1047eab7d363SIlia Diachkov MIB.addImm(SpvMemOp); 1048eab7d363SIlia Diachkov } 1049eab7d363SIlia Diachkov 1050eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectLoad(Register ResVReg, 1051eab7d363SIlia Diachkov const SPIRVType *ResType, 1052eab7d363SIlia Diachkov MachineInstr &I) const { 1053d9847cdeSSameer Sahasrabuddhe unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0; 1054eab7d363SIlia Diachkov Register Ptr = I.getOperand(1 + OpOffset).getReg(); 10554b692a95SSteven Perron 10564b692a95SSteven Perron auto *PtrDef = getVRegDef(*MRI, Ptr); 10574b692a95SSteven Perron auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef); 10584b692a95SSteven Perron if (IntPtrDef && 10594b692a95SSteven Perron IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer) { 10604b692a95SSteven Perron Register ImageReg = IntPtrDef->getOperand(2).getReg(); 10614b692a95SSteven Perron Register NewImageReg = 10624b692a95SSteven Perron MRI->createVirtualRegister(MRI->getRegClass(ImageReg)); 10634b692a95SSteven Perron auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg)); 10644b692a95SSteven Perron if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg), 10654b692a95SSteven Perron *ImageDef, I)) { 10664b692a95SSteven Perron return false; 10674b692a95SSteven Perron } 10684b692a95SSteven Perron 10694b692a95SSteven Perron Register IdxReg = IntPtrDef->getOperand(3).getReg(); 10704b692a95SSteven Perron return generateImageRead(ResVReg, ResType, NewImageReg, IdxReg, 10714b692a95SSteven Perron I.getDebugLoc(), I); 10724b692a95SSteven Perron } 10734b692a95SSteven Perron 1074eab7d363SIlia Diachkov auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad)) 1075eab7d363SIlia Diachkov .addDef(ResVReg) 1076eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 1077eab7d363SIlia Diachkov .addUse(Ptr); 1078eab7d363SIlia Diachkov if (!I.getNumMemOperands()) { 1079d9847cdeSSameer Sahasrabuddhe assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS || 1080d9847cdeSSameer Sahasrabuddhe I.getOpcode() == 1081d9847cdeSSameer Sahasrabuddhe TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS); 1082eab7d363SIlia Diachkov addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB); 1083eab7d363SIlia Diachkov } else { 1084eab7d363SIlia Diachkov addMemoryOperands(*I.memoperands_begin(), MIB); 1085eab7d363SIlia Diachkov } 1086eab7d363SIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 1087eab7d363SIlia Diachkov } 1088eab7d363SIlia Diachkov 1089eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const { 1090d9847cdeSSameer Sahasrabuddhe unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0; 1091eab7d363SIlia Diachkov Register StoreVal = I.getOperand(0 + OpOffset).getReg(); 1092eab7d363SIlia Diachkov Register Ptr = I.getOperand(1 + OpOffset).getReg(); 10934b692a95SSteven Perron 10944b692a95SSteven Perron auto *PtrDef = getVRegDef(*MRI, Ptr); 10954b692a95SSteven Perron auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef); 10964b692a95SSteven Perron if (IntPtrDef && 10974b692a95SSteven Perron IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer) { 10984b692a95SSteven Perron Register ImageReg = IntPtrDef->getOperand(2).getReg(); 10994b692a95SSteven Perron Register NewImageReg = 11004b692a95SSteven Perron MRI->createVirtualRegister(MRI->getRegClass(ImageReg)); 11014b692a95SSteven Perron auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg)); 11024b692a95SSteven Perron if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg), 11034b692a95SSteven Perron *ImageDef, I)) { 11044b692a95SSteven Perron return false; 11054b692a95SSteven Perron } 11064b692a95SSteven Perron 11074b692a95SSteven Perron Register IdxReg = IntPtrDef->getOperand(3).getReg(); 11084b692a95SSteven Perron return BuildMI(*I.getParent(), I, I.getDebugLoc(), 11094b692a95SSteven Perron TII.get(SPIRV::OpImageWrite)) 11104b692a95SSteven Perron .addUse(NewImageReg) 11114b692a95SSteven Perron .addUse(IdxReg) 11124b692a95SSteven Perron .addUse(StoreVal) 11134b692a95SSteven Perron .constrainAllUses(TII, TRI, RBI); 11144b692a95SSteven Perron } 11154b692a95SSteven Perron 1116eab7d363SIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 1117eab7d363SIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpStore)) 1118eab7d363SIlia Diachkov .addUse(Ptr) 1119eab7d363SIlia Diachkov .addUse(StoreVal); 1120eab7d363SIlia Diachkov if (!I.getNumMemOperands()) { 1121d9847cdeSSameer Sahasrabuddhe assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS || 1122d9847cdeSSameer Sahasrabuddhe I.getOpcode() == 1123d9847cdeSSameer Sahasrabuddhe TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS); 1124eab7d363SIlia Diachkov addMemoryOperands(I.getOperand(2 + OpOffset).getImm(), MIB); 1125eab7d363SIlia Diachkov } else { 1126eab7d363SIlia Diachkov addMemoryOperands(*I.memoperands_begin(), MIB); 1127eab7d363SIlia Diachkov } 1128eab7d363SIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 1129eab7d363SIlia Diachkov } 1130eab7d363SIlia Diachkov 1131ada70f50SVyacheslav Levytskyy bool SPIRVInstructionSelector::selectStackSave(Register ResVReg, 1132ada70f50SVyacheslav Levytskyy const SPIRVType *ResType, 1133ada70f50SVyacheslav Levytskyy MachineInstr &I) const { 1134ada70f50SVyacheslav Levytskyy if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) 1135ada70f50SVyacheslav Levytskyy report_fatal_error( 1136ada70f50SVyacheslav Levytskyy "llvm.stacksave intrinsic: this instruction requires the following " 1137ada70f50SVyacheslav Levytskyy "SPIR-V extension: SPV_INTEL_variable_length_array", 1138ada70f50SVyacheslav Levytskyy false); 1139ada70f50SVyacheslav Levytskyy MachineBasicBlock &BB = *I.getParent(); 1140ada70f50SVyacheslav Levytskyy return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSaveMemoryINTEL)) 1141ada70f50SVyacheslav Levytskyy .addDef(ResVReg) 1142ada70f50SVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(ResType)) 1143ada70f50SVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 1144ada70f50SVyacheslav Levytskyy } 1145ada70f50SVyacheslav Levytskyy 1146ada70f50SVyacheslav Levytskyy bool SPIRVInstructionSelector::selectStackRestore(MachineInstr &I) const { 1147ada70f50SVyacheslav Levytskyy if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) 1148ada70f50SVyacheslav Levytskyy report_fatal_error( 1149ada70f50SVyacheslav Levytskyy "llvm.stackrestore intrinsic: this instruction requires the following " 1150ada70f50SVyacheslav Levytskyy "SPIR-V extension: SPV_INTEL_variable_length_array", 1151ada70f50SVyacheslav Levytskyy false); 1152ada70f50SVyacheslav Levytskyy if (!I.getOperand(0).isReg()) 1153ada70f50SVyacheslav Levytskyy return false; 1154ada70f50SVyacheslav Levytskyy MachineBasicBlock &BB = *I.getParent(); 1155ada70f50SVyacheslav Levytskyy return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpRestoreMemoryINTEL)) 1156ada70f50SVyacheslav Levytskyy .addUse(I.getOperand(0).getReg()) 1157ada70f50SVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 1158ada70f50SVyacheslav Levytskyy } 1159ada70f50SVyacheslav Levytskyy 1160eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectMemOperation(Register ResVReg, 1161eab7d363SIlia Diachkov MachineInstr &I) const { 1162eab7d363SIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 1163698c8001SIlia Diachkov Register SrcReg = I.getOperand(1).getReg(); 1164a93cbd4eSFinn Plummer bool Result = true; 1165698c8001SIlia Diachkov if (I.getOpcode() == TargetOpcode::G_MEMSET) { 1166698c8001SIlia Diachkov assert(I.getOperand(1).isReg() && I.getOperand(2).isReg()); 1167698c8001SIlia Diachkov unsigned Val = getIConstVal(I.getOperand(1).getReg(), MRI); 1168698c8001SIlia Diachkov unsigned Num = getIConstVal(I.getOperand(2).getReg(), MRI); 1169698c8001SIlia Diachkov SPIRVType *ValTy = GR.getOrCreateSPIRVIntegerType(8, I, TII); 1170698c8001SIlia Diachkov SPIRVType *ArrTy = GR.getOrCreateSPIRVArrayType(ValTy, Num, I, TII); 1171f6aa5087SVyacheslav Levytskyy Register Const = GR.getOrCreateConstIntArray(Val, Num, I, ArrTy, TII); 1172698c8001SIlia Diachkov SPIRVType *VarTy = GR.getOrCreateSPIRVPointerType( 1173698c8001SIlia Diachkov ArrTy, I, TII, SPIRV::StorageClass::UniformConstant); 1174698c8001SIlia Diachkov // TODO: check if we have such GV, add init, use buildGlobalVariable. 11751d250d90SVyacheslav Levytskyy Function &CurFunction = GR.CurMF->getFunction(); 11761d250d90SVyacheslav Levytskyy Type *LLVMArrTy = 11771d250d90SVyacheslav Levytskyy ArrayType::get(IntegerType::get(CurFunction.getContext(), 8), Num); 11781d250d90SVyacheslav Levytskyy // Module takes ownership of the global var. 11791d250d90SVyacheslav Levytskyy GlobalVariable *GV = new GlobalVariable(*CurFunction.getParent(), LLVMArrTy, 11801d250d90SVyacheslav Levytskyy true, GlobalValue::InternalLinkage, 11811d250d90SVyacheslav Levytskyy Constant::getNullValue(LLVMArrTy)); 118267d3ef74SVyacheslav Levytskyy Register VarReg = MRI->createGenericVirtualRegister(LLT::scalar(64)); 1183698c8001SIlia Diachkov GR.add(GV, GR.CurMF, VarReg); 118483c1d003SVyacheslav Levytskyy GR.addGlobalObject(GV, GR.CurMF, VarReg); 1185698c8001SIlia Diachkov 1186a93cbd4eSFinn Plummer Result &= 1187698c8001SIlia Diachkov BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpVariable)) 1188698c8001SIlia Diachkov .addDef(VarReg) 1189698c8001SIlia Diachkov .addUse(GR.getSPIRVTypeID(VarTy)) 1190698c8001SIlia Diachkov .addImm(SPIRV::StorageClass::UniformConstant) 1191698c8001SIlia Diachkov .addUse(Const) 1192698c8001SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 1193e41df5cbSNathan Gauër buildOpDecorate(VarReg, I, TII, SPIRV::Decoration::Constant, {}); 1194698c8001SIlia Diachkov SPIRVType *SourceTy = GR.getOrCreateSPIRVPointerType( 1195698c8001SIlia Diachkov ValTy, I, TII, SPIRV::StorageClass::UniformConstant); 119667d3ef74SVyacheslav Levytskyy SrcReg = MRI->createGenericVirtualRegister(LLT::scalar(64)); 11975889f684SAshley Coleman selectOpWithSrcs(SrcReg, SourceTy, I, {VarReg}, SPIRV::OpBitcast); 1198698c8001SIlia Diachkov } 1199eab7d363SIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCopyMemorySized)) 1200b8e1544bSIlia Diachkov .addUse(I.getOperand(0).getReg()) 1201698c8001SIlia Diachkov .addUse(SrcReg) 1202eab7d363SIlia Diachkov .addUse(I.getOperand(2).getReg()); 1203eab7d363SIlia Diachkov if (I.getNumMemOperands()) 1204eab7d363SIlia Diachkov addMemoryOperands(*I.memoperands_begin(), MIB); 1205a93cbd4eSFinn Plummer Result &= MIB.constrainAllUses(TII, TRI, RBI); 1206b8e1544bSIlia Diachkov if (ResVReg.isValid() && ResVReg != MIB->getOperand(0).getReg()) 120742633cf2SVyacheslav Levytskyy Result &= BuildCOPY(ResVReg, MIB->getOperand(0).getReg(), I); 1208eab7d363SIlia Diachkov return Result; 1209eab7d363SIlia Diachkov } 1210eab7d363SIlia Diachkov 1211eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg, 1212eab7d363SIlia Diachkov const SPIRVType *ResType, 1213eab7d363SIlia Diachkov MachineInstr &I, 1214925768eeSVyacheslav Levytskyy unsigned NewOpcode, 1215925768eeSVyacheslav Levytskyy unsigned NegateOpcode) const { 1216a93cbd4eSFinn Plummer bool Result = true; 1217eab7d363SIlia Diachkov assert(I.hasOneMemOperand()); 1218eab7d363SIlia Diachkov const MachineMemOperand *MemOp = *I.memoperands_begin(); 12193cfd0c0dSAlex Voicu uint32_t Scope = static_cast<uint32_t>(getMemScope( 12203cfd0c0dSAlex Voicu GR.CurMF->getFunction().getContext(), MemOp->getSyncScopeID())); 1221a93cbd4eSFinn Plummer auto ScopeConstant = buildI32Constant(Scope, I); 1222a93cbd4eSFinn Plummer Register ScopeReg = ScopeConstant.first; 1223a93cbd4eSFinn Plummer Result &= ScopeConstant.second; 1224eab7d363SIlia Diachkov 1225eab7d363SIlia Diachkov Register Ptr = I.getOperand(1).getReg(); 1226eab7d363SIlia Diachkov // TODO: Changed as it's implemented in the translator. See test/atomicrmw.ll 1227eab7d363SIlia Diachkov // auto ScSem = 1228eab7d363SIlia Diachkov // getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr)); 1229eab7d363SIlia Diachkov AtomicOrdering AO = MemOp->getSuccessOrdering(); 1230eab7d363SIlia Diachkov uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO)); 1231a93cbd4eSFinn Plummer auto MemSemConstant = buildI32Constant(MemSem /*| ScSem*/, I); 1232a93cbd4eSFinn Plummer Register MemSemReg = MemSemConstant.first; 1233a93cbd4eSFinn Plummer Result &= MemSemConstant.second; 1234eab7d363SIlia Diachkov 1235925768eeSVyacheslav Levytskyy Register ValueReg = I.getOperand(2).getReg(); 1236925768eeSVyacheslav Levytskyy if (NegateOpcode != 0) { 1237925768eeSVyacheslav Levytskyy // Translation with negative value operand is requested 1238f9c98068SVyacheslav Levytskyy Register TmpReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 12395889f684SAshley Coleman Result &= selectOpWithSrcs(TmpReg, ResType, I, {ValueReg}, NegateOpcode); 1240925768eeSVyacheslav Levytskyy ValueReg = TmpReg; 1241925768eeSVyacheslav Levytskyy } 1242925768eeSVyacheslav Levytskyy 1243a93cbd4eSFinn Plummer return Result && 1244a93cbd4eSFinn Plummer BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode)) 1245eab7d363SIlia Diachkov .addDef(ResVReg) 1246eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 1247eab7d363SIlia Diachkov .addUse(Ptr) 1248eab7d363SIlia Diachkov .addUse(ScopeReg) 1249eab7d363SIlia Diachkov .addUse(MemSemReg) 1250925768eeSVyacheslav Levytskyy .addUse(ValueReg) 1251eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 1252eab7d363SIlia Diachkov } 1253eab7d363SIlia Diachkov 1254540d2551SVyacheslav Levytskyy bool SPIRVInstructionSelector::selectUnmergeValues(MachineInstr &I) const { 1255540d2551SVyacheslav Levytskyy unsigned ArgI = I.getNumOperands() - 1; 1256540d2551SVyacheslav Levytskyy Register SrcReg = 1257540d2551SVyacheslav Levytskyy I.getOperand(ArgI).isReg() ? I.getOperand(ArgI).getReg() : Register(0); 1258540d2551SVyacheslav Levytskyy SPIRVType *DefType = 1259540d2551SVyacheslav Levytskyy SrcReg.isValid() ? GR.getSPIRVTypeForVReg(SrcReg) : nullptr; 1260540d2551SVyacheslav Levytskyy if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector) 1261540d2551SVyacheslav Levytskyy report_fatal_error( 1262540d2551SVyacheslav Levytskyy "cannot select G_UNMERGE_VALUES with a non-vector argument"); 1263540d2551SVyacheslav Levytskyy 1264540d2551SVyacheslav Levytskyy SPIRVType *ScalarType = 1265540d2551SVyacheslav Levytskyy GR.getSPIRVTypeForVReg(DefType->getOperand(1).getReg()); 1266540d2551SVyacheslav Levytskyy MachineBasicBlock &BB = *I.getParent(); 1267540d2551SVyacheslav Levytskyy bool Res = false; 1268540d2551SVyacheslav Levytskyy for (unsigned i = 0; i < I.getNumDefs(); ++i) { 1269540d2551SVyacheslav Levytskyy Register ResVReg = I.getOperand(i).getReg(); 1270540d2551SVyacheslav Levytskyy SPIRVType *ResType = GR.getSPIRVTypeForVReg(ResVReg); 1271540d2551SVyacheslav Levytskyy if (!ResType) { 1272540d2551SVyacheslav Levytskyy // There was no "assign type" actions, let's fix this now 1273540d2551SVyacheslav Levytskyy ResType = ScalarType; 127467d3ef74SVyacheslav Levytskyy MRI->setRegClass(ResVReg, GR.getRegClass(ResType)); 1275540d2551SVyacheslav Levytskyy MRI->setType(ResVReg, LLT::scalar(GR.getScalarOrVectorBitWidth(ResType))); 1276540d2551SVyacheslav Levytskyy GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF); 1277540d2551SVyacheslav Levytskyy } 1278540d2551SVyacheslav Levytskyy auto MIB = 1279540d2551SVyacheslav Levytskyy BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract)) 1280540d2551SVyacheslav Levytskyy .addDef(ResVReg) 1281540d2551SVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(ResType)) 1282540d2551SVyacheslav Levytskyy .addUse(SrcReg) 1283540d2551SVyacheslav Levytskyy .addImm(static_cast<int64_t>(i)); 1284540d2551SVyacheslav Levytskyy Res |= MIB.constrainAllUses(TII, TRI, RBI); 1285540d2551SVyacheslav Levytskyy } 1286540d2551SVyacheslav Levytskyy return Res; 1287540d2551SVyacheslav Levytskyy } 1288540d2551SVyacheslav Levytskyy 1289eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectFence(MachineInstr &I) const { 1290eab7d363SIlia Diachkov AtomicOrdering AO = AtomicOrdering(I.getOperand(0).getImm()); 1291eab7d363SIlia Diachkov uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO)); 1292a93cbd4eSFinn Plummer auto MemSemConstant = buildI32Constant(MemSem, I); 1293a93cbd4eSFinn Plummer Register MemSemReg = MemSemConstant.first; 1294a93cbd4eSFinn Plummer bool Result = MemSemConstant.second; 1295eab7d363SIlia Diachkov SyncScope::ID Ord = SyncScope::ID(I.getOperand(1).getImm()); 12963cfd0c0dSAlex Voicu uint32_t Scope = static_cast<uint32_t>( 12973cfd0c0dSAlex Voicu getMemScope(GR.CurMF->getFunction().getContext(), Ord)); 1298a93cbd4eSFinn Plummer auto ScopeConstant = buildI32Constant(Scope, I); 1299a93cbd4eSFinn Plummer Register ScopeReg = ScopeConstant.first; 1300a93cbd4eSFinn Plummer Result &= ScopeConstant.second; 1301eab7d363SIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 1302a93cbd4eSFinn Plummer return Result && 1303a93cbd4eSFinn Plummer BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpMemoryBarrier)) 1304eab7d363SIlia Diachkov .addUse(ScopeReg) 1305eab7d363SIlia Diachkov .addUse(MemSemReg) 1306eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 1307eab7d363SIlia Diachkov } 1308eab7d363SIlia Diachkov 1309a059b299SVyacheslav Levytskyy bool SPIRVInstructionSelector::selectOverflowArith(Register ResVReg, 1310a059b299SVyacheslav Levytskyy const SPIRVType *ResType, 1311a059b299SVyacheslav Levytskyy MachineInstr &I, 1312a059b299SVyacheslav Levytskyy unsigned Opcode) const { 1313a059b299SVyacheslav Levytskyy Type *ResTy = nullptr; 1314a059b299SVyacheslav Levytskyy StringRef ResName; 1315a059b299SVyacheslav Levytskyy if (!GR.findValueAttrs(&I, ResTy, ResName)) 1316a059b299SVyacheslav Levytskyy report_fatal_error( 1317a059b299SVyacheslav Levytskyy "Not enough info to select the arithmetic with overflow instruction"); 1318a059b299SVyacheslav Levytskyy if (!ResTy || !ResTy->isStructTy()) 1319a059b299SVyacheslav Levytskyy report_fatal_error("Expect struct type result for the arithmetic " 1320a059b299SVyacheslav Levytskyy "with overflow instruction"); 1321a059b299SVyacheslav Levytskyy // "Result Type must be from OpTypeStruct. The struct must have two members, 1322a059b299SVyacheslav Levytskyy // and the two members must be the same type." 1323a059b299SVyacheslav Levytskyy Type *ResElemTy = cast<StructType>(ResTy)->getElementType(0); 13248ac46d6bSVyacheslav Levytskyy ResTy = StructType::get(ResElemTy, ResElemTy); 1325a059b299SVyacheslav Levytskyy // Build SPIR-V types and constant(s) if needed. 1326a059b299SVyacheslav Levytskyy MachineIRBuilder MIRBuilder(I); 1327a059b299SVyacheslav Levytskyy SPIRVType *StructType = GR.getOrCreateSPIRVType( 1328a059b299SVyacheslav Levytskyy ResTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false); 1329a059b299SVyacheslav Levytskyy assert(I.getNumDefs() > 1 && "Not enought operands"); 1330a059b299SVyacheslav Levytskyy SPIRVType *BoolType = GR.getOrCreateSPIRVBoolType(I, TII); 1331a059b299SVyacheslav Levytskyy unsigned N = GR.getScalarOrVectorComponentCount(ResType); 1332a059b299SVyacheslav Levytskyy if (N > 1) 1333a059b299SVyacheslav Levytskyy BoolType = GR.getOrCreateSPIRVVectorType(BoolType, N, I, TII); 1334a059b299SVyacheslav Levytskyy Register BoolTypeReg = GR.getSPIRVTypeID(BoolType); 1335a059b299SVyacheslav Levytskyy Register ZeroReg = buildZerosVal(ResType, I); 1336a059b299SVyacheslav Levytskyy // A new virtual register to store the result struct. 1337a059b299SVyacheslav Levytskyy Register StructVReg = MRI->createGenericVirtualRegister(LLT::scalar(64)); 1338a059b299SVyacheslav Levytskyy MRI->setRegClass(StructVReg, &SPIRV::IDRegClass); 1339a059b299SVyacheslav Levytskyy // Build the result name if needed. 1340a059b299SVyacheslav Levytskyy if (ResName.size() > 0) 1341a059b299SVyacheslav Levytskyy buildOpName(StructVReg, ResName, MIRBuilder); 1342a059b299SVyacheslav Levytskyy // Build the arithmetic with overflow instruction. 1343a059b299SVyacheslav Levytskyy MachineBasicBlock &BB = *I.getParent(); 1344a059b299SVyacheslav Levytskyy auto MIB = 1345a059b299SVyacheslav Levytskyy BuildMI(BB, MIRBuilder.getInsertPt(), I.getDebugLoc(), TII.get(Opcode)) 1346a059b299SVyacheslav Levytskyy .addDef(StructVReg) 1347a059b299SVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(StructType)); 1348a059b299SVyacheslav Levytskyy for (unsigned i = I.getNumDefs(); i < I.getNumOperands(); ++i) 1349a059b299SVyacheslav Levytskyy MIB.addUse(I.getOperand(i).getReg()); 1350a93cbd4eSFinn Plummer bool Result = MIB.constrainAllUses(TII, TRI, RBI); 1351a059b299SVyacheslav Levytskyy // Build instructions to extract fields of the instruction's result. 1352a059b299SVyacheslav Levytskyy // A new virtual register to store the higher part of the result struct. 1353a059b299SVyacheslav Levytskyy Register HigherVReg = MRI->createGenericVirtualRegister(LLT::scalar(64)); 1354a059b299SVyacheslav Levytskyy MRI->setRegClass(HigherVReg, &SPIRV::iIDRegClass); 1355a059b299SVyacheslav Levytskyy for (unsigned i = 0; i < I.getNumDefs(); ++i) { 1356a059b299SVyacheslav Levytskyy auto MIB = 1357a059b299SVyacheslav Levytskyy BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract)) 1358a059b299SVyacheslav Levytskyy .addDef(i == 1 ? HigherVReg : I.getOperand(i).getReg()) 1359a059b299SVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(ResType)) 1360a059b299SVyacheslav Levytskyy .addUse(StructVReg) 1361a059b299SVyacheslav Levytskyy .addImm(i); 1362a93cbd4eSFinn Plummer Result &= MIB.constrainAllUses(TII, TRI, RBI); 1363a059b299SVyacheslav Levytskyy } 1364a059b299SVyacheslav Levytskyy // Build boolean value from the higher part. 1365a93cbd4eSFinn Plummer return Result && BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual)) 1366a059b299SVyacheslav Levytskyy .addDef(I.getOperand(1).getReg()) 1367a059b299SVyacheslav Levytskyy .addUse(BoolTypeReg) 1368a059b299SVyacheslav Levytskyy .addUse(HigherVReg) 1369a059b299SVyacheslav Levytskyy .addUse(ZeroReg) 1370a059b299SVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 1371a059b299SVyacheslav Levytskyy } 1372a059b299SVyacheslav Levytskyy 1373eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg, 1374eab7d363SIlia Diachkov const SPIRVType *ResType, 1375eab7d363SIlia Diachkov MachineInstr &I) const { 1376a93cbd4eSFinn Plummer bool Result = true; 1377b8e1544bSIlia Diachkov Register ScopeReg; 1378b8e1544bSIlia Diachkov Register MemSemEqReg; 1379b8e1544bSIlia Diachkov Register MemSemNeqReg; 1380b8e1544bSIlia Diachkov Register Ptr = I.getOperand(2).getReg(); 1381d9847cdeSSameer Sahasrabuddhe if (!isa<GIntrinsic>(I)) { 1382eab7d363SIlia Diachkov assert(I.hasOneMemOperand()); 1383eab7d363SIlia Diachkov const MachineMemOperand *MemOp = *I.memoperands_begin(); 13843cfd0c0dSAlex Voicu unsigned Scope = static_cast<uint32_t>(getMemScope( 13853cfd0c0dSAlex Voicu GR.CurMF->getFunction().getContext(), MemOp->getSyncScopeID())); 1386a93cbd4eSFinn Plummer auto ScopeConstant = buildI32Constant(Scope, I); 1387a93cbd4eSFinn Plummer ScopeReg = ScopeConstant.first; 1388a93cbd4eSFinn Plummer Result &= ScopeConstant.second; 1389eab7d363SIlia Diachkov 1390b8e1544bSIlia Diachkov unsigned ScSem = static_cast<uint32_t>( 1391b8e1544bSIlia Diachkov getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr))); 1392b8e1544bSIlia Diachkov AtomicOrdering AO = MemOp->getSuccessOrdering(); 1393b8e1544bSIlia Diachkov unsigned MemSemEq = static_cast<uint32_t>(getMemSemantics(AO)) | ScSem; 1394a93cbd4eSFinn Plummer auto MemSemEqConstant = buildI32Constant(MemSemEq, I); 1395a93cbd4eSFinn Plummer MemSemEqReg = MemSemEqConstant.first; 1396a93cbd4eSFinn Plummer Result &= MemSemEqConstant.second; 1397b8e1544bSIlia Diachkov AtomicOrdering FO = MemOp->getFailureOrdering(); 1398b8e1544bSIlia Diachkov unsigned MemSemNeq = static_cast<uint32_t>(getMemSemantics(FO)) | ScSem; 1399a93cbd4eSFinn Plummer if (MemSemEq == MemSemNeq) 1400a93cbd4eSFinn Plummer MemSemNeqReg = MemSemEqReg; 1401a93cbd4eSFinn Plummer else { 1402a93cbd4eSFinn Plummer auto MemSemNeqConstant = buildI32Constant(MemSemEq, I); 1403a93cbd4eSFinn Plummer MemSemNeqReg = MemSemNeqConstant.first; 1404a93cbd4eSFinn Plummer Result &= MemSemNeqConstant.second; 1405a93cbd4eSFinn Plummer } 1406b8e1544bSIlia Diachkov } else { 1407b8e1544bSIlia Diachkov ScopeReg = I.getOperand(5).getReg(); 1408b8e1544bSIlia Diachkov MemSemEqReg = I.getOperand(6).getReg(); 1409b8e1544bSIlia Diachkov MemSemNeqReg = I.getOperand(7).getReg(); 1410b8e1544bSIlia Diachkov } 1411b8e1544bSIlia Diachkov 1412eab7d363SIlia Diachkov Register Cmp = I.getOperand(3).getReg(); 1413eab7d363SIlia Diachkov Register Val = I.getOperand(4).getReg(); 1414eab7d363SIlia Diachkov SPIRVType *SpvValTy = GR.getSPIRVTypeForVReg(Val); 1415f9c98068SVyacheslav Levytskyy Register ACmpRes = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 1416eab7d363SIlia Diachkov const DebugLoc &DL = I.getDebugLoc(); 1417a93cbd4eSFinn Plummer Result &= 1418b8e1544bSIlia Diachkov BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpAtomicCompareExchange)) 1419b8e1544bSIlia Diachkov .addDef(ACmpRes) 1420eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(SpvValTy)) 1421eab7d363SIlia Diachkov .addUse(Ptr) 1422eab7d363SIlia Diachkov .addUse(ScopeReg) 1423eab7d363SIlia Diachkov .addUse(MemSemEqReg) 1424eab7d363SIlia Diachkov .addUse(MemSemNeqReg) 1425eab7d363SIlia Diachkov .addUse(Val) 1426eab7d363SIlia Diachkov .addUse(Cmp) 1427eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 1428f9c98068SVyacheslav Levytskyy Register CmpSuccReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 1429b8e1544bSIlia Diachkov SPIRVType *BoolTy = GR.getOrCreateSPIRVBoolType(I, TII); 1430a93cbd4eSFinn Plummer Result &= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpIEqual)) 1431b8e1544bSIlia Diachkov .addDef(CmpSuccReg) 1432b8e1544bSIlia Diachkov .addUse(GR.getSPIRVTypeID(BoolTy)) 1433b8e1544bSIlia Diachkov .addUse(ACmpRes) 1434b8e1544bSIlia Diachkov .addUse(Cmp) 1435b8e1544bSIlia Diachkov .constrainAllUses(TII, TRI, RBI); 1436f9c98068SVyacheslav Levytskyy Register TmpReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 1437a93cbd4eSFinn Plummer Result &= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert)) 1438b8e1544bSIlia Diachkov .addDef(TmpReg) 1439b8e1544bSIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 1440b8e1544bSIlia Diachkov .addUse(ACmpRes) 1441b8e1544bSIlia Diachkov .addUse(GR.getOrCreateUndef(I, ResType, TII)) 1442b8e1544bSIlia Diachkov .addImm(0) 1443b8e1544bSIlia Diachkov .constrainAllUses(TII, TRI, RBI); 1444a93cbd4eSFinn Plummer return Result && 1445a93cbd4eSFinn Plummer BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert)) 1446b8e1544bSIlia Diachkov .addDef(ResVReg) 1447b8e1544bSIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 1448b8e1544bSIlia Diachkov .addUse(CmpSuccReg) 1449b8e1544bSIlia Diachkov .addUse(TmpReg) 1450b8e1544bSIlia Diachkov .addImm(1) 1451b8e1544bSIlia Diachkov .constrainAllUses(TII, TRI, RBI); 1452eab7d363SIlia Diachkov } 1453eab7d363SIlia Diachkov 1454b25b507cSIlia Diachkov static bool isGenericCastablePtr(SPIRV::StorageClass::StorageClass SC) { 1455eab7d363SIlia Diachkov switch (SC) { 1456eab7d363SIlia Diachkov case SPIRV::StorageClass::Workgroup: 1457eab7d363SIlia Diachkov case SPIRV::StorageClass::CrossWorkgroup: 1458eab7d363SIlia Diachkov case SPIRV::StorageClass::Function: 1459eab7d363SIlia Diachkov return true; 1460eab7d363SIlia Diachkov default: 1461eab7d363SIlia Diachkov return false; 1462eab7d363SIlia Diachkov } 1463eab7d363SIlia Diachkov } 1464eab7d363SIlia Diachkov 14654a602d92SVyacheslav Levytskyy static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) { 14664a602d92SVyacheslav Levytskyy switch (SC) { 14674a602d92SVyacheslav Levytskyy case SPIRV::StorageClass::DeviceOnlyINTEL: 14684a602d92SVyacheslav Levytskyy case SPIRV::StorageClass::HostOnlyINTEL: 14694a602d92SVyacheslav Levytskyy return true; 14704a602d92SVyacheslav Levytskyy default: 14714a602d92SVyacheslav Levytskyy return false; 14724a602d92SVyacheslav Levytskyy } 14734a602d92SVyacheslav Levytskyy } 14744a602d92SVyacheslav Levytskyy 14753e79c7feSVyacheslav Levytskyy // Returns true ResVReg is referred only from global vars and OpName's. 14763e79c7feSVyacheslav Levytskyy static bool isASCastInGVar(MachineRegisterInfo *MRI, Register ResVReg) { 14773e79c7feSVyacheslav Levytskyy bool IsGRef = false; 14783e79c7feSVyacheslav Levytskyy bool IsAllowedRefs = 14793e79c7feSVyacheslav Levytskyy std::all_of(MRI->use_instr_begin(ResVReg), MRI->use_instr_end(), 14803e79c7feSVyacheslav Levytskyy [&IsGRef](auto const &It) { 14813e79c7feSVyacheslav Levytskyy unsigned Opcode = It.getOpcode(); 14823e79c7feSVyacheslav Levytskyy if (Opcode == SPIRV::OpConstantComposite || 14833e79c7feSVyacheslav Levytskyy Opcode == SPIRV::OpVariable || 14843e79c7feSVyacheslav Levytskyy isSpvIntrinsic(It, Intrinsic::spv_init_global)) 14853e79c7feSVyacheslav Levytskyy return IsGRef = true; 14863e79c7feSVyacheslav Levytskyy return Opcode == SPIRV::OpName; 14873e79c7feSVyacheslav Levytskyy }); 14883e79c7feSVyacheslav Levytskyy return IsAllowedRefs && IsGRef; 14893e79c7feSVyacheslav Levytskyy } 14903e79c7feSVyacheslav Levytskyy 14913e79c7feSVyacheslav Levytskyy Register SPIRVInstructionSelector::getUcharPtrTypeReg( 14923e79c7feSVyacheslav Levytskyy MachineInstr &I, SPIRV::StorageClass::StorageClass SC) const { 14933e79c7feSVyacheslav Levytskyy return GR.getSPIRVTypeID(GR.getOrCreateSPIRVPointerType( 14943e79c7feSVyacheslav Levytskyy GR.getOrCreateSPIRVIntegerType(8, I, TII), I, TII, SC)); 14953e79c7feSVyacheslav Levytskyy } 14963e79c7feSVyacheslav Levytskyy 14973e79c7feSVyacheslav Levytskyy MachineInstrBuilder 14983e79c7feSVyacheslav Levytskyy SPIRVInstructionSelector::buildSpecConstantOp(MachineInstr &I, Register Dest, 14993e79c7feSVyacheslav Levytskyy Register Src, Register DestType, 15003e79c7feSVyacheslav Levytskyy uint32_t Opcode) const { 15013e79c7feSVyacheslav Levytskyy return BuildMI(*I.getParent(), I, I.getDebugLoc(), 15023e79c7feSVyacheslav Levytskyy TII.get(SPIRV::OpSpecConstantOp)) 15033e79c7feSVyacheslav Levytskyy .addDef(Dest) 15043e79c7feSVyacheslav Levytskyy .addUse(DestType) 15053e79c7feSVyacheslav Levytskyy .addImm(Opcode) 15063e79c7feSVyacheslav Levytskyy .addUse(Src); 15073e79c7feSVyacheslav Levytskyy } 15083e79c7feSVyacheslav Levytskyy 15093e79c7feSVyacheslav Levytskyy MachineInstrBuilder 15103e79c7feSVyacheslav Levytskyy SPIRVInstructionSelector::buildConstGenericPtr(MachineInstr &I, Register SrcPtr, 15113e79c7feSVyacheslav Levytskyy SPIRVType *SrcPtrTy) const { 15123e79c7feSVyacheslav Levytskyy SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType( 15133e79c7feSVyacheslav Levytskyy GR.getPointeeType(SrcPtrTy), I, TII, SPIRV::StorageClass::Generic); 15143e79c7feSVyacheslav Levytskyy Register Tmp = MRI->createVirtualRegister(&SPIRV::pIDRegClass); 15153e79c7feSVyacheslav Levytskyy MRI->setType(Tmp, LLT::pointer(storageClassToAddressSpace( 15163e79c7feSVyacheslav Levytskyy SPIRV::StorageClass::Generic), 15173e79c7feSVyacheslav Levytskyy GR.getPointerSize())); 15183e79c7feSVyacheslav Levytskyy MachineFunction *MF = I.getParent()->getParent(); 15193e79c7feSVyacheslav Levytskyy GR.assignSPIRVTypeToVReg(GenericPtrTy, Tmp, *MF); 15203e79c7feSVyacheslav Levytskyy MachineInstrBuilder MIB = buildSpecConstantOp( 15213e79c7feSVyacheslav Levytskyy I, Tmp, SrcPtr, GR.getSPIRVTypeID(GenericPtrTy), 15223e79c7feSVyacheslav Levytskyy static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric)); 15233e79c7feSVyacheslav Levytskyy GR.add(MIB.getInstr(), MF, Tmp); 15243e79c7feSVyacheslav Levytskyy return MIB; 15253e79c7feSVyacheslav Levytskyy } 15263e79c7feSVyacheslav Levytskyy 1527eab7d363SIlia Diachkov // In SPIR-V address space casting can only happen to and from the Generic 15284a602d92SVyacheslav Levytskyy // storage class. We can also only cast Workgroup, CrossWorkgroup, or Function 1529eab7d363SIlia Diachkov // pointers to and from Generic pointers. As such, we can convert e.g. from 1530eab7d363SIlia Diachkov // Workgroup to Function by going via a Generic pointer as an intermediary. All 1531eab7d363SIlia Diachkov // other combinations can only be done by a bitcast, and are probably not safe. 1532eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg, 1533eab7d363SIlia Diachkov const SPIRVType *ResType, 1534eab7d363SIlia Diachkov MachineInstr &I) const { 1535b8e1544bSIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 15363e79c7feSVyacheslav Levytskyy const DebugLoc &DL = I.getDebugLoc(); 15373e79c7feSVyacheslav Levytskyy 1538eab7d363SIlia Diachkov Register SrcPtr = I.getOperand(1).getReg(); 1539eab7d363SIlia Diachkov SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr); 15403e79c7feSVyacheslav Levytskyy 15413e79c7feSVyacheslav Levytskyy // don't generate a cast for a null that may be represented by OpTypeInt 15423e79c7feSVyacheslav Levytskyy if (SrcPtrTy->getOpcode() != SPIRV::OpTypePointer || 15433e79c7feSVyacheslav Levytskyy ResType->getOpcode() != SPIRV::OpTypePointer) 154442633cf2SVyacheslav Levytskyy return BuildCOPY(ResVReg, SrcPtr, I); 15453e79c7feSVyacheslav Levytskyy 15463e79c7feSVyacheslav Levytskyy SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtrTy); 15473e79c7feSVyacheslav Levytskyy SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResType); 15483e79c7feSVyacheslav Levytskyy 15493e79c7feSVyacheslav Levytskyy if (isASCastInGVar(MRI, ResVReg)) { 15503e79c7feSVyacheslav Levytskyy // AddrSpaceCast uses within OpVariable and OpConstantComposite instructions 15513e79c7feSVyacheslav Levytskyy // are expressed by OpSpecConstantOp with an Opcode. 15523e79c7feSVyacheslav Levytskyy // TODO: maybe insert a check whether the Kernel capability was declared and 15533e79c7feSVyacheslav Levytskyy // so PtrCastToGeneric/GenericCastToPtr are available. 15543e79c7feSVyacheslav Levytskyy unsigned SpecOpcode = 15553e79c7feSVyacheslav Levytskyy DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC) 15563e79c7feSVyacheslav Levytskyy ? static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric) 15573e79c7feSVyacheslav Levytskyy : (SrcSC == SPIRV::StorageClass::Generic && 15583e79c7feSVyacheslav Levytskyy isGenericCastablePtr(DstSC) 15593e79c7feSVyacheslav Levytskyy ? static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr) 15603e79c7feSVyacheslav Levytskyy : 0); 15613e79c7feSVyacheslav Levytskyy // TODO: OpConstantComposite expects i8*, so we are forced to forget a 15623e79c7feSVyacheslav Levytskyy // correct value of ResType and use general i8* instead. Maybe this should 15633e79c7feSVyacheslav Levytskyy // be addressed in the emit-intrinsic step to infer a correct 15643e79c7feSVyacheslav Levytskyy // OpConstantComposite type. 15653e79c7feSVyacheslav Levytskyy if (SpecOpcode) { 15663e79c7feSVyacheslav Levytskyy return buildSpecConstantOp(I, ResVReg, SrcPtr, 15673e79c7feSVyacheslav Levytskyy getUcharPtrTypeReg(I, DstSC), SpecOpcode) 15683e79c7feSVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 15693e79c7feSVyacheslav Levytskyy } else if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) { 15703e79c7feSVyacheslav Levytskyy MachineInstrBuilder MIB = buildConstGenericPtr(I, SrcPtr, SrcPtrTy); 15713e79c7feSVyacheslav Levytskyy return MIB.constrainAllUses(TII, TRI, RBI) && 15723e79c7feSVyacheslav Levytskyy buildSpecConstantOp( 15733e79c7feSVyacheslav Levytskyy I, ResVReg, MIB->getOperand(0).getReg(), 15743e79c7feSVyacheslav Levytskyy getUcharPtrTypeReg(I, DstSC), 15753e79c7feSVyacheslav Levytskyy static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr)) 15763e79c7feSVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 15773e79c7feSVyacheslav Levytskyy } 15783e79c7feSVyacheslav Levytskyy } 1579eab7d363SIlia Diachkov 15804a602d92SVyacheslav Levytskyy // don't generate a cast between identical storage classes 15814a602d92SVyacheslav Levytskyy if (SrcSC == DstSC) 158242633cf2SVyacheslav Levytskyy return BuildCOPY(ResVReg, SrcPtr, I); 15834a602d92SVyacheslav Levytskyy 15845f99eb9bSNathan Gauër if ((SrcSC == SPIRV::StorageClass::Function && 15855f99eb9bSNathan Gauër DstSC == SPIRV::StorageClass::Private) || 15865f99eb9bSNathan Gauër (DstSC == SPIRV::StorageClass::Function && 158742633cf2SVyacheslav Levytskyy SrcSC == SPIRV::StorageClass::Private)) 158842633cf2SVyacheslav Levytskyy return BuildCOPY(ResVReg, SrcPtr, I); 15895f99eb9bSNathan Gauër 15904a602d92SVyacheslav Levytskyy // Casting from an eligible pointer to Generic. 1591eab7d363SIlia Diachkov if (DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(SrcSC)) 1592eab7d363SIlia Diachkov return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric); 15934a602d92SVyacheslav Levytskyy // Casting from Generic to an eligible pointer. 1594eab7d363SIlia Diachkov if (SrcSC == SPIRV::StorageClass::Generic && isGenericCastablePtr(DstSC)) 1595eab7d363SIlia Diachkov return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr); 15964a602d92SVyacheslav Levytskyy // Casting between 2 eligible pointers using Generic as an intermediary. 1597eab7d363SIlia Diachkov if (isGenericCastablePtr(SrcSC) && isGenericCastablePtr(DstSC)) { 1598f9c98068SVyacheslav Levytskyy Register Tmp = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 1599eab7d363SIlia Diachkov SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType( 160057f79371SVyacheslav Levytskyy GR.getPointeeType(SrcPtrTy), I, TII, SPIRV::StorageClass::Generic); 1601a93cbd4eSFinn Plummer bool Result = BuildMI(BB, I, DL, TII.get(SPIRV::OpPtrCastToGeneric)) 1602eab7d363SIlia Diachkov .addDef(Tmp) 1603eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(GenericPtrTy)) 1604eab7d363SIlia Diachkov .addUse(SrcPtr) 1605eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 1606a93cbd4eSFinn Plummer return Result && BuildMI(BB, I, DL, TII.get(SPIRV::OpGenericCastToPtr)) 1607eab7d363SIlia Diachkov .addDef(ResVReg) 1608eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 1609eab7d363SIlia Diachkov .addUse(Tmp) 1610eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 1611eab7d363SIlia Diachkov } 16124a602d92SVyacheslav Levytskyy 16134a602d92SVyacheslav Levytskyy // Check if instructions from the SPV_INTEL_usm_storage_classes extension may 16144a602d92SVyacheslav Levytskyy // be applied 16154a602d92SVyacheslav Levytskyy if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::CrossWorkgroup) 16164a602d92SVyacheslav Levytskyy return selectUnOp(ResVReg, ResType, I, 16174a602d92SVyacheslav Levytskyy SPIRV::OpPtrCastToCrossWorkgroupINTEL); 16184a602d92SVyacheslav Levytskyy if (SrcSC == SPIRV::StorageClass::CrossWorkgroup && isUSMStorageClass(DstSC)) 16194a602d92SVyacheslav Levytskyy return selectUnOp(ResVReg, ResType, I, 16204a602d92SVyacheslav Levytskyy SPIRV::OpCrossWorkgroupCastToPtrINTEL); 16219a737109SVyacheslav Levytskyy if (isUSMStorageClass(SrcSC) && DstSC == SPIRV::StorageClass::Generic) 16229a737109SVyacheslav Levytskyy return selectUnOp(ResVReg, ResType, I, SPIRV::OpPtrCastToGeneric); 16239a737109SVyacheslav Levytskyy if (SrcSC == SPIRV::StorageClass::Generic && isUSMStorageClass(DstSC)) 16249a737109SVyacheslav Levytskyy return selectUnOp(ResVReg, ResType, I, SPIRV::OpGenericCastToPtr); 16254a602d92SVyacheslav Levytskyy 16269a737109SVyacheslav Levytskyy // Bitcast for pointers requires that the address spaces must match 16279a737109SVyacheslav Levytskyy return false; 1628eab7d363SIlia Diachkov } 1629eab7d363SIlia Diachkov 1630eab7d363SIlia Diachkov static unsigned getFCmpOpcode(unsigned PredNum) { 1631eab7d363SIlia Diachkov auto Pred = static_cast<CmpInst::Predicate>(PredNum); 1632eab7d363SIlia Diachkov switch (Pred) { 1633eab7d363SIlia Diachkov case CmpInst::FCMP_OEQ: 1634eab7d363SIlia Diachkov return SPIRV::OpFOrdEqual; 1635eab7d363SIlia Diachkov case CmpInst::FCMP_OGE: 1636eab7d363SIlia Diachkov return SPIRV::OpFOrdGreaterThanEqual; 1637eab7d363SIlia Diachkov case CmpInst::FCMP_OGT: 1638eab7d363SIlia Diachkov return SPIRV::OpFOrdGreaterThan; 1639eab7d363SIlia Diachkov case CmpInst::FCMP_OLE: 1640eab7d363SIlia Diachkov return SPIRV::OpFOrdLessThanEqual; 1641eab7d363SIlia Diachkov case CmpInst::FCMP_OLT: 1642eab7d363SIlia Diachkov return SPIRV::OpFOrdLessThan; 1643eab7d363SIlia Diachkov case CmpInst::FCMP_ONE: 1644eab7d363SIlia Diachkov return SPIRV::OpFOrdNotEqual; 1645eab7d363SIlia Diachkov case CmpInst::FCMP_ORD: 1646eab7d363SIlia Diachkov return SPIRV::OpOrdered; 1647eab7d363SIlia Diachkov case CmpInst::FCMP_UEQ: 1648eab7d363SIlia Diachkov return SPIRV::OpFUnordEqual; 1649eab7d363SIlia Diachkov case CmpInst::FCMP_UGE: 1650eab7d363SIlia Diachkov return SPIRV::OpFUnordGreaterThanEqual; 1651eab7d363SIlia Diachkov case CmpInst::FCMP_UGT: 1652eab7d363SIlia Diachkov return SPIRV::OpFUnordGreaterThan; 1653eab7d363SIlia Diachkov case CmpInst::FCMP_ULE: 1654eab7d363SIlia Diachkov return SPIRV::OpFUnordLessThanEqual; 1655eab7d363SIlia Diachkov case CmpInst::FCMP_ULT: 1656eab7d363SIlia Diachkov return SPIRV::OpFUnordLessThan; 1657eab7d363SIlia Diachkov case CmpInst::FCMP_UNE: 1658eab7d363SIlia Diachkov return SPIRV::OpFUnordNotEqual; 1659eab7d363SIlia Diachkov case CmpInst::FCMP_UNO: 1660eab7d363SIlia Diachkov return SPIRV::OpUnordered; 1661eab7d363SIlia Diachkov default: 1662eab7d363SIlia Diachkov llvm_unreachable("Unknown predicate type for FCmp"); 1663eab7d363SIlia Diachkov } 1664eab7d363SIlia Diachkov } 1665eab7d363SIlia Diachkov 1666eab7d363SIlia Diachkov static unsigned getICmpOpcode(unsigned PredNum) { 1667eab7d363SIlia Diachkov auto Pred = static_cast<CmpInst::Predicate>(PredNum); 1668eab7d363SIlia Diachkov switch (Pred) { 1669eab7d363SIlia Diachkov case CmpInst::ICMP_EQ: 1670eab7d363SIlia Diachkov return SPIRV::OpIEqual; 1671eab7d363SIlia Diachkov case CmpInst::ICMP_NE: 1672eab7d363SIlia Diachkov return SPIRV::OpINotEqual; 1673eab7d363SIlia Diachkov case CmpInst::ICMP_SGE: 1674eab7d363SIlia Diachkov return SPIRV::OpSGreaterThanEqual; 1675eab7d363SIlia Diachkov case CmpInst::ICMP_SGT: 1676eab7d363SIlia Diachkov return SPIRV::OpSGreaterThan; 1677eab7d363SIlia Diachkov case CmpInst::ICMP_SLE: 1678eab7d363SIlia Diachkov return SPIRV::OpSLessThanEqual; 1679eab7d363SIlia Diachkov case CmpInst::ICMP_SLT: 1680eab7d363SIlia Diachkov return SPIRV::OpSLessThan; 1681eab7d363SIlia Diachkov case CmpInst::ICMP_UGE: 1682eab7d363SIlia Diachkov return SPIRV::OpUGreaterThanEqual; 1683eab7d363SIlia Diachkov case CmpInst::ICMP_UGT: 1684eab7d363SIlia Diachkov return SPIRV::OpUGreaterThan; 1685eab7d363SIlia Diachkov case CmpInst::ICMP_ULE: 1686eab7d363SIlia Diachkov return SPIRV::OpULessThanEqual; 1687eab7d363SIlia Diachkov case CmpInst::ICMP_ULT: 1688eab7d363SIlia Diachkov return SPIRV::OpULessThan; 1689eab7d363SIlia Diachkov default: 1690eab7d363SIlia Diachkov llvm_unreachable("Unknown predicate type for ICmp"); 1691eab7d363SIlia Diachkov } 1692eab7d363SIlia Diachkov } 1693eab7d363SIlia Diachkov 1694eab7d363SIlia Diachkov static unsigned getPtrCmpOpcode(unsigned Pred) { 1695eab7d363SIlia Diachkov switch (static_cast<CmpInst::Predicate>(Pred)) { 1696eab7d363SIlia Diachkov case CmpInst::ICMP_EQ: 1697eab7d363SIlia Diachkov return SPIRV::OpPtrEqual; 1698eab7d363SIlia Diachkov case CmpInst::ICMP_NE: 1699eab7d363SIlia Diachkov return SPIRV::OpPtrNotEqual; 1700eab7d363SIlia Diachkov default: 1701eab7d363SIlia Diachkov llvm_unreachable("Unknown predicate type for pointer comparison"); 1702eab7d363SIlia Diachkov } 1703eab7d363SIlia Diachkov } 1704eab7d363SIlia Diachkov 1705eab7d363SIlia Diachkov // Return the logical operation, or abort if none exists. 1706eab7d363SIlia Diachkov static unsigned getBoolCmpOpcode(unsigned PredNum) { 1707eab7d363SIlia Diachkov auto Pred = static_cast<CmpInst::Predicate>(PredNum); 1708eab7d363SIlia Diachkov switch (Pred) { 1709eab7d363SIlia Diachkov case CmpInst::ICMP_EQ: 1710eab7d363SIlia Diachkov return SPIRV::OpLogicalEqual; 1711eab7d363SIlia Diachkov case CmpInst::ICMP_NE: 1712eab7d363SIlia Diachkov return SPIRV::OpLogicalNotEqual; 1713eab7d363SIlia Diachkov default: 1714eab7d363SIlia Diachkov llvm_unreachable("Unknown predicate type for Bool comparison"); 1715eab7d363SIlia Diachkov } 1716eab7d363SIlia Diachkov } 1717eab7d363SIlia Diachkov 17186a38e19cSS. Bharadwaj Yadavalli static APFloat getZeroFP(const Type *LLVMFloatTy) { 17196a38e19cSS. Bharadwaj Yadavalli if (!LLVMFloatTy) 17206a38e19cSS. Bharadwaj Yadavalli return APFloat::getZero(APFloat::IEEEsingle()); 17216a38e19cSS. Bharadwaj Yadavalli switch (LLVMFloatTy->getScalarType()->getTypeID()) { 17226a38e19cSS. Bharadwaj Yadavalli case Type::HalfTyID: 17236a38e19cSS. Bharadwaj Yadavalli return APFloat::getZero(APFloat::IEEEhalf()); 17246a38e19cSS. Bharadwaj Yadavalli default: 17256a38e19cSS. Bharadwaj Yadavalli case Type::FloatTyID: 17266a38e19cSS. Bharadwaj Yadavalli return APFloat::getZero(APFloat::IEEEsingle()); 17276a38e19cSS. Bharadwaj Yadavalli case Type::DoubleTyID: 17286a38e19cSS. Bharadwaj Yadavalli return APFloat::getZero(APFloat::IEEEdouble()); 17296a38e19cSS. Bharadwaj Yadavalli } 17306a38e19cSS. Bharadwaj Yadavalli } 17316a38e19cSS. Bharadwaj Yadavalli 17326a38e19cSS. Bharadwaj Yadavalli static APFloat getOneFP(const Type *LLVMFloatTy) { 17336a38e19cSS. Bharadwaj Yadavalli if (!LLVMFloatTy) 17346a38e19cSS. Bharadwaj Yadavalli return APFloat::getOne(APFloat::IEEEsingle()); 17356a38e19cSS. Bharadwaj Yadavalli switch (LLVMFloatTy->getScalarType()->getTypeID()) { 17366a38e19cSS. Bharadwaj Yadavalli case Type::HalfTyID: 17376a38e19cSS. Bharadwaj Yadavalli return APFloat::getOne(APFloat::IEEEhalf()); 17386a38e19cSS. Bharadwaj Yadavalli default: 17396a38e19cSS. Bharadwaj Yadavalli case Type::FloatTyID: 17406a38e19cSS. Bharadwaj Yadavalli return APFloat::getOne(APFloat::IEEEsingle()); 17416a38e19cSS. Bharadwaj Yadavalli case Type::DoubleTyID: 17426a38e19cSS. Bharadwaj Yadavalli return APFloat::getOne(APFloat::IEEEdouble()); 17436a38e19cSS. Bharadwaj Yadavalli } 17446a38e19cSS. Bharadwaj Yadavalli } 17456a38e19cSS. Bharadwaj Yadavalli 1746105dcc88SFarzon Lotfi bool SPIRVInstructionSelector::selectAnyOrAll(Register ResVReg, 174705093e24SFarzon Lotfi const SPIRVType *ResType, 1748105dcc88SFarzon Lotfi MachineInstr &I, 1749105dcc88SFarzon Lotfi unsigned OpAnyOrAll) const { 175005093e24SFarzon Lotfi assert(I.getNumOperands() == 3); 175105093e24SFarzon Lotfi assert(I.getOperand(2).isReg()); 175205093e24SFarzon Lotfi MachineBasicBlock &BB = *I.getParent(); 175305093e24SFarzon Lotfi Register InputRegister = I.getOperand(2).getReg(); 175405093e24SFarzon Lotfi SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister); 175505093e24SFarzon Lotfi 175605093e24SFarzon Lotfi if (!InputType) 175705093e24SFarzon Lotfi report_fatal_error("Input Type could not be determined."); 175805093e24SFarzon Lotfi 175905093e24SFarzon Lotfi bool IsBoolTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeBool); 176005093e24SFarzon Lotfi bool IsVectorTy = InputType->getOpcode() == SPIRV::OpTypeVector; 176105093e24SFarzon Lotfi if (IsBoolTy && !IsVectorTy) { 176205093e24SFarzon Lotfi assert(ResVReg == I.getOperand(0).getReg()); 176342633cf2SVyacheslav Levytskyy return BuildCOPY(ResVReg, InputRegister, I); 176405093e24SFarzon Lotfi } 176505093e24SFarzon Lotfi 176605093e24SFarzon Lotfi bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat); 176705093e24SFarzon Lotfi unsigned SpirvNotEqualId = 176805093e24SFarzon Lotfi IsFloatTy ? SPIRV::OpFOrdNotEqual : SPIRV::OpINotEqual; 176905093e24SFarzon Lotfi SPIRVType *SpvBoolScalarTy = GR.getOrCreateSPIRVBoolType(I, TII); 177005093e24SFarzon Lotfi SPIRVType *SpvBoolTy = SpvBoolScalarTy; 177105093e24SFarzon Lotfi Register NotEqualReg = ResVReg; 177205093e24SFarzon Lotfi 177305093e24SFarzon Lotfi if (IsVectorTy) { 177405093e24SFarzon Lotfi NotEqualReg = IsBoolTy ? InputRegister 1775f9c98068SVyacheslav Levytskyy : MRI->createVirtualRegister(&SPIRV::iIDRegClass); 177605093e24SFarzon Lotfi const unsigned NumElts = InputType->getOperand(2).getImm(); 177705093e24SFarzon Lotfi SpvBoolTy = GR.getOrCreateSPIRVVectorType(SpvBoolTy, NumElts, I, TII); 177805093e24SFarzon Lotfi } 177905093e24SFarzon Lotfi 1780a93cbd4eSFinn Plummer bool Result = true; 178105093e24SFarzon Lotfi if (!IsBoolTy) { 178205093e24SFarzon Lotfi Register ConstZeroReg = 178305093e24SFarzon Lotfi IsFloatTy ? buildZerosValF(InputType, I) : buildZerosVal(InputType, I); 178405093e24SFarzon Lotfi 1785a93cbd4eSFinn Plummer Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(SpirvNotEqualId)) 178605093e24SFarzon Lotfi .addDef(NotEqualReg) 178705093e24SFarzon Lotfi .addUse(GR.getSPIRVTypeID(SpvBoolTy)) 178805093e24SFarzon Lotfi .addUse(InputRegister) 178905093e24SFarzon Lotfi .addUse(ConstZeroReg) 179005093e24SFarzon Lotfi .constrainAllUses(TII, TRI, RBI); 179105093e24SFarzon Lotfi } 179205093e24SFarzon Lotfi 179305093e24SFarzon Lotfi if (!IsVectorTy) 1794a93cbd4eSFinn Plummer return Result; 179505093e24SFarzon Lotfi 1796a93cbd4eSFinn Plummer return Result && BuildMI(BB, I, I.getDebugLoc(), TII.get(OpAnyOrAll)) 179705093e24SFarzon Lotfi .addDef(ResVReg) 179805093e24SFarzon Lotfi .addUse(GR.getSPIRVTypeID(SpvBoolScalarTy)) 179905093e24SFarzon Lotfi .addUse(NotEqualReg) 180005093e24SFarzon Lotfi .constrainAllUses(TII, TRI, RBI); 180105093e24SFarzon Lotfi } 180205093e24SFarzon Lotfi 1803105dcc88SFarzon Lotfi bool SPIRVInstructionSelector::selectAll(Register ResVReg, 1804105dcc88SFarzon Lotfi const SPIRVType *ResType, 1805105dcc88SFarzon Lotfi MachineInstr &I) const { 1806105dcc88SFarzon Lotfi return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAll); 1807105dcc88SFarzon Lotfi } 1808105dcc88SFarzon Lotfi 1809105dcc88SFarzon Lotfi bool SPIRVInstructionSelector::selectAny(Register ResVReg, 1810105dcc88SFarzon Lotfi const SPIRVType *ResType, 1811105dcc88SFarzon Lotfi MachineInstr &I) const { 1812105dcc88SFarzon Lotfi return selectAnyOrAll(ResVReg, ResType, I, SPIRV::OpAny); 1813105dcc88SFarzon Lotfi } 1814105dcc88SFarzon Lotfi 1815319c7a42SGreg Roth // Select the OpDot instruction for the given float dot 1816319c7a42SGreg Roth bool SPIRVInstructionSelector::selectFloatDot(Register ResVReg, 1817319c7a42SGreg Roth const SPIRVType *ResType, 1818319c7a42SGreg Roth MachineInstr &I) const { 1819319c7a42SGreg Roth assert(I.getNumOperands() == 4); 1820319c7a42SGreg Roth assert(I.getOperand(2).isReg()); 1821319c7a42SGreg Roth assert(I.getOperand(3).isReg()); 1822319c7a42SGreg Roth 1823319c7a42SGreg Roth [[maybe_unused]] SPIRVType *VecType = 1824319c7a42SGreg Roth GR.getSPIRVTypeForVReg(I.getOperand(2).getReg()); 1825319c7a42SGreg Roth 1826319c7a42SGreg Roth assert(VecType->getOpcode() == SPIRV::OpTypeVector && 1827319c7a42SGreg Roth GR.getScalarOrVectorComponentCount(VecType) > 1 && 1828319c7a42SGreg Roth "dot product requires a vector of at least 2 components"); 1829319c7a42SGreg Roth 1830319c7a42SGreg Roth [[maybe_unused]] SPIRVType *EltType = 1831319c7a42SGreg Roth GR.getSPIRVTypeForVReg(VecType->getOperand(1).getReg()); 1832319c7a42SGreg Roth 1833319c7a42SGreg Roth assert(EltType->getOpcode() == SPIRV::OpTypeFloat); 1834319c7a42SGreg Roth 1835319c7a42SGreg Roth MachineBasicBlock &BB = *I.getParent(); 1836319c7a42SGreg Roth return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpDot)) 1837319c7a42SGreg Roth .addDef(ResVReg) 1838319c7a42SGreg Roth .addUse(GR.getSPIRVTypeID(ResType)) 1839319c7a42SGreg Roth .addUse(I.getOperand(2).getReg()) 1840319c7a42SGreg Roth .addUse(I.getOperand(3).getReg()) 1841319c7a42SGreg Roth .constrainAllUses(TII, TRI, RBI); 1842319c7a42SGreg Roth } 1843319c7a42SGreg Roth 1844319c7a42SGreg Roth bool SPIRVInstructionSelector::selectIntegerDot(Register ResVReg, 1845319c7a42SGreg Roth const SPIRVType *ResType, 1846dcd69ddeSFinn Plummer MachineInstr &I, 1847dcd69ddeSFinn Plummer bool Signed) const { 1848dcd69ddeSFinn Plummer assert(I.getNumOperands() == 4); 1849dcd69ddeSFinn Plummer assert(I.getOperand(2).isReg()); 1850dcd69ddeSFinn Plummer assert(I.getOperand(3).isReg()); 1851dcd69ddeSFinn Plummer MachineBasicBlock &BB = *I.getParent(); 1852dcd69ddeSFinn Plummer 1853dcd69ddeSFinn Plummer auto DotOp = Signed ? SPIRV::OpSDot : SPIRV::OpUDot; 1854dcd69ddeSFinn Plummer return BuildMI(BB, I, I.getDebugLoc(), TII.get(DotOp)) 1855dcd69ddeSFinn Plummer .addDef(ResVReg) 1856dcd69ddeSFinn Plummer .addUse(GR.getSPIRVTypeID(ResType)) 1857dcd69ddeSFinn Plummer .addUse(I.getOperand(2).getReg()) 1858dcd69ddeSFinn Plummer .addUse(I.getOperand(3).getReg()) 1859dcd69ddeSFinn Plummer .constrainAllUses(TII, TRI, RBI); 1860dcd69ddeSFinn Plummer } 1861dcd69ddeSFinn Plummer 1862dcd69ddeSFinn Plummer // Since pre-1.6 SPIRV has no integer dot implementation, 1863dcd69ddeSFinn Plummer // expand by piecewise multiplying and adding the results 1864dcd69ddeSFinn Plummer bool SPIRVInstructionSelector::selectIntegerDotExpansion( 1865dcd69ddeSFinn Plummer Register ResVReg, const SPIRVType *ResType, MachineInstr &I) const { 1866319c7a42SGreg Roth assert(I.getNumOperands() == 4); 1867319c7a42SGreg Roth assert(I.getOperand(2).isReg()); 1868319c7a42SGreg Roth assert(I.getOperand(3).isReg()); 1869319c7a42SGreg Roth MachineBasicBlock &BB = *I.getParent(); 1870319c7a42SGreg Roth 1871319c7a42SGreg Roth // Multiply the vectors, then sum the results 1872319c7a42SGreg Roth Register Vec0 = I.getOperand(2).getReg(); 1873319c7a42SGreg Roth Register Vec1 = I.getOperand(3).getReg(); 18743cdac067SFinn Plummer Register TmpVec = MRI->createVirtualRegister(GR.getRegClass(ResType)); 1875319c7a42SGreg Roth SPIRVType *VecType = GR.getSPIRVTypeForVReg(Vec0); 1876319c7a42SGreg Roth 1877319c7a42SGreg Roth bool Result = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIMulV)) 1878319c7a42SGreg Roth .addDef(TmpVec) 1879319c7a42SGreg Roth .addUse(GR.getSPIRVTypeID(VecType)) 1880319c7a42SGreg Roth .addUse(Vec0) 1881319c7a42SGreg Roth .addUse(Vec1) 1882319c7a42SGreg Roth .constrainAllUses(TII, TRI, RBI); 1883319c7a42SGreg Roth 1884319c7a42SGreg Roth assert(VecType->getOpcode() == SPIRV::OpTypeVector && 1885319c7a42SGreg Roth GR.getScalarOrVectorComponentCount(VecType) > 1 && 1886319c7a42SGreg Roth "dot product requires a vector of at least 2 components"); 1887319c7a42SGreg Roth 18883cdac067SFinn Plummer Register Res = MRI->createVirtualRegister(GR.getRegClass(ResType)); 18893cdac067SFinn Plummer Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract)) 1890319c7a42SGreg Roth .addDef(Res) 1891319c7a42SGreg Roth .addUse(GR.getSPIRVTypeID(ResType)) 1892319c7a42SGreg Roth .addUse(TmpVec) 1893319c7a42SGreg Roth .addImm(0) 1894319c7a42SGreg Roth .constrainAllUses(TII, TRI, RBI); 1895319c7a42SGreg Roth 1896319c7a42SGreg Roth for (unsigned i = 1; i < GR.getScalarOrVectorComponentCount(VecType); i++) { 18973cdac067SFinn Plummer Register Elt = MRI->createVirtualRegister(GR.getRegClass(ResType)); 1898319c7a42SGreg Roth 18993cdac067SFinn Plummer Result &= 1900319c7a42SGreg Roth BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract)) 1901319c7a42SGreg Roth .addDef(Elt) 1902319c7a42SGreg Roth .addUse(GR.getSPIRVTypeID(ResType)) 1903319c7a42SGreg Roth .addUse(TmpVec) 1904319c7a42SGreg Roth .addImm(i) 1905319c7a42SGreg Roth .constrainAllUses(TII, TRI, RBI); 1906319c7a42SGreg Roth 1907319c7a42SGreg Roth Register Sum = i < GR.getScalarOrVectorComponentCount(VecType) - 1 19083cdac067SFinn Plummer ? MRI->createVirtualRegister(GR.getRegClass(ResType)) 1909319c7a42SGreg Roth : ResVReg; 1910319c7a42SGreg Roth 19113cdac067SFinn Plummer Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS)) 1912319c7a42SGreg Roth .addDef(Sum) 1913319c7a42SGreg Roth .addUse(GR.getSPIRVTypeID(ResType)) 1914319c7a42SGreg Roth .addUse(Res) 1915319c7a42SGreg Roth .addUse(Elt) 1916319c7a42SGreg Roth .constrainAllUses(TII, TRI, RBI); 1917319c7a42SGreg Roth Res = Sum; 1918319c7a42SGreg Roth } 1919319c7a42SGreg Roth 1920319c7a42SGreg Roth return Result; 1921319c7a42SGreg Roth } 1922319c7a42SGreg Roth 19233cdac067SFinn Plummer template <bool Signed> 19243cdac067SFinn Plummer bool SPIRVInstructionSelector::selectDot4AddPacked(Register ResVReg, 19253cdac067SFinn Plummer const SPIRVType *ResType, 19263cdac067SFinn Plummer MachineInstr &I) const { 19273cdac067SFinn Plummer assert(I.getNumOperands() == 5); 19283cdac067SFinn Plummer assert(I.getOperand(2).isReg()); 19293cdac067SFinn Plummer assert(I.getOperand(3).isReg()); 19303cdac067SFinn Plummer assert(I.getOperand(4).isReg()); 19313cdac067SFinn Plummer MachineBasicBlock &BB = *I.getParent(); 19323cdac067SFinn Plummer 19333cdac067SFinn Plummer auto DotOp = Signed ? SPIRV::OpSDot : SPIRV::OpUDot; 19343cdac067SFinn Plummer Register Dot = MRI->createVirtualRegister(GR.getRegClass(ResType)); 19353cdac067SFinn Plummer bool Result = BuildMI(BB, I, I.getDebugLoc(), TII.get(DotOp)) 19363cdac067SFinn Plummer .addDef(Dot) 19373cdac067SFinn Plummer .addUse(GR.getSPIRVTypeID(ResType)) 19383cdac067SFinn Plummer .addUse(I.getOperand(2).getReg()) 19393cdac067SFinn Plummer .addUse(I.getOperand(3).getReg()) 19403cdac067SFinn Plummer .constrainAllUses(TII, TRI, RBI); 19413cdac067SFinn Plummer 1942a93cbd4eSFinn Plummer return Result && BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS)) 19433cdac067SFinn Plummer .addDef(ResVReg) 19443cdac067SFinn Plummer .addUse(GR.getSPIRVTypeID(ResType)) 19453cdac067SFinn Plummer .addUse(Dot) 19463cdac067SFinn Plummer .addUse(I.getOperand(4).getReg()) 19473cdac067SFinn Plummer .constrainAllUses(TII, TRI, RBI); 19483cdac067SFinn Plummer } 19493cdac067SFinn Plummer 19503cdac067SFinn Plummer // Since pre-1.6 SPIRV has no DotProductInput4x8BitPacked implementation, 19513cdac067SFinn Plummer // extract the elements of the packed inputs, multiply them and add the result 19523cdac067SFinn Plummer // to the accumulator. 19533cdac067SFinn Plummer template <bool Signed> 19543cdac067SFinn Plummer bool SPIRVInstructionSelector::selectDot4AddPackedExpansion( 19553cdac067SFinn Plummer Register ResVReg, const SPIRVType *ResType, MachineInstr &I) const { 19563cdac067SFinn Plummer assert(I.getNumOperands() == 5); 19573cdac067SFinn Plummer assert(I.getOperand(2).isReg()); 19583cdac067SFinn Plummer assert(I.getOperand(3).isReg()); 19593cdac067SFinn Plummer assert(I.getOperand(4).isReg()); 19603cdac067SFinn Plummer MachineBasicBlock &BB = *I.getParent(); 19613cdac067SFinn Plummer 1962a93cbd4eSFinn Plummer bool Result = true; 19633cdac067SFinn Plummer 19643cdac067SFinn Plummer // Acc = C 19653cdac067SFinn Plummer Register Acc = I.getOperand(4).getReg(); 19663cdac067SFinn Plummer SPIRVType *EltType = GR.getOrCreateSPIRVIntegerType(8, I, TII); 19673cdac067SFinn Plummer auto ExtractOp = 19683cdac067SFinn Plummer Signed ? SPIRV::OpBitFieldSExtract : SPIRV::OpBitFieldUExtract; 19693cdac067SFinn Plummer 19703cdac067SFinn Plummer // Extract the i8 element, multiply and add it to the accumulator 19713cdac067SFinn Plummer for (unsigned i = 0; i < 4; i++) { 19723cdac067SFinn Plummer // A[i] 19733cdac067SFinn Plummer Register AElt = MRI->createVirtualRegister(&SPIRV::IDRegClass); 1974a93cbd4eSFinn Plummer Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp)) 19753cdac067SFinn Plummer .addDef(AElt) 19763cdac067SFinn Plummer .addUse(GR.getSPIRVTypeID(ResType)) 19773cdac067SFinn Plummer .addUse(I.getOperand(2).getReg()) 19783cdac067SFinn Plummer .addUse(GR.getOrCreateConstInt(i * 8, I, EltType, TII)) 19793cdac067SFinn Plummer .addUse(GR.getOrCreateConstInt(8, I, EltType, TII)) 19803cdac067SFinn Plummer .constrainAllUses(TII, TRI, RBI); 19813cdac067SFinn Plummer 19823cdac067SFinn Plummer // B[i] 19833cdac067SFinn Plummer Register BElt = MRI->createVirtualRegister(&SPIRV::IDRegClass); 1984a93cbd4eSFinn Plummer Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp)) 19853cdac067SFinn Plummer .addDef(BElt) 19863cdac067SFinn Plummer .addUse(GR.getSPIRVTypeID(ResType)) 19873cdac067SFinn Plummer .addUse(I.getOperand(3).getReg()) 19883cdac067SFinn Plummer .addUse(GR.getOrCreateConstInt(i * 8, I, EltType, TII)) 19893cdac067SFinn Plummer .addUse(GR.getOrCreateConstInt(8, I, EltType, TII)) 19903cdac067SFinn Plummer .constrainAllUses(TII, TRI, RBI); 19913cdac067SFinn Plummer 19923cdac067SFinn Plummer // A[i] * B[i] 19933cdac067SFinn Plummer Register Mul = MRI->createVirtualRegister(&SPIRV::IDRegClass); 1994a93cbd4eSFinn Plummer Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIMulS)) 19953cdac067SFinn Plummer .addDef(Mul) 19963cdac067SFinn Plummer .addUse(GR.getSPIRVTypeID(ResType)) 19973cdac067SFinn Plummer .addUse(AElt) 19983cdac067SFinn Plummer .addUse(BElt) 19993cdac067SFinn Plummer .constrainAllUses(TII, TRI, RBI); 20003cdac067SFinn Plummer 20013cdac067SFinn Plummer // Discard 24 highest-bits so that stored i32 register is i8 equivalent 20023cdac067SFinn Plummer Register MaskMul = MRI->createVirtualRegister(&SPIRV::IDRegClass); 2003a93cbd4eSFinn Plummer Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp)) 20043cdac067SFinn Plummer .addDef(MaskMul) 20053cdac067SFinn Plummer .addUse(GR.getSPIRVTypeID(ResType)) 20063cdac067SFinn Plummer .addUse(Mul) 20073cdac067SFinn Plummer .addUse(GR.getOrCreateConstInt(0, I, EltType, TII)) 20083cdac067SFinn Plummer .addUse(GR.getOrCreateConstInt(8, I, EltType, TII)) 20093cdac067SFinn Plummer .constrainAllUses(TII, TRI, RBI); 20103cdac067SFinn Plummer 20113cdac067SFinn Plummer // Acc = Acc + A[i] * B[i] 20123cdac067SFinn Plummer Register Sum = 20133cdac067SFinn Plummer i < 3 ? MRI->createVirtualRegister(&SPIRV::IDRegClass) : ResVReg; 2014a93cbd4eSFinn Plummer Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS)) 20153cdac067SFinn Plummer .addDef(Sum) 20163cdac067SFinn Plummer .addUse(GR.getSPIRVTypeID(ResType)) 20173cdac067SFinn Plummer .addUse(Acc) 20183cdac067SFinn Plummer .addUse(MaskMul) 20193cdac067SFinn Plummer .constrainAllUses(TII, TRI, RBI); 20203cdac067SFinn Plummer 20213cdac067SFinn Plummer Acc = Sum; 20223cdac067SFinn Plummer } 20233cdac067SFinn Plummer 20243cdac067SFinn Plummer return Result; 20253cdac067SFinn Plummer } 20263cdac067SFinn Plummer 20276a38e19cSS. Bharadwaj Yadavalli /// Transform saturate(x) to clamp(x, 0.0f, 1.0f) as SPIRV 20286a38e19cSS. Bharadwaj Yadavalli /// does not have a saturate builtin. 20296a38e19cSS. Bharadwaj Yadavalli bool SPIRVInstructionSelector::selectSaturate(Register ResVReg, 20306a38e19cSS. Bharadwaj Yadavalli const SPIRVType *ResType, 20316a38e19cSS. Bharadwaj Yadavalli MachineInstr &I) const { 20326a38e19cSS. Bharadwaj Yadavalli assert(I.getNumOperands() == 3); 20336a38e19cSS. Bharadwaj Yadavalli assert(I.getOperand(2).isReg()); 20346a38e19cSS. Bharadwaj Yadavalli MachineBasicBlock &BB = *I.getParent(); 20356a38e19cSS. Bharadwaj Yadavalli Register VZero = buildZerosValF(ResType, I); 20366a38e19cSS. Bharadwaj Yadavalli Register VOne = buildOnesValF(ResType, I); 20376a38e19cSS. Bharadwaj Yadavalli 20386a38e19cSS. Bharadwaj Yadavalli return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) 20396a38e19cSS. Bharadwaj Yadavalli .addDef(ResVReg) 20406a38e19cSS. Bharadwaj Yadavalli .addUse(GR.getSPIRVTypeID(ResType)) 20416a38e19cSS. Bharadwaj Yadavalli .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450)) 20426a38e19cSS. Bharadwaj Yadavalli .addImm(GL::FClamp) 20436a38e19cSS. Bharadwaj Yadavalli .addUse(I.getOperand(2).getReg()) 20446a38e19cSS. Bharadwaj Yadavalli .addUse(VZero) 20456a38e19cSS. Bharadwaj Yadavalli .addUse(VOne) 20466a38e19cSS. Bharadwaj Yadavalli .constrainAllUses(TII, TRI, RBI); 20476a38e19cSS. Bharadwaj Yadavalli } 20486a38e19cSS. Bharadwaj Yadavalli 2049a9a5a18aSTim Gymnich bool SPIRVInstructionSelector::selectSign(Register ResVReg, 2050a9a5a18aSTim Gymnich const SPIRVType *ResType, 2051a9a5a18aSTim Gymnich MachineInstr &I) const { 2052a9a5a18aSTim Gymnich assert(I.getNumOperands() == 3); 2053a9a5a18aSTim Gymnich assert(I.getOperand(2).isReg()); 2054a9a5a18aSTim Gymnich MachineBasicBlock &BB = *I.getParent(); 2055a9a5a18aSTim Gymnich Register InputRegister = I.getOperand(2).getReg(); 2056a9a5a18aSTim Gymnich SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister); 2057a9a5a18aSTim Gymnich auto &DL = I.getDebugLoc(); 2058a9a5a18aSTim Gymnich 2059a9a5a18aSTim Gymnich if (!InputType) 2060a9a5a18aSTim Gymnich report_fatal_error("Input Type could not be determined."); 2061a9a5a18aSTim Gymnich 2062a9a5a18aSTim Gymnich bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat); 2063a9a5a18aSTim Gymnich 2064a9a5a18aSTim Gymnich unsigned SignBitWidth = GR.getScalarOrVectorBitWidth(InputType); 2065a9a5a18aSTim Gymnich unsigned ResBitWidth = GR.getScalarOrVectorBitWidth(ResType); 2066a9a5a18aSTim Gymnich 2067a9a5a18aSTim Gymnich bool NeedsConversion = IsFloatTy || SignBitWidth != ResBitWidth; 2068a9a5a18aSTim Gymnich 2069a9a5a18aSTim Gymnich auto SignOpcode = IsFloatTy ? GL::FSign : GL::SSign; 2070a9a5a18aSTim Gymnich Register SignReg = NeedsConversion 2071a9a5a18aSTim Gymnich ? MRI->createVirtualRegister(&SPIRV::IDRegClass) 2072a9a5a18aSTim Gymnich : ResVReg; 2073a9a5a18aSTim Gymnich 2074a9a5a18aSTim Gymnich bool Result = 2075a9a5a18aSTim Gymnich BuildMI(BB, I, DL, TII.get(SPIRV::OpExtInst)) 2076a9a5a18aSTim Gymnich .addDef(SignReg) 2077a9a5a18aSTim Gymnich .addUse(GR.getSPIRVTypeID(InputType)) 2078a9a5a18aSTim Gymnich .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450)) 2079a9a5a18aSTim Gymnich .addImm(SignOpcode) 2080a9a5a18aSTim Gymnich .addUse(InputRegister) 2081a9a5a18aSTim Gymnich .constrainAllUses(TII, TRI, RBI); 2082a9a5a18aSTim Gymnich 2083a9a5a18aSTim Gymnich if (NeedsConversion) { 2084a9a5a18aSTim Gymnich auto ConvertOpcode = IsFloatTy ? SPIRV::OpConvertFToS : SPIRV::OpSConvert; 2085a93cbd4eSFinn Plummer Result &= BuildMI(*I.getParent(), I, DL, TII.get(ConvertOpcode)) 2086a9a5a18aSTim Gymnich .addDef(ResVReg) 2087a9a5a18aSTim Gymnich .addUse(GR.getSPIRVTypeID(ResType)) 2088a9a5a18aSTim Gymnich .addUse(SignReg) 2089a9a5a18aSTim Gymnich .constrainAllUses(TII, TRI, RBI); 2090a9a5a18aSTim Gymnich } 2091a9a5a18aSTim Gymnich 2092a9a5a18aSTim Gymnich return Result; 2093a9a5a18aSTim Gymnich } 2094a9a5a18aSTim Gymnich 20956735c5ebSAshley Coleman bool SPIRVInstructionSelector::selectWaveOpInst(Register ResVReg, 20966735c5ebSAshley Coleman const SPIRVType *ResType, 20976735c5ebSAshley Coleman MachineInstr &I, 20986735c5ebSAshley Coleman unsigned Opcode) const { 20996735c5ebSAshley Coleman MachineBasicBlock &BB = *I.getParent(); 21006735c5ebSAshley Coleman SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); 21016735c5ebSAshley Coleman 21026735c5ebSAshley Coleman auto BMI = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) 21036735c5ebSAshley Coleman .addDef(ResVReg) 21046735c5ebSAshley Coleman .addUse(GR.getSPIRVTypeID(ResType)) 21056735c5ebSAshley Coleman .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, 21066735c5ebSAshley Coleman IntTy, TII)); 21076735c5ebSAshley Coleman 21086735c5ebSAshley Coleman for (unsigned J = 2; J < I.getNumOperands(); J++) { 21096735c5ebSAshley Coleman BMI.addUse(I.getOperand(J).getReg()); 21106735c5ebSAshley Coleman } 21116735c5ebSAshley Coleman 21126735c5ebSAshley Coleman return BMI.constrainAllUses(TII, TRI, RBI); 21136735c5ebSAshley Coleman } 21146735c5ebSAshley Coleman 2115e520b283SFinn Plummer bool SPIRVInstructionSelector::selectWaveActiveCountBits( 2116e520b283SFinn Plummer Register ResVReg, const SPIRVType *ResType, MachineInstr &I) const { 2117e520b283SFinn Plummer 2118e520b283SFinn Plummer SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); 2119e520b283SFinn Plummer SPIRVType *BallotType = GR.getOrCreateSPIRVVectorType(IntTy, 4, I, TII); 2120e520b283SFinn Plummer Register BallotReg = MRI->createVirtualRegister(GR.getRegClass(BallotType)); 21216735c5ebSAshley Coleman bool Result = selectWaveOpInst(BallotReg, BallotType, I, 21226735c5ebSAshley Coleman SPIRV::OpGroupNonUniformBallot); 2123e520b283SFinn Plummer 21246735c5ebSAshley Coleman MachineBasicBlock &BB = *I.getParent(); 2125e520b283SFinn Plummer Result &= 2126e520b283SFinn Plummer BuildMI(BB, I, I.getDebugLoc(), 2127e520b283SFinn Plummer TII.get(SPIRV::OpGroupNonUniformBallotBitCount)) 2128e520b283SFinn Plummer .addDef(ResVReg) 2129e520b283SFinn Plummer .addUse(GR.getSPIRVTypeID(ResType)) 2130e520b283SFinn Plummer .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII)) 2131e520b283SFinn Plummer .addImm(SPIRV::GroupOperation::Reduce) 2132e520b283SFinn Plummer .addUse(BallotReg) 2133e520b283SFinn Plummer .constrainAllUses(TII, TRI, RBI); 2134e520b283SFinn Plummer 2135e520b283SFinn Plummer return Result; 2136e520b283SFinn Plummer } 2137e520b283SFinn Plummer 2138*aab25f20SAdam Yang bool SPIRVInstructionSelector::selectWaveReduceMax(Register ResVReg, 2139*aab25f20SAdam Yang const SPIRVType *ResType, 2140*aab25f20SAdam Yang MachineInstr &I, 2141*aab25f20SAdam Yang bool IsUnsigned) const { 2142*aab25f20SAdam Yang assert(I.getNumOperands() == 3); 2143*aab25f20SAdam Yang assert(I.getOperand(2).isReg()); 2144*aab25f20SAdam Yang MachineBasicBlock &BB = *I.getParent(); 2145*aab25f20SAdam Yang Register InputRegister = I.getOperand(2).getReg(); 2146*aab25f20SAdam Yang SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister); 2147*aab25f20SAdam Yang 2148*aab25f20SAdam Yang if (!InputType) 2149*aab25f20SAdam Yang report_fatal_error("Input Type could not be determined."); 2150*aab25f20SAdam Yang 2151*aab25f20SAdam Yang SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); 2152*aab25f20SAdam Yang // Retreive the operation to use based on input type 2153*aab25f20SAdam Yang bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat); 2154*aab25f20SAdam Yang auto IntegerOpcodeType = 2155*aab25f20SAdam Yang IsUnsigned ? SPIRV::OpGroupNonUniformUMax : SPIRV::OpGroupNonUniformSMax; 2156*aab25f20SAdam Yang auto Opcode = IsFloatTy ? SPIRV::OpGroupNonUniformFMax : IntegerOpcodeType; 2157*aab25f20SAdam Yang return BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) 2158*aab25f20SAdam Yang .addDef(ResVReg) 2159*aab25f20SAdam Yang .addUse(GR.getSPIRVTypeID(ResType)) 2160*aab25f20SAdam Yang .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII)) 2161*aab25f20SAdam Yang .addImm(SPIRV::GroupOperation::Reduce) 2162*aab25f20SAdam Yang .addUse(I.getOperand(2).getReg()) 2163*aab25f20SAdam Yang .constrainAllUses(TII, TRI, RBI); 2164*aab25f20SAdam Yang } 2165*aab25f20SAdam Yang 21664446a984SAdam Yang bool SPIRVInstructionSelector::selectWaveReduceSum(Register ResVReg, 21674446a984SAdam Yang const SPIRVType *ResType, 21684446a984SAdam Yang MachineInstr &I) const { 21694446a984SAdam Yang assert(I.getNumOperands() == 3); 21704446a984SAdam Yang assert(I.getOperand(2).isReg()); 21714446a984SAdam Yang MachineBasicBlock &BB = *I.getParent(); 21724446a984SAdam Yang Register InputRegister = I.getOperand(2).getReg(); 21734446a984SAdam Yang SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister); 21744446a984SAdam Yang 21754446a984SAdam Yang if (!InputType) 21764446a984SAdam Yang report_fatal_error("Input Type could not be determined."); 21774446a984SAdam Yang 21784446a984SAdam Yang SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32, I, TII); 21794446a984SAdam Yang // Retreive the operation to use based on input type 21804446a984SAdam Yang bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat); 21814446a984SAdam Yang auto Opcode = 21824446a984SAdam Yang IsFloatTy ? SPIRV::OpGroupNonUniformFAdd : SPIRV::OpGroupNonUniformIAdd; 21834446a984SAdam Yang return BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) 21844446a984SAdam Yang .addDef(ResVReg) 21854446a984SAdam Yang .addUse(GR.getSPIRVTypeID(ResType)) 21864446a984SAdam Yang .addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII)) 21874446a984SAdam Yang .addImm(SPIRV::GroupOperation::Reduce) 21884446a984SAdam Yang .addUse(I.getOperand(2).getReg()); 21894446a984SAdam Yang } 21904446a984SAdam Yang 2191eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg, 2192eab7d363SIlia Diachkov const SPIRVType *ResType, 2193eab7d363SIlia Diachkov MachineInstr &I) const { 2194eab7d363SIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 2195eab7d363SIlia Diachkov return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse)) 2196eab7d363SIlia Diachkov .addDef(ResVReg) 2197eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 2198eab7d363SIlia Diachkov .addUse(I.getOperand(1).getReg()) 2199eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 2200eab7d363SIlia Diachkov } 2201eab7d363SIlia Diachkov 22029796b0e9SVyacheslav Levytskyy bool SPIRVInstructionSelector::selectFreeze(Register ResVReg, 22039796b0e9SVyacheslav Levytskyy const SPIRVType *ResType, 22049796b0e9SVyacheslav Levytskyy MachineInstr &I) const { 22059796b0e9SVyacheslav Levytskyy // There is no way to implement `freeze` correctly without support on SPIR-V 22069796b0e9SVyacheslav Levytskyy // standard side, but we may at least address a simple (static) case when 22079796b0e9SVyacheslav Levytskyy // undef/poison value presence is obvious. The main benefit of even 22089796b0e9SVyacheslav Levytskyy // incomplete `freeze` support is preventing of translation from crashing due 22099796b0e9SVyacheslav Levytskyy // to lack of support on legalization and instruction selection steps. 22109796b0e9SVyacheslav Levytskyy if (!I.getOperand(0).isReg() || !I.getOperand(1).isReg()) 22119796b0e9SVyacheslav Levytskyy return false; 22129796b0e9SVyacheslav Levytskyy Register OpReg = I.getOperand(1).getReg(); 22139796b0e9SVyacheslav Levytskyy if (MachineInstr *Def = MRI->getVRegDef(OpReg)) { 22149796b0e9SVyacheslav Levytskyy Register Reg; 22159796b0e9SVyacheslav Levytskyy switch (Def->getOpcode()) { 22169796b0e9SVyacheslav Levytskyy case SPIRV::ASSIGN_TYPE: 22179796b0e9SVyacheslav Levytskyy if (MachineInstr *AssignToDef = 22189796b0e9SVyacheslav Levytskyy MRI->getVRegDef(Def->getOperand(1).getReg())) { 22199796b0e9SVyacheslav Levytskyy if (AssignToDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF) 22209796b0e9SVyacheslav Levytskyy Reg = Def->getOperand(2).getReg(); 22219796b0e9SVyacheslav Levytskyy } 22229796b0e9SVyacheslav Levytskyy break; 22239796b0e9SVyacheslav Levytskyy case SPIRV::OpUndef: 22249796b0e9SVyacheslav Levytskyy Reg = Def->getOperand(1).getReg(); 22259796b0e9SVyacheslav Levytskyy break; 22269796b0e9SVyacheslav Levytskyy } 22279796b0e9SVyacheslav Levytskyy unsigned DestOpCode; 22289796b0e9SVyacheslav Levytskyy if (Reg.isValid()) { 22299796b0e9SVyacheslav Levytskyy DestOpCode = SPIRV::OpConstantNull; 22309796b0e9SVyacheslav Levytskyy } else { 22319796b0e9SVyacheslav Levytskyy DestOpCode = TargetOpcode::COPY; 22329796b0e9SVyacheslav Levytskyy Reg = OpReg; 22339796b0e9SVyacheslav Levytskyy } 22349796b0e9SVyacheslav Levytskyy return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(DestOpCode)) 22359796b0e9SVyacheslav Levytskyy .addDef(I.getOperand(0).getReg()) 22369796b0e9SVyacheslav Levytskyy .addUse(Reg) 22379796b0e9SVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 22389796b0e9SVyacheslav Levytskyy } 22399796b0e9SVyacheslav Levytskyy return false; 22409796b0e9SVyacheslav Levytskyy } 22419796b0e9SVyacheslav Levytskyy 2242c2483ed5SVyacheslav Levytskyy static unsigned getArrayComponentCount(MachineRegisterInfo *MRI, 2243c2483ed5SVyacheslav Levytskyy const SPIRVType *ResType) { 2244c2483ed5SVyacheslav Levytskyy Register OpReg = ResType->getOperand(2).getReg(); 2245c2483ed5SVyacheslav Levytskyy SPIRVType *OpDef = MRI->getVRegDef(OpReg); 2246c2483ed5SVyacheslav Levytskyy if (!OpDef) 2247c2483ed5SVyacheslav Levytskyy return 0; 2248c2483ed5SVyacheslav Levytskyy if (OpDef->getOpcode() == SPIRV::ASSIGN_TYPE && 2249c2483ed5SVyacheslav Levytskyy OpDef->getOperand(1).isReg()) { 2250c2483ed5SVyacheslav Levytskyy if (SPIRVType *RefDef = MRI->getVRegDef(OpDef->getOperand(1).getReg())) 2251c2483ed5SVyacheslav Levytskyy OpDef = RefDef; 2252c2483ed5SVyacheslav Levytskyy } 2253c2483ed5SVyacheslav Levytskyy unsigned N = OpDef->getOpcode() == TargetOpcode::G_CONSTANT 2254c2483ed5SVyacheslav Levytskyy ? OpDef->getOperand(1).getCImm()->getValue().getZExtValue() 2255c2483ed5SVyacheslav Levytskyy : 0; 2256c2483ed5SVyacheslav Levytskyy return N; 2257c2483ed5SVyacheslav Levytskyy } 2258c2483ed5SVyacheslav Levytskyy 2259b0d03cccSVyacheslav Levytskyy // Return true if the type represents a constant register 2260b0efde6dSVyacheslav Levytskyy static bool isConstReg(MachineRegisterInfo *MRI, SPIRVType *OpDef, 2261b0efde6dSVyacheslav Levytskyy SmallPtrSet<SPIRVType *, 4> &Visited) { 2262b0d03cccSVyacheslav Levytskyy if (OpDef->getOpcode() == SPIRV::ASSIGN_TYPE && 2263b0d03cccSVyacheslav Levytskyy OpDef->getOperand(1).isReg()) { 2264b0d03cccSVyacheslav Levytskyy if (SPIRVType *RefDef = MRI->getVRegDef(OpDef->getOperand(1).getReg())) 2265b0d03cccSVyacheslav Levytskyy OpDef = RefDef; 2266b0d03cccSVyacheslav Levytskyy } 2267b0efde6dSVyacheslav Levytskyy 2268b0efde6dSVyacheslav Levytskyy if (Visited.contains(OpDef)) 2269b0efde6dSVyacheslav Levytskyy return true; 2270b0efde6dSVyacheslav Levytskyy Visited.insert(OpDef); 2271b0efde6dSVyacheslav Levytskyy 2272b0efde6dSVyacheslav Levytskyy unsigned Opcode = OpDef->getOpcode(); 2273b0efde6dSVyacheslav Levytskyy switch (Opcode) { 2274b0efde6dSVyacheslav Levytskyy case TargetOpcode::G_CONSTANT: 2275b0efde6dSVyacheslav Levytskyy case TargetOpcode::G_FCONSTANT: 2276b0efde6dSVyacheslav Levytskyy return true; 2277b0efde6dSVyacheslav Levytskyy case TargetOpcode::G_INTRINSIC: 2278b0efde6dSVyacheslav Levytskyy case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: 2279b0efde6dSVyacheslav Levytskyy case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 2280b0efde6dSVyacheslav Levytskyy return cast<GIntrinsic>(*OpDef).getIntrinsicID() == 2281b0efde6dSVyacheslav Levytskyy Intrinsic::spv_const_composite; 2282b0efde6dSVyacheslav Levytskyy case TargetOpcode::G_BUILD_VECTOR: 2283b0efde6dSVyacheslav Levytskyy case TargetOpcode::G_SPLAT_VECTOR: { 2284b0efde6dSVyacheslav Levytskyy for (unsigned i = OpDef->getNumExplicitDefs(); i < OpDef->getNumOperands(); 2285b0efde6dSVyacheslav Levytskyy i++) { 2286b0efde6dSVyacheslav Levytskyy SPIRVType *OpNestedDef = 2287b0efde6dSVyacheslav Levytskyy OpDef->getOperand(i).isReg() 2288b0efde6dSVyacheslav Levytskyy ? MRI->getVRegDef(OpDef->getOperand(i).getReg()) 2289b0efde6dSVyacheslav Levytskyy : nullptr; 2290b0efde6dSVyacheslav Levytskyy if (OpNestedDef && !isConstReg(MRI, OpNestedDef, Visited)) 2291b0efde6dSVyacheslav Levytskyy return false; 2292b0efde6dSVyacheslav Levytskyy } 2293b0efde6dSVyacheslav Levytskyy return true; 2294b0efde6dSVyacheslav Levytskyy } 2295b0efde6dSVyacheslav Levytskyy } 2296b0efde6dSVyacheslav Levytskyy return false; 2297b0d03cccSVyacheslav Levytskyy } 2298b0d03cccSVyacheslav Levytskyy 2299b0d03cccSVyacheslav Levytskyy // Return true if the virtual register represents a constant 2300b0d03cccSVyacheslav Levytskyy static bool isConstReg(MachineRegisterInfo *MRI, Register OpReg) { 2301b0efde6dSVyacheslav Levytskyy SmallPtrSet<SPIRVType *, 4> Visited; 2302b0d03cccSVyacheslav Levytskyy if (SPIRVType *OpDef = MRI->getVRegDef(OpReg)) 2303b0efde6dSVyacheslav Levytskyy return isConstReg(MRI, OpDef, Visited); 2304b0d03cccSVyacheslav Levytskyy return false; 2305b0d03cccSVyacheslav Levytskyy } 2306b0d03cccSVyacheslav Levytskyy 23072fc7a727SVyacheslav Levytskyy bool SPIRVInstructionSelector::selectBuildVector(Register ResVReg, 23082fc7a727SVyacheslav Levytskyy const SPIRVType *ResType, 23092fc7a727SVyacheslav Levytskyy MachineInstr &I) const { 23102fc7a727SVyacheslav Levytskyy unsigned N = 0; 23112fc7a727SVyacheslav Levytskyy if (ResType->getOpcode() == SPIRV::OpTypeVector) 23122fc7a727SVyacheslav Levytskyy N = GR.getScalarOrVectorComponentCount(ResType); 23132fc7a727SVyacheslav Levytskyy else if (ResType->getOpcode() == SPIRV::OpTypeArray) 23142fc7a727SVyacheslav Levytskyy N = getArrayComponentCount(MRI, ResType); 23152fc7a727SVyacheslav Levytskyy else 23162fc7a727SVyacheslav Levytskyy report_fatal_error("Cannot select G_BUILD_VECTOR with a non-vector result"); 23172fc7a727SVyacheslav Levytskyy if (I.getNumExplicitOperands() - I.getNumExplicitDefs() != N) 23182fc7a727SVyacheslav Levytskyy report_fatal_error("G_BUILD_VECTOR and the result type are inconsistent"); 23192fc7a727SVyacheslav Levytskyy 23202fc7a727SVyacheslav Levytskyy // check if we may construct a constant vector 23212fc7a727SVyacheslav Levytskyy bool IsConst = true; 23222fc7a727SVyacheslav Levytskyy for (unsigned i = I.getNumExplicitDefs(); 23232fc7a727SVyacheslav Levytskyy i < I.getNumExplicitOperands() && IsConst; ++i) 23242fc7a727SVyacheslav Levytskyy if (!isConstReg(MRI, I.getOperand(i).getReg())) 23252fc7a727SVyacheslav Levytskyy IsConst = false; 23262fc7a727SVyacheslav Levytskyy 23272fc7a727SVyacheslav Levytskyy if (!IsConst && N < 2) 23282fc7a727SVyacheslav Levytskyy report_fatal_error( 23292fc7a727SVyacheslav Levytskyy "There must be at least two constituent operands in a vector"); 23302fc7a727SVyacheslav Levytskyy 233142633cf2SVyacheslav Levytskyy MRI->setRegClass(ResVReg, GR.getRegClass(ResType)); 23322fc7a727SVyacheslav Levytskyy auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), 23332fc7a727SVyacheslav Levytskyy TII.get(IsConst ? SPIRV::OpConstantComposite 23342fc7a727SVyacheslav Levytskyy : SPIRV::OpCompositeConstruct)) 23352fc7a727SVyacheslav Levytskyy .addDef(ResVReg) 23362fc7a727SVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(ResType)); 23372fc7a727SVyacheslav Levytskyy for (unsigned i = I.getNumExplicitDefs(); i < I.getNumExplicitOperands(); ++i) 23382fc7a727SVyacheslav Levytskyy MIB.addUse(I.getOperand(i).getReg()); 23392fc7a727SVyacheslav Levytskyy return MIB.constrainAllUses(TII, TRI, RBI); 23402fc7a727SVyacheslav Levytskyy } 23412fc7a727SVyacheslav Levytskyy 23420a443f13SVyacheslav Levytskyy bool SPIRVInstructionSelector::selectSplatVector(Register ResVReg, 23430a443f13SVyacheslav Levytskyy const SPIRVType *ResType, 23440a443f13SVyacheslav Levytskyy MachineInstr &I) const { 2345c2483ed5SVyacheslav Levytskyy unsigned N = 0; 2346c2483ed5SVyacheslav Levytskyy if (ResType->getOpcode() == SPIRV::OpTypeVector) 2347c2483ed5SVyacheslav Levytskyy N = GR.getScalarOrVectorComponentCount(ResType); 2348c2483ed5SVyacheslav Levytskyy else if (ResType->getOpcode() == SPIRV::OpTypeArray) 2349c2483ed5SVyacheslav Levytskyy N = getArrayComponentCount(MRI, ResType); 2350c2483ed5SVyacheslav Levytskyy else 23510a443f13SVyacheslav Levytskyy report_fatal_error("Cannot select G_SPLAT_VECTOR with a non-vector result"); 2352c2483ed5SVyacheslav Levytskyy 23530a443f13SVyacheslav Levytskyy unsigned OpIdx = I.getNumExplicitDefs(); 23540a443f13SVyacheslav Levytskyy if (!I.getOperand(OpIdx).isReg()) 23550a443f13SVyacheslav Levytskyy report_fatal_error("Unexpected argument in G_SPLAT_VECTOR"); 23560a443f13SVyacheslav Levytskyy 23570a443f13SVyacheslav Levytskyy // check if we may construct a constant vector 23580a443f13SVyacheslav Levytskyy Register OpReg = I.getOperand(OpIdx).getReg(); 2359b0d03cccSVyacheslav Levytskyy bool IsConst = isConstReg(MRI, OpReg); 23600a443f13SVyacheslav Levytskyy 23610a443f13SVyacheslav Levytskyy if (!IsConst && N < 2) 23620a443f13SVyacheslav Levytskyy report_fatal_error( 23630a443f13SVyacheslav Levytskyy "There must be at least two constituent operands in a vector"); 23640a443f13SVyacheslav Levytskyy 236542633cf2SVyacheslav Levytskyy MRI->setRegClass(ResVReg, GR.getRegClass(ResType)); 23660a443f13SVyacheslav Levytskyy auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), 23670a443f13SVyacheslav Levytskyy TII.get(IsConst ? SPIRV::OpConstantComposite 23680a443f13SVyacheslav Levytskyy : SPIRV::OpCompositeConstruct)) 23690a443f13SVyacheslav Levytskyy .addDef(ResVReg) 23700a443f13SVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(ResType)); 23710a443f13SVyacheslav Levytskyy for (unsigned i = 0; i < N; ++i) 23720a443f13SVyacheslav Levytskyy MIB.addUse(OpReg); 23730a443f13SVyacheslav Levytskyy return MIB.constrainAllUses(TII, TRI, RBI); 23740a443f13SVyacheslav Levytskyy } 23750a443f13SVyacheslav Levytskyy 2376bc6c0681Sjoaosaffran bool SPIRVInstructionSelector::selectDiscard(Register ResVReg, 2377bc6c0681Sjoaosaffran const SPIRVType *ResType, 2378bc6c0681Sjoaosaffran MachineInstr &I) const { 2379bc6c0681Sjoaosaffran 2380bc6c0681Sjoaosaffran unsigned Opcode; 2381bc6c0681Sjoaosaffran 2382bc6c0681Sjoaosaffran if (STI.canUseExtension( 2383bc6c0681Sjoaosaffran SPIRV::Extension::SPV_EXT_demote_to_helper_invocation) || 2384bc6c0681Sjoaosaffran STI.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6))) { 2385bc6c0681Sjoaosaffran Opcode = SPIRV::OpDemoteToHelperInvocation; 2386bc6c0681Sjoaosaffran } else { 2387bc6c0681Sjoaosaffran Opcode = SPIRV::OpKill; 2388bc6c0681Sjoaosaffran // OpKill must be the last operation of any basic block. 23893ed2a813SVyacheslav Levytskyy if (MachineInstr *NextI = I.getNextNode()) { 23903ed2a813SVyacheslav Levytskyy GR.invalidateMachineInstr(NextI); 2391bc6c0681Sjoaosaffran NextI->removeFromParent(); 2392bc6c0681Sjoaosaffran } 23933ed2a813SVyacheslav Levytskyy } 2394bc6c0681Sjoaosaffran 2395bc6c0681Sjoaosaffran MachineBasicBlock &BB = *I.getParent(); 2396bc6c0681Sjoaosaffran return BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) 2397bc6c0681Sjoaosaffran .constrainAllUses(TII, TRI, RBI); 2398bc6c0681Sjoaosaffran } 2399bc6c0681Sjoaosaffran 2400eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectCmp(Register ResVReg, 2401eab7d363SIlia Diachkov const SPIRVType *ResType, 2402eab7d363SIlia Diachkov unsigned CmpOpc, 2403eab7d363SIlia Diachkov MachineInstr &I) const { 2404eab7d363SIlia Diachkov Register Cmp0 = I.getOperand(2).getReg(); 2405eab7d363SIlia Diachkov Register Cmp1 = I.getOperand(3).getReg(); 2406eab7d363SIlia Diachkov assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() == 2407eab7d363SIlia Diachkov GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() && 2408eab7d363SIlia Diachkov "CMP operands should have the same type"); 2409eab7d363SIlia Diachkov return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(CmpOpc)) 2410eab7d363SIlia Diachkov .addDef(ResVReg) 2411eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 2412eab7d363SIlia Diachkov .addUse(Cmp0) 2413eab7d363SIlia Diachkov .addUse(Cmp1) 2414eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 2415eab7d363SIlia Diachkov } 2416eab7d363SIlia Diachkov 2417eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectICmp(Register ResVReg, 2418eab7d363SIlia Diachkov const SPIRVType *ResType, 2419eab7d363SIlia Diachkov MachineInstr &I) const { 2420eab7d363SIlia Diachkov auto Pred = I.getOperand(1).getPredicate(); 2421eab7d363SIlia Diachkov unsigned CmpOpc; 2422eab7d363SIlia Diachkov 2423eab7d363SIlia Diachkov Register CmpOperand = I.getOperand(2).getReg(); 2424eab7d363SIlia Diachkov if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer)) 2425eab7d363SIlia Diachkov CmpOpc = getPtrCmpOpcode(Pred); 2426eab7d363SIlia Diachkov else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool)) 2427eab7d363SIlia Diachkov CmpOpc = getBoolCmpOpcode(Pred); 2428eab7d363SIlia Diachkov else 2429eab7d363SIlia Diachkov CmpOpc = getICmpOpcode(Pred); 2430eab7d363SIlia Diachkov return selectCmp(ResVReg, ResType, CmpOpc, I); 2431eab7d363SIlia Diachkov } 2432eab7d363SIlia Diachkov 243367d3ef74SVyacheslav Levytskyy void SPIRVInstructionSelector::renderFImm64(MachineInstrBuilder &MIB, 2434eab7d363SIlia Diachkov const MachineInstr &I, 2435eab7d363SIlia Diachkov int OpIdx) const { 2436eab7d363SIlia Diachkov assert(I.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 && 2437eab7d363SIlia Diachkov "Expected G_FCONSTANT"); 2438eab7d363SIlia Diachkov const ConstantFP *FPImm = I.getOperand(1).getFPImm(); 2439eab7d363SIlia Diachkov addNumImm(FPImm->getValueAPF().bitcastToAPInt(), MIB); 2440eab7d363SIlia Diachkov } 2441eab7d363SIlia Diachkov 2442eab7d363SIlia Diachkov void SPIRVInstructionSelector::renderImm32(MachineInstrBuilder &MIB, 2443eab7d363SIlia Diachkov const MachineInstr &I, 2444eab7d363SIlia Diachkov int OpIdx) const { 2445eab7d363SIlia Diachkov assert(I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 && 2446eab7d363SIlia Diachkov "Expected G_CONSTANT"); 2447eab7d363SIlia Diachkov addNumImm(I.getOperand(1).getCImm()->getValue(), MIB); 2448eab7d363SIlia Diachkov } 2449eab7d363SIlia Diachkov 2450a93cbd4eSFinn Plummer std::pair<Register, bool> 2451eab7d363SIlia Diachkov SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I, 2452eab7d363SIlia Diachkov const SPIRVType *ResType) const { 2453fa2a7a25SAleksandr Bezzubikov Type *LLVMTy = IntegerType::get(GR.CurMF->getFunction().getContext(), 32); 2454eab7d363SIlia Diachkov const SPIRVType *SpvI32Ty = 2455eab7d363SIlia Diachkov ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32, I, TII); 2456fa2a7a25SAleksandr Bezzubikov // Find a constant in DT or build a new one. 2457fa2a7a25SAleksandr Bezzubikov auto ConstInt = ConstantInt::get(LLVMTy, Val); 2458fa2a7a25SAleksandr Bezzubikov Register NewReg = GR.find(ConstInt, GR.CurMF); 2459a93cbd4eSFinn Plummer bool Result = true; 2460fa2a7a25SAleksandr Bezzubikov if (!NewReg.isValid()) { 246167d3ef74SVyacheslav Levytskyy NewReg = MRI->createGenericVirtualRegister(LLT::scalar(64)); 2462fa2a7a25SAleksandr Bezzubikov GR.add(ConstInt, GR.CurMF, NewReg); 2463eab7d363SIlia Diachkov MachineInstr *MI; 2464eab7d363SIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 2465eab7d363SIlia Diachkov if (Val == 0) { 2466eab7d363SIlia Diachkov MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull)) 2467eab7d363SIlia Diachkov .addDef(NewReg) 2468eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(SpvI32Ty)); 2469eab7d363SIlia Diachkov } else { 2470eab7d363SIlia Diachkov MI = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI)) 2471eab7d363SIlia Diachkov .addDef(NewReg) 2472eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(SpvI32Ty)) 2473eab7d363SIlia Diachkov .addImm(APInt(32, Val).getZExtValue()); 2474eab7d363SIlia Diachkov } 2475a93cbd4eSFinn Plummer Result &= constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); 2476fa2a7a25SAleksandr Bezzubikov } 2477a93cbd4eSFinn Plummer return {NewReg, Result}; 2478eab7d363SIlia Diachkov } 2479eab7d363SIlia Diachkov 2480eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectFCmp(Register ResVReg, 2481eab7d363SIlia Diachkov const SPIRVType *ResType, 2482eab7d363SIlia Diachkov MachineInstr &I) const { 2483eab7d363SIlia Diachkov unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate()); 2484eab7d363SIlia Diachkov return selectCmp(ResVReg, ResType, CmpOp, I); 2485eab7d363SIlia Diachkov } 2486eab7d363SIlia Diachkov 2487eab7d363SIlia Diachkov Register SPIRVInstructionSelector::buildZerosVal(const SPIRVType *ResType, 2488eab7d363SIlia Diachkov MachineInstr &I) const { 248905093e24SFarzon Lotfi // OpenCL uses nulls for Zero. In HLSL we don't use null constants. 249005093e24SFarzon Lotfi bool ZeroAsNull = STI.isOpenCLEnv(); 2491b8e1544bSIlia Diachkov if (ResType->getOpcode() == SPIRV::OpTypeVector) 249205093e24SFarzon Lotfi return GR.getOrCreateConstVector(0UL, I, ResType, TII, ZeroAsNull); 249305093e24SFarzon Lotfi return GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull); 249405093e24SFarzon Lotfi } 249505093e24SFarzon Lotfi 249605093e24SFarzon Lotfi Register SPIRVInstructionSelector::buildZerosValF(const SPIRVType *ResType, 249705093e24SFarzon Lotfi MachineInstr &I) const { 249805093e24SFarzon Lotfi // OpenCL uses nulls for Zero. In HLSL we don't use null constants. 249905093e24SFarzon Lotfi bool ZeroAsNull = STI.isOpenCLEnv(); 250005093e24SFarzon Lotfi APFloat VZero = getZeroFP(GR.getTypeForSPIRVType(ResType)); 250105093e24SFarzon Lotfi if (ResType->getOpcode() == SPIRV::OpTypeVector) 250205093e24SFarzon Lotfi return GR.getOrCreateConstVector(VZero, I, ResType, TII, ZeroAsNull); 250305093e24SFarzon Lotfi return GR.getOrCreateConstFP(VZero, I, ResType, TII, ZeroAsNull); 2504eab7d363SIlia Diachkov } 2505eab7d363SIlia Diachkov 25066a38e19cSS. Bharadwaj Yadavalli Register SPIRVInstructionSelector::buildOnesValF(const SPIRVType *ResType, 25076a38e19cSS. Bharadwaj Yadavalli MachineInstr &I) const { 25086a38e19cSS. Bharadwaj Yadavalli // OpenCL uses nulls for Zero. In HLSL we don't use null constants. 25096a38e19cSS. Bharadwaj Yadavalli bool ZeroAsNull = STI.isOpenCLEnv(); 25106a38e19cSS. Bharadwaj Yadavalli APFloat VOne = getOneFP(GR.getTypeForSPIRVType(ResType)); 25116a38e19cSS. Bharadwaj Yadavalli if (ResType->getOpcode() == SPIRV::OpTypeVector) 25126a38e19cSS. Bharadwaj Yadavalli return GR.getOrCreateConstVector(VOne, I, ResType, TII, ZeroAsNull); 25136a38e19cSS. Bharadwaj Yadavalli return GR.getOrCreateConstFP(VOne, I, ResType, TII, ZeroAsNull); 25146a38e19cSS. Bharadwaj Yadavalli } 25156a38e19cSS. Bharadwaj Yadavalli 2516eab7d363SIlia Diachkov Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes, 2517eab7d363SIlia Diachkov const SPIRVType *ResType, 2518eab7d363SIlia Diachkov MachineInstr &I) const { 2519eab7d363SIlia Diachkov unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType); 2520147ff1b4SMichal Paszkowski APInt One = 2521147ff1b4SMichal Paszkowski AllOnes ? APInt::getAllOnes(BitWidth) : APInt::getOneBitSet(BitWidth, 0); 2522b8e1544bSIlia Diachkov if (ResType->getOpcode() == SPIRV::OpTypeVector) 252305093e24SFarzon Lotfi return GR.getOrCreateConstVector(One.getZExtValue(), I, ResType, TII); 2524b8e1544bSIlia Diachkov return GR.getOrCreateConstInt(One.getZExtValue(), I, ResType, TII); 2525eab7d363SIlia Diachkov } 2526eab7d363SIlia Diachkov 2527eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectSelect(Register ResVReg, 2528eab7d363SIlia Diachkov const SPIRVType *ResType, 2529eab7d363SIlia Diachkov MachineInstr &I, 2530eab7d363SIlia Diachkov bool IsSigned) const { 2531eab7d363SIlia Diachkov // To extend a bool, we need to use OpSelect between constants. 2532eab7d363SIlia Diachkov Register ZeroReg = buildZerosVal(ResType, I); 2533eab7d363SIlia Diachkov Register OneReg = buildOnesVal(IsSigned, ResType, I); 2534eab7d363SIlia Diachkov bool IsScalarBool = 2535eab7d363SIlia Diachkov GR.isScalarOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool); 2536eab7d363SIlia Diachkov unsigned Opcode = 253742633cf2SVyacheslav Levytskyy IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond; 2538eab7d363SIlia Diachkov return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode)) 2539eab7d363SIlia Diachkov .addDef(ResVReg) 2540eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 2541eab7d363SIlia Diachkov .addUse(I.getOperand(1).getReg()) 2542eab7d363SIlia Diachkov .addUse(OneReg) 2543eab7d363SIlia Diachkov .addUse(ZeroReg) 2544eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 2545eab7d363SIlia Diachkov } 2546eab7d363SIlia Diachkov 2547eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectIToF(Register ResVReg, 2548eab7d363SIlia Diachkov const SPIRVType *ResType, 2549eab7d363SIlia Diachkov MachineInstr &I, bool IsSigned, 2550eab7d363SIlia Diachkov unsigned Opcode) const { 2551eab7d363SIlia Diachkov Register SrcReg = I.getOperand(1).getReg(); 2552eab7d363SIlia Diachkov // We can convert bool value directly to float type without OpConvert*ToF, 2553eab7d363SIlia Diachkov // however the translator generates OpSelect+OpConvert*ToF, so we do the same. 2554eab7d363SIlia Diachkov if (GR.isScalarOrVectorOfType(I.getOperand(1).getReg(), SPIRV::OpTypeBool)) { 2555eab7d363SIlia Diachkov unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType); 2556eab7d363SIlia Diachkov SPIRVType *TmpType = GR.getOrCreateSPIRVIntegerType(BitWidth, I, TII); 2557eab7d363SIlia Diachkov if (ResType->getOpcode() == SPIRV::OpTypeVector) { 2558eab7d363SIlia Diachkov const unsigned NumElts = ResType->getOperand(2).getImm(); 2559eab7d363SIlia Diachkov TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts, I, TII); 2560eab7d363SIlia Diachkov } 2561f9c98068SVyacheslav Levytskyy SrcReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 2562eab7d363SIlia Diachkov selectSelect(SrcReg, TmpType, I, false); 2563eab7d363SIlia Diachkov } 25645889f684SAshley Coleman return selectOpWithSrcs(ResVReg, ResType, I, {SrcReg}, Opcode); 2565eab7d363SIlia Diachkov } 2566eab7d363SIlia Diachkov 2567eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectExt(Register ResVReg, 2568eab7d363SIlia Diachkov const SPIRVType *ResType, 2569eab7d363SIlia Diachkov MachineInstr &I, bool IsSigned) const { 257089d12556SVyacheslav Levytskyy Register SrcReg = I.getOperand(1).getReg(); 257189d12556SVyacheslav Levytskyy if (GR.isScalarOrVectorOfType(SrcReg, SPIRV::OpTypeBool)) 2572eab7d363SIlia Diachkov return selectSelect(ResVReg, ResType, I, IsSigned); 257389d12556SVyacheslav Levytskyy 257489d12556SVyacheslav Levytskyy SPIRVType *SrcType = GR.getSPIRVTypeForVReg(SrcReg); 257542633cf2SVyacheslav Levytskyy if (SrcType == ResType) 257642633cf2SVyacheslav Levytskyy return BuildCOPY(ResVReg, SrcReg, I); 257789d12556SVyacheslav Levytskyy 2578eab7d363SIlia Diachkov unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; 2579eab7d363SIlia Diachkov return selectUnOp(ResVReg, ResType, I, Opcode); 2580eab7d363SIlia Diachkov } 2581eab7d363SIlia Diachkov 25820f131704SVyacheslav Levytskyy bool SPIRVInstructionSelector::selectSUCmp(Register ResVReg, 25830f131704SVyacheslav Levytskyy const SPIRVType *ResType, 25840f131704SVyacheslav Levytskyy MachineInstr &I, 25850f131704SVyacheslav Levytskyy bool IsSigned) const { 25860f131704SVyacheslav Levytskyy MachineIRBuilder MIRBuilder(I); 25870f131704SVyacheslav Levytskyy MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 25880f131704SVyacheslav Levytskyy MachineBasicBlock &BB = *I.getParent(); 25890f131704SVyacheslav Levytskyy // Ensure we have bool. 25900f131704SVyacheslav Levytskyy SPIRVType *BoolType = GR.getOrCreateSPIRVBoolType(I, TII); 25910f131704SVyacheslav Levytskyy unsigned N = GR.getScalarOrVectorComponentCount(ResType); 25920f131704SVyacheslav Levytskyy if (N > 1) 25930f131704SVyacheslav Levytskyy BoolType = GR.getOrCreateSPIRVVectorType(BoolType, N, I, TII); 25940f131704SVyacheslav Levytskyy Register BoolTypeReg = GR.getSPIRVTypeID(BoolType); 25950f131704SVyacheslav Levytskyy // Build less-than-equal and less-than. 25960f131704SVyacheslav Levytskyy // TODO: replace with one-liner createVirtualRegister() from 25970f131704SVyacheslav Levytskyy // llvm/lib/Target/SPIRV/SPIRVUtils.cpp when PR #116609 is merged. 25980f131704SVyacheslav Levytskyy Register IsLessEqReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); 25990f131704SVyacheslav Levytskyy MRI->setType(IsLessEqReg, LLT::scalar(64)); 26000f131704SVyacheslav Levytskyy GR.assignSPIRVTypeToVReg(ResType, IsLessEqReg, MIRBuilder.getMF()); 26010f131704SVyacheslav Levytskyy bool Result = BuildMI(BB, I, I.getDebugLoc(), 26020f131704SVyacheslav Levytskyy TII.get(IsSigned ? SPIRV::OpSLessThanEqual 26030f131704SVyacheslav Levytskyy : SPIRV::OpULessThanEqual)) 26040f131704SVyacheslav Levytskyy .addDef(IsLessEqReg) 26050f131704SVyacheslav Levytskyy .addUse(BoolTypeReg) 26060f131704SVyacheslav Levytskyy .addUse(I.getOperand(1).getReg()) 26070f131704SVyacheslav Levytskyy .addUse(I.getOperand(2).getReg()) 26080f131704SVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 26090f131704SVyacheslav Levytskyy Register IsLessReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); 26100f131704SVyacheslav Levytskyy MRI->setType(IsLessReg, LLT::scalar(64)); 26110f131704SVyacheslav Levytskyy GR.assignSPIRVTypeToVReg(ResType, IsLessReg, MIRBuilder.getMF()); 26120f131704SVyacheslav Levytskyy Result &= BuildMI(BB, I, I.getDebugLoc(), 26130f131704SVyacheslav Levytskyy TII.get(IsSigned ? SPIRV::OpSLessThan : SPIRV::OpULessThan)) 26140f131704SVyacheslav Levytskyy .addDef(IsLessReg) 26150f131704SVyacheslav Levytskyy .addUse(BoolTypeReg) 26160f131704SVyacheslav Levytskyy .addUse(I.getOperand(1).getReg()) 26170f131704SVyacheslav Levytskyy .addUse(I.getOperand(2).getReg()) 26180f131704SVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 26190f131704SVyacheslav Levytskyy // Build selects. 26200f131704SVyacheslav Levytskyy Register ResTypeReg = GR.getSPIRVTypeID(ResType); 26210f131704SVyacheslav Levytskyy Register NegOneOrZeroReg = 26220f131704SVyacheslav Levytskyy MRI->createVirtualRegister(GR.getRegClass(ResType)); 26230f131704SVyacheslav Levytskyy MRI->setType(NegOneOrZeroReg, LLT::scalar(64)); 26240f131704SVyacheslav Levytskyy GR.assignSPIRVTypeToVReg(ResType, NegOneOrZeroReg, MIRBuilder.getMF()); 26250f131704SVyacheslav Levytskyy unsigned SelectOpcode = 26260f131704SVyacheslav Levytskyy N > 1 ? SPIRV::OpSelectVIVCond : SPIRV::OpSelectSISCond; 26270f131704SVyacheslav Levytskyy Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(SelectOpcode)) 26280f131704SVyacheslav Levytskyy .addDef(NegOneOrZeroReg) 26290f131704SVyacheslav Levytskyy .addUse(ResTypeReg) 26300f131704SVyacheslav Levytskyy .addUse(IsLessReg) 26310f131704SVyacheslav Levytskyy .addUse(buildOnesVal(true, ResType, I)) // -1 26320f131704SVyacheslav Levytskyy .addUse(buildZerosVal(ResType, I)) 26330f131704SVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 26340f131704SVyacheslav Levytskyy return Result & BuildMI(BB, I, I.getDebugLoc(), TII.get(SelectOpcode)) 26350f131704SVyacheslav Levytskyy .addDef(ResVReg) 26360f131704SVyacheslav Levytskyy .addUse(ResTypeReg) 26370f131704SVyacheslav Levytskyy .addUse(IsLessEqReg) 26380f131704SVyacheslav Levytskyy .addUse(NegOneOrZeroReg) // -1 or 0 26390f131704SVyacheslav Levytskyy .addUse(buildOnesVal(false, ResType, I)) 26400f131704SVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 26410f131704SVyacheslav Levytskyy } 26420f131704SVyacheslav Levytskyy 2643eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectIntToBool(Register IntReg, 2644eab7d363SIlia Diachkov Register ResVReg, 2645698c8001SIlia Diachkov MachineInstr &I, 2646eab7d363SIlia Diachkov const SPIRVType *IntTy, 2647698c8001SIlia Diachkov const SPIRVType *BoolTy) const { 2648eab7d363SIlia Diachkov // To truncate to a bool, we use OpBitwiseAnd 1 and OpINotEqual to zero. 2649f9c98068SVyacheslav Levytskyy Register BitIntReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 2650eab7d363SIlia Diachkov bool IsVectorTy = IntTy->getOpcode() == SPIRV::OpTypeVector; 2651eab7d363SIlia Diachkov unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS; 2652eab7d363SIlia Diachkov Register Zero = buildZerosVal(IntTy, I); 2653eab7d363SIlia Diachkov Register One = buildOnesVal(false, IntTy, I); 2654eab7d363SIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 2655a93cbd4eSFinn Plummer bool Result = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) 2656eab7d363SIlia Diachkov .addDef(BitIntReg) 2657eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(IntTy)) 2658eab7d363SIlia Diachkov .addUse(IntReg) 2659eab7d363SIlia Diachkov .addUse(One) 2660eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 2661a93cbd4eSFinn Plummer return Result && BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual)) 2662eab7d363SIlia Diachkov .addDef(ResVReg) 2663eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(BoolTy)) 2664eab7d363SIlia Diachkov .addUse(BitIntReg) 2665eab7d363SIlia Diachkov .addUse(Zero) 2666eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 2667eab7d363SIlia Diachkov } 2668eab7d363SIlia Diachkov 2669eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectTrunc(Register ResVReg, 2670eab7d363SIlia Diachkov const SPIRVType *ResType, 2671eab7d363SIlia Diachkov MachineInstr &I) const { 2672eab7d363SIlia Diachkov Register IntReg = I.getOperand(1).getReg(); 2673eab7d363SIlia Diachkov const SPIRVType *ArgType = GR.getSPIRVTypeForVReg(IntReg); 267489d12556SVyacheslav Levytskyy if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool)) 2675698c8001SIlia Diachkov return selectIntToBool(IntReg, ResVReg, I, ArgType, ResType); 267642633cf2SVyacheslav Levytskyy if (ArgType == ResType) 267742633cf2SVyacheslav Levytskyy return BuildCOPY(ResVReg, IntReg, I); 2678eab7d363SIlia Diachkov bool IsSigned = GR.isScalarOrVectorSigned(ResType); 2679eab7d363SIlia Diachkov unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; 2680eab7d363SIlia Diachkov return selectUnOp(ResVReg, ResType, I, Opcode); 2681eab7d363SIlia Diachkov } 2682eab7d363SIlia Diachkov 2683eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectConst(Register ResVReg, 2684eab7d363SIlia Diachkov const SPIRVType *ResType, 2685eab7d363SIlia Diachkov const APInt &Imm, 2686eab7d363SIlia Diachkov MachineInstr &I) const { 2687b8e1544bSIlia Diachkov unsigned TyOpcode = ResType->getOpcode(); 2688147ff1b4SMichal Paszkowski assert(TyOpcode != SPIRV::OpTypePointer || Imm.isZero()); 2689eab7d363SIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 2690b8e1544bSIlia Diachkov if ((TyOpcode == SPIRV::OpTypePointer || TyOpcode == SPIRV::OpTypeEvent) && 2691147ff1b4SMichal Paszkowski Imm.isZero()) 2692eab7d363SIlia Diachkov return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull)) 2693eab7d363SIlia Diachkov .addDef(ResVReg) 2694eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 2695eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 2696b8e1544bSIlia Diachkov if (TyOpcode == SPIRV::OpTypeInt) { 2697dc4330a9SMichal Paszkowski assert(Imm.getBitWidth() <= 64 && "Unsupported integer width!"); 2698b8e1544bSIlia Diachkov Register Reg = GR.getOrCreateConstInt(Imm.getZExtValue(), I, ResType, TII); 269942633cf2SVyacheslav Levytskyy return Reg == ResVReg ? true : BuildCOPY(ResVReg, Reg, I); 2700eab7d363SIlia Diachkov } 2701eab7d363SIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI)) 2702eab7d363SIlia Diachkov .addDef(ResVReg) 2703eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)); 2704eab7d363SIlia Diachkov // <=32-bit integers should be caught by the sdag pattern. 2705eab7d363SIlia Diachkov assert(Imm.getBitWidth() > 32); 2706eab7d363SIlia Diachkov addNumImm(Imm, MIB); 2707eab7d363SIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 2708eab7d363SIlia Diachkov } 2709eab7d363SIlia Diachkov 2710eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectOpUndef(Register ResVReg, 2711eab7d363SIlia Diachkov const SPIRVType *ResType, 2712eab7d363SIlia Diachkov MachineInstr &I) const { 2713eab7d363SIlia Diachkov return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpUndef)) 2714eab7d363SIlia Diachkov .addDef(ResVReg) 2715eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 2716eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 2717eab7d363SIlia Diachkov } 2718eab7d363SIlia Diachkov 27190098f2aeSIlia Diachkov static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI) { 27200098f2aeSIlia Diachkov assert(MO.isReg()); 27210098f2aeSIlia Diachkov const SPIRVType *TypeInst = MRI->getVRegDef(MO.getReg()); 27220d9172ecSVyacheslav Levytskyy if (TypeInst->getOpcode() == SPIRV::ASSIGN_TYPE) { 27230098f2aeSIlia Diachkov assert(TypeInst->getOperand(1).isReg()); 27240098f2aeSIlia Diachkov MachineInstr *ImmInst = MRI->getVRegDef(TypeInst->getOperand(1).getReg()); 27250098f2aeSIlia Diachkov return ImmInst->getOpcode() == TargetOpcode::G_CONSTANT; 27260098f2aeSIlia Diachkov } 27270d9172ecSVyacheslav Levytskyy return TypeInst->getOpcode() == SPIRV::OpConstantI; 27280d9172ecSVyacheslav Levytskyy } 27290098f2aeSIlia Diachkov 27300098f2aeSIlia Diachkov static int64_t foldImm(const MachineOperand &MO, MachineRegisterInfo *MRI) { 27310098f2aeSIlia Diachkov const SPIRVType *TypeInst = MRI->getVRegDef(MO.getReg()); 27320d9172ecSVyacheslav Levytskyy if (TypeInst->getOpcode() == SPIRV::OpConstantI) 27330d9172ecSVyacheslav Levytskyy return TypeInst->getOperand(2).getImm(); 27340098f2aeSIlia Diachkov MachineInstr *ImmInst = MRI->getVRegDef(TypeInst->getOperand(1).getReg()); 27350098f2aeSIlia Diachkov assert(ImmInst->getOpcode() == TargetOpcode::G_CONSTANT); 27360098f2aeSIlia Diachkov return ImmInst->getOperand(1).getCImm()->getZExtValue(); 27370098f2aeSIlia Diachkov } 27380098f2aeSIlia Diachkov 27390098f2aeSIlia Diachkov bool SPIRVInstructionSelector::selectInsertVal(Register ResVReg, 27400098f2aeSIlia Diachkov const SPIRVType *ResType, 27410098f2aeSIlia Diachkov MachineInstr &I) const { 27420098f2aeSIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 2743b8e1544bSIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeInsert)) 27440098f2aeSIlia Diachkov .addDef(ResVReg) 27450098f2aeSIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 27460098f2aeSIlia Diachkov // object to insert 27470098f2aeSIlia Diachkov .addUse(I.getOperand(3).getReg()) 27480098f2aeSIlia Diachkov // composite to insert into 2749b8e1544bSIlia Diachkov .addUse(I.getOperand(2).getReg()); 2750b8e1544bSIlia Diachkov for (unsigned i = 4; i < I.getNumOperands(); i++) 2751b8e1544bSIlia Diachkov MIB.addImm(foldImm(I.getOperand(i), MRI)); 2752b8e1544bSIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 27530098f2aeSIlia Diachkov } 27540098f2aeSIlia Diachkov 27550098f2aeSIlia Diachkov bool SPIRVInstructionSelector::selectExtractVal(Register ResVReg, 27560098f2aeSIlia Diachkov const SPIRVType *ResType, 27570098f2aeSIlia Diachkov MachineInstr &I) const { 27580098f2aeSIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 2759b8e1544bSIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract)) 27600098f2aeSIlia Diachkov .addDef(ResVReg) 27610098f2aeSIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 2762b8e1544bSIlia Diachkov .addUse(I.getOperand(2).getReg()); 2763b8e1544bSIlia Diachkov for (unsigned i = 3; i < I.getNumOperands(); i++) 2764b8e1544bSIlia Diachkov MIB.addImm(foldImm(I.getOperand(i), MRI)); 2765b8e1544bSIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 27660098f2aeSIlia Diachkov } 27670098f2aeSIlia Diachkov 27680098f2aeSIlia Diachkov bool SPIRVInstructionSelector::selectInsertElt(Register ResVReg, 27690098f2aeSIlia Diachkov const SPIRVType *ResType, 27700098f2aeSIlia Diachkov MachineInstr &I) const { 27710098f2aeSIlia Diachkov if (isImm(I.getOperand(4), MRI)) 27720098f2aeSIlia Diachkov return selectInsertVal(ResVReg, ResType, I); 27730098f2aeSIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 27740098f2aeSIlia Diachkov return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorInsertDynamic)) 27750098f2aeSIlia Diachkov .addDef(ResVReg) 27760098f2aeSIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 27770098f2aeSIlia Diachkov .addUse(I.getOperand(2).getReg()) 27780098f2aeSIlia Diachkov .addUse(I.getOperand(3).getReg()) 27790098f2aeSIlia Diachkov .addUse(I.getOperand(4).getReg()) 27800098f2aeSIlia Diachkov .constrainAllUses(TII, TRI, RBI); 27810098f2aeSIlia Diachkov } 27820098f2aeSIlia Diachkov 27830098f2aeSIlia Diachkov bool SPIRVInstructionSelector::selectExtractElt(Register ResVReg, 27840098f2aeSIlia Diachkov const SPIRVType *ResType, 27850098f2aeSIlia Diachkov MachineInstr &I) const { 27860098f2aeSIlia Diachkov if (isImm(I.getOperand(3), MRI)) 27870098f2aeSIlia Diachkov return selectExtractVal(ResVReg, ResType, I); 27880098f2aeSIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 27890098f2aeSIlia Diachkov return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpVectorExtractDynamic)) 27900098f2aeSIlia Diachkov .addDef(ResVReg) 27910098f2aeSIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 27920098f2aeSIlia Diachkov .addUse(I.getOperand(2).getReg()) 27930098f2aeSIlia Diachkov .addUse(I.getOperand(3).getReg()) 27940098f2aeSIlia Diachkov .constrainAllUses(TII, TRI, RBI); 27950098f2aeSIlia Diachkov } 27960098f2aeSIlia Diachkov 27970098f2aeSIlia Diachkov bool SPIRVInstructionSelector::selectGEP(Register ResVReg, 27980098f2aeSIlia Diachkov const SPIRVType *ResType, 27990098f2aeSIlia Diachkov MachineInstr &I) const { 28007658688cSNathan Gauër const bool IsGEPInBounds = I.getOperand(2).getImm(); 2801c01b5bbbSNathan Gauër 2802c01b5bbbSNathan Gauër // OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator only 2803c01b5bbbSNathan Gauër // relies on PtrAccessChain, so we'll try not to deviate. For Vulkan however, 2804c01b5bbbSNathan Gauër // we have to use Op[InBounds]AccessChain. 2805c01b5bbbSNathan Gauër const unsigned Opcode = STI.isVulkanEnv() 28067658688cSNathan Gauër ? (IsGEPInBounds ? SPIRV::OpInBoundsAccessChain 2807c01b5bbbSNathan Gauër : SPIRV::OpAccessChain) 28087658688cSNathan Gauër : (IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain 2809c01b5bbbSNathan Gauër : SPIRV::OpPtrAccessChain); 2810c01b5bbbSNathan Gauër 28110098f2aeSIlia Diachkov auto Res = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode)) 28120098f2aeSIlia Diachkov .addDef(ResVReg) 28130098f2aeSIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 28140098f2aeSIlia Diachkov // Object to get a pointer to. 28150098f2aeSIlia Diachkov .addUse(I.getOperand(3).getReg()); 28160098f2aeSIlia Diachkov // Adding indices. 2817c01b5bbbSNathan Gauër const unsigned StartingIndex = 2818c01b5bbbSNathan Gauër (Opcode == SPIRV::OpAccessChain || Opcode == SPIRV::OpInBoundsAccessChain) 2819c01b5bbbSNathan Gauër ? 5 2820c01b5bbbSNathan Gauër : 4; 2821c01b5bbbSNathan Gauër for (unsigned i = StartingIndex; i < I.getNumExplicitOperands(); ++i) 28220098f2aeSIlia Diachkov Res.addUse(I.getOperand(i).getReg()); 28230098f2aeSIlia Diachkov return Res.constrainAllUses(TII, TRI, RBI); 28240098f2aeSIlia Diachkov } 28250098f2aeSIlia Diachkov 2826b0d03cccSVyacheslav Levytskyy // Maybe wrap a value into OpSpecConstantOp 2827b0d03cccSVyacheslav Levytskyy bool SPIRVInstructionSelector::wrapIntoSpecConstantOp( 2828b0d03cccSVyacheslav Levytskyy MachineInstr &I, SmallVector<Register> &CompositeArgs) const { 2829b0d03cccSVyacheslav Levytskyy bool Result = true; 2830b0d03cccSVyacheslav Levytskyy unsigned Lim = I.getNumExplicitOperands(); 2831b0d03cccSVyacheslav Levytskyy for (unsigned i = I.getNumExplicitDefs() + 1; i < Lim; ++i) { 2832b0d03cccSVyacheslav Levytskyy Register OpReg = I.getOperand(i).getReg(); 2833b0d03cccSVyacheslav Levytskyy SPIRVType *OpDefine = MRI->getVRegDef(OpReg); 2834b0d03cccSVyacheslav Levytskyy SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpReg); 2835b0efde6dSVyacheslav Levytskyy SmallPtrSet<SPIRVType *, 4> Visited; 2836b0efde6dSVyacheslav Levytskyy if (!OpDefine || !OpType || isConstReg(MRI, OpDefine, Visited) || 2837b0efde6dSVyacheslav Levytskyy OpDefine->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST || 2838b0efde6dSVyacheslav Levytskyy GR.isAggregateType(OpType)) { 2839b0d03cccSVyacheslav Levytskyy // The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed 2840b0d03cccSVyacheslav Levytskyy // by selectAddrSpaceCast() 2841b0d03cccSVyacheslav Levytskyy CompositeArgs.push_back(OpReg); 2842b0d03cccSVyacheslav Levytskyy continue; 2843b0d03cccSVyacheslav Levytskyy } 2844b0d03cccSVyacheslav Levytskyy MachineFunction *MF = I.getMF(); 2845b0d03cccSVyacheslav Levytskyy Register WrapReg = GR.find(OpDefine, MF); 2846b0d03cccSVyacheslav Levytskyy if (WrapReg.isValid()) { 2847b0d03cccSVyacheslav Levytskyy CompositeArgs.push_back(WrapReg); 2848b0d03cccSVyacheslav Levytskyy continue; 2849b0d03cccSVyacheslav Levytskyy } 2850b0d03cccSVyacheslav Levytskyy // Create a new register for the wrapper 285142633cf2SVyacheslav Levytskyy WrapReg = MRI->createVirtualRegister(GR.getRegClass(OpType)); 2852b0d03cccSVyacheslav Levytskyy GR.add(OpDefine, MF, WrapReg); 2853b0d03cccSVyacheslav Levytskyy CompositeArgs.push_back(WrapReg); 2854b0d03cccSVyacheslav Levytskyy // Decorate the wrapper register and generate a new instruction 285567d3ef74SVyacheslav Levytskyy MRI->setType(WrapReg, LLT::pointer(0, 64)); 2856b0d03cccSVyacheslav Levytskyy GR.assignSPIRVTypeToVReg(OpType, WrapReg, *MF); 2857b0d03cccSVyacheslav Levytskyy MachineBasicBlock &BB = *I.getParent(); 2858b0d03cccSVyacheslav Levytskyy Result = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSpecConstantOp)) 2859b0d03cccSVyacheslav Levytskyy .addDef(WrapReg) 2860b0d03cccSVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(OpType)) 2861b0d03cccSVyacheslav Levytskyy .addImm(static_cast<uint32_t>(SPIRV::Opcode::Bitcast)) 2862b0d03cccSVyacheslav Levytskyy .addUse(OpReg) 2863b0d03cccSVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 2864b0d03cccSVyacheslav Levytskyy if (!Result) 2865b0d03cccSVyacheslav Levytskyy break; 2866b0d03cccSVyacheslav Levytskyy } 2867b0d03cccSVyacheslav Levytskyy return Result; 2868b0d03cccSVyacheslav Levytskyy } 2869b0d03cccSVyacheslav Levytskyy 2870eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, 2871eab7d363SIlia Diachkov const SPIRVType *ResType, 2872eab7d363SIlia Diachkov MachineInstr &I) const { 28730098f2aeSIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 287459f34e8cSVyacheslav Levytskyy Intrinsic::ID IID = cast<GIntrinsic>(I).getIntrinsicID(); 287559f34e8cSVyacheslav Levytskyy switch (IID) { 28760098f2aeSIlia Diachkov case Intrinsic::spv_load: 28770098f2aeSIlia Diachkov return selectLoad(ResVReg, ResType, I); 28780098f2aeSIlia Diachkov case Intrinsic::spv_store: 28790098f2aeSIlia Diachkov return selectStore(I); 28800098f2aeSIlia Diachkov case Intrinsic::spv_extractv: 28810098f2aeSIlia Diachkov return selectExtractVal(ResVReg, ResType, I); 28820098f2aeSIlia Diachkov case Intrinsic::spv_insertv: 28830098f2aeSIlia Diachkov return selectInsertVal(ResVReg, ResType, I); 28840098f2aeSIlia Diachkov case Intrinsic::spv_extractelt: 28850098f2aeSIlia Diachkov return selectExtractElt(ResVReg, ResType, I); 28860098f2aeSIlia Diachkov case Intrinsic::spv_insertelt: 28870098f2aeSIlia Diachkov return selectInsertElt(ResVReg, ResType, I); 28880098f2aeSIlia Diachkov case Intrinsic::spv_gep: 28890098f2aeSIlia Diachkov return selectGEP(ResVReg, ResType, I); 28900098f2aeSIlia Diachkov case Intrinsic::spv_unref_global: 28910098f2aeSIlia Diachkov case Intrinsic::spv_init_global: { 28920098f2aeSIlia Diachkov MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg()); 28930098f2aeSIlia Diachkov MachineInstr *Init = I.getNumExplicitOperands() > 2 28940098f2aeSIlia Diachkov ? MRI->getVRegDef(I.getOperand(2).getReg()) 28950098f2aeSIlia Diachkov : nullptr; 28960098f2aeSIlia Diachkov assert(MI); 28970098f2aeSIlia Diachkov return selectGlobalValue(MI->getOperand(0).getReg(), *MI, Init); 2898b8435e39SMichal Paszkowski } 2899b8435e39SMichal Paszkowski case Intrinsic::spv_undef: { 2900b8435e39SMichal Paszkowski auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef)) 2901b8435e39SMichal Paszkowski .addDef(ResVReg) 2902b8435e39SMichal Paszkowski .addUse(GR.getSPIRVTypeID(ResType)); 2903b8435e39SMichal Paszkowski return MIB.constrainAllUses(TII, TRI, RBI); 2904b8435e39SMichal Paszkowski } 29050098f2aeSIlia Diachkov case Intrinsic::spv_const_composite: { 29060098f2aeSIlia Diachkov // If no values are attached, the composite is null constant. 29070098f2aeSIlia Diachkov bool IsNull = I.getNumExplicitDefs() + 1 == I.getNumExplicitOperands(); 2908b0d03cccSVyacheslav Levytskyy // Select a proper instruction. 2909b0d03cccSVyacheslav Levytskyy unsigned Opcode = SPIRV::OpConstantNull; 2910b0d03cccSVyacheslav Levytskyy SmallVector<Register> CompositeArgs; 2911b0d03cccSVyacheslav Levytskyy if (!IsNull) { 2912b0d03cccSVyacheslav Levytskyy Opcode = SPIRV::OpConstantComposite; 2913b0d03cccSVyacheslav Levytskyy if (!wrapIntoSpecConstantOp(I, CompositeArgs)) 2914b0d03cccSVyacheslav Levytskyy return false; 2915b0d03cccSVyacheslav Levytskyy } 291642633cf2SVyacheslav Levytskyy MRI->setRegClass(ResVReg, GR.getRegClass(ResType)); 29170098f2aeSIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) 29180098f2aeSIlia Diachkov .addDef(ResVReg) 29190098f2aeSIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)); 29200098f2aeSIlia Diachkov // skip type MD node we already used when generated assign.type for this 29210098f2aeSIlia Diachkov if (!IsNull) { 2922b0d03cccSVyacheslav Levytskyy for (Register OpReg : CompositeArgs) 2923b0d03cccSVyacheslav Levytskyy MIB.addUse(OpReg); 29240098f2aeSIlia Diachkov } 29250098f2aeSIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 2926b8435e39SMichal Paszkowski } 29270098f2aeSIlia Diachkov case Intrinsic::spv_assign_name: { 29280098f2aeSIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpName)); 29290098f2aeSIlia Diachkov MIB.addUse(I.getOperand(I.getNumExplicitDefs() + 1).getReg()); 29300098f2aeSIlia Diachkov for (unsigned i = I.getNumExplicitDefs() + 2; 29310098f2aeSIlia Diachkov i < I.getNumExplicitOperands(); ++i) { 29320098f2aeSIlia Diachkov MIB.addImm(I.getOperand(i).getImm()); 29330098f2aeSIlia Diachkov } 29340098f2aeSIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 2935b8435e39SMichal Paszkowski } 29360098f2aeSIlia Diachkov case Intrinsic::spv_switch: { 29370098f2aeSIlia Diachkov auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSwitch)); 29380098f2aeSIlia Diachkov for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) { 29390098f2aeSIlia Diachkov if (I.getOperand(i).isReg()) 29400098f2aeSIlia Diachkov MIB.addReg(I.getOperand(i).getReg()); 29410098f2aeSIlia Diachkov else if (I.getOperand(i).isCImm()) 29420098f2aeSIlia Diachkov addNumImm(I.getOperand(i).getCImm()->getValue(), MIB); 29430098f2aeSIlia Diachkov else if (I.getOperand(i).isMBB()) 29440098f2aeSIlia Diachkov MIB.addMBB(I.getOperand(i).getMBB()); 29450098f2aeSIlia Diachkov else 29460098f2aeSIlia Diachkov llvm_unreachable("Unexpected OpSwitch operand"); 29470098f2aeSIlia Diachkov } 29480098f2aeSIlia Diachkov return MIB.constrainAllUses(TII, TRI, RBI); 2949b8435e39SMichal Paszkowski } 2950380bb51bSjoaosaffran case Intrinsic::spv_loop_merge: { 2951380bb51bSjoaosaffran auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoopMerge)); 29521ed65febSNathan Gauër for (unsigned i = 1; i < I.getNumExplicitOperands(); ++i) { 29531ed65febSNathan Gauër assert(I.getOperand(i).isMBB()); 29541ed65febSNathan Gauër MIB.addMBB(I.getOperand(i).getMBB()); 29551ed65febSNathan Gauër } 29561ed65febSNathan Gauër MIB.addImm(SPIRV::SelectionControl::None); 29571ed65febSNathan Gauër return MIB.constrainAllUses(TII, TRI, RBI); 29581ed65febSNathan Gauër } 2959380bb51bSjoaosaffran case Intrinsic::spv_selection_merge: { 2960380bb51bSjoaosaffran auto MIB = 2961380bb51bSjoaosaffran BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpSelectionMerge)); 2962380bb51bSjoaosaffran assert(I.getOperand(1).isMBB() && 2963380bb51bSjoaosaffran "operand 1 to spv_selection_merge must be a basic block"); 2964380bb51bSjoaosaffran MIB.addMBB(I.getOperand(1).getMBB()); 2965380bb51bSjoaosaffran MIB.addImm(getSelectionOperandForImm(I.getOperand(2).getImm())); 2966380bb51bSjoaosaffran return MIB.constrainAllUses(TII, TRI, RBI); 2967380bb51bSjoaosaffran } 2968b8e1544bSIlia Diachkov case Intrinsic::spv_cmpxchg: 2969b8e1544bSIlia Diachkov return selectAtomicCmpXchg(ResVReg, ResType, I); 2970698c8001SIlia Diachkov case Intrinsic::spv_unreachable: 2971a93cbd4eSFinn Plummer return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUnreachable)) 2972a93cbd4eSFinn Plummer .constrainAllUses(TII, TRI, RBI); 2973698c8001SIlia Diachkov case Intrinsic::spv_alloca: 2974698c8001SIlia Diachkov return selectFrameIndex(ResVReg, ResType, I); 2975ada70f50SVyacheslav Levytskyy case Intrinsic::spv_alloca_array: 2976ada70f50SVyacheslav Levytskyy return selectAllocaArray(ResVReg, ResType, I); 297705640657SPaulo Matos case Intrinsic::spv_assume: 29788b732658SPaulo Matos if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) 2979a93cbd4eSFinn Plummer return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAssumeTrueKHR)) 2980a93cbd4eSFinn Plummer .addUse(I.getOperand(1).getReg()) 2981a93cbd4eSFinn Plummer .constrainAllUses(TII, TRI, RBI); 298205640657SPaulo Matos break; 298305640657SPaulo Matos case Intrinsic::spv_expect: 29848b732658SPaulo Matos if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) 2985a93cbd4eSFinn Plummer return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExpectKHR)) 298605640657SPaulo Matos .addDef(ResVReg) 298705640657SPaulo Matos .addUse(GR.getSPIRVTypeID(ResType)) 298805640657SPaulo Matos .addUse(I.getOperand(2).getReg()) 2989a93cbd4eSFinn Plummer .addUse(I.getOperand(3).getReg()) 2990a93cbd4eSFinn Plummer .constrainAllUses(TII, TRI, RBI); 299105640657SPaulo Matos break; 29920e347660SVyacheslav Levytskyy case Intrinsic::arithmetic_fence: 29930e347660SVyacheslav Levytskyy if (STI.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence)) 2994a93cbd4eSFinn Plummer return BuildMI(BB, I, I.getDebugLoc(), 2995a93cbd4eSFinn Plummer TII.get(SPIRV::OpArithmeticFenceEXT)) 29960e347660SVyacheslav Levytskyy .addDef(ResVReg) 29970e347660SVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(ResType)) 2998a93cbd4eSFinn Plummer .addUse(I.getOperand(2).getReg()) 2999a93cbd4eSFinn Plummer .constrainAllUses(TII, TRI, RBI); 30000e347660SVyacheslav Levytskyy else 300142633cf2SVyacheslav Levytskyy return BuildCOPY(ResVReg, I.getOperand(2).getReg(), I); 30020e347660SVyacheslav Levytskyy break; 30036325dd57SNatalie Chouinard case Intrinsic::spv_thread_id: 3004951a284fSZhengxing li // The HLSL SV_DispatchThreadID semantic is lowered to llvm.spv.thread.id 3005951a284fSZhengxing li // intrinsic in LLVM IR for SPIR-V backend. 3006951a284fSZhengxing li // 3007951a284fSZhengxing li // In SPIR-V backend, llvm.spv.thread.id is now correctly translated to a 3008951a284fSZhengxing li // `GlobalInvocationId` builtin variable 3009951a284fSZhengxing li return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalInvocationId, ResVReg, 3010951a284fSZhengxing li ResType, I); 3011951a284fSZhengxing li case Intrinsic::spv_thread_id_in_group: 3012951a284fSZhengxing li // The HLSL SV_GroupThreadId semantic is lowered to 3013951a284fSZhengxing li // llvm.spv.thread.id.in.group intrinsic in LLVM IR for SPIR-V backend. 3014951a284fSZhengxing li // 3015951a284fSZhengxing li // In SPIR-V backend, llvm.spv.thread.id.in.group is now correctly 3016951a284fSZhengxing li // translated to a `LocalInvocationId` builtin variable 3017951a284fSZhengxing li return loadVec3BuiltinInputID(SPIRV::BuiltIn::LocalInvocationId, ResVReg, 3018951a284fSZhengxing li ResType, I); 30197a761100SZhengxing li case Intrinsic::spv_group_id: 30207a761100SZhengxing li // The HLSL SV_GroupId semantic is lowered to 30217a761100SZhengxing li // llvm.spv.group.id intrinsic in LLVM IR for SPIR-V backend. 30227a761100SZhengxing li // 30237a761100SZhengxing li // In SPIR-V backend, llvm.spv.group.id is now translated to a `WorkgroupId` 30247a761100SZhengxing li // builtin variable 30257a761100SZhengxing li return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupId, ResVReg, ResType, 30267a761100SZhengxing li I); 3027319c7a42SGreg Roth case Intrinsic::spv_fdot: 3028319c7a42SGreg Roth return selectFloatDot(ResVReg, ResType, I); 3029319c7a42SGreg Roth case Intrinsic::spv_udot: 3030319c7a42SGreg Roth case Intrinsic::spv_sdot: 3031dcd69ddeSFinn Plummer if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) || 3032dcd69ddeSFinn Plummer STI.isAtLeastSPIRVVer(VersionTuple(1, 6))) 3033dcd69ddeSFinn Plummer return selectIntegerDot(ResVReg, ResType, I, 3034dcd69ddeSFinn Plummer /*Signed=*/IID == Intrinsic::spv_sdot); 3035dcd69ddeSFinn Plummer return selectIntegerDotExpansion(ResVReg, ResType, I); 30363cdac067SFinn Plummer case Intrinsic::spv_dot4add_i8packed: 30373cdac067SFinn Plummer if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) || 30383cdac067SFinn Plummer STI.isAtLeastSPIRVVer(VersionTuple(1, 6))) 30393cdac067SFinn Plummer return selectDot4AddPacked<true>(ResVReg, ResType, I); 30403cdac067SFinn Plummer return selectDot4AddPackedExpansion<true>(ResVReg, ResType, I); 3041bf30b6c3SFinn Plummer case Intrinsic::spv_dot4add_u8packed: 3042bf30b6c3SFinn Plummer if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) || 3043bf30b6c3SFinn Plummer STI.isAtLeastSPIRVVer(VersionTuple(1, 6))) 3044bf30b6c3SFinn Plummer return selectDot4AddPacked<false>(ResVReg, ResType, I); 3045bf30b6c3SFinn Plummer return selectDot4AddPackedExpansion<false>(ResVReg, ResType, I); 304605093e24SFarzon Lotfi case Intrinsic::spv_all: 304705093e24SFarzon Lotfi return selectAll(ResVReg, ResType, I); 3048105dcc88SFarzon Lotfi case Intrinsic::spv_any: 3049105dcc88SFarzon Lotfi return selectAny(ResVReg, ResType, I); 3050c098435eSJoshua Batista case Intrinsic::spv_cross: 3051c098435eSJoshua Batista return selectExtInst(ResVReg, ResType, I, CL::cross, GL::Cross); 305221edac25SFarzon Lotfi case Intrinsic::spv_distance: 305321edac25SFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::distance, GL::Distance); 3054c4c54af5SFarzon Lotfi case Intrinsic::spv_lerp: 3055add6b2f3SFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::mix, GL::FMix); 3056e4e938f3SJoshua Batista case Intrinsic::spv_length: 3057add6b2f3SFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::length, GL::Length); 305826475050SFinn Plummer case Intrinsic::spv_degrees: 305926475050SFinn Plummer return selectExtInst(ResVReg, ResType, I, CL::degrees, GL::Degrees); 3060c92d9b06SAndrii Levytskyi case Intrinsic::spv_frac: 3061add6b2f3SFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract); 30621b2d11deSJoshua Batista case Intrinsic::spv_normalize: 3063add6b2f3SFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::normalize, GL::Normalize); 306435a2b609SHelena Kotas case Intrinsic::spv_rsqrt: 3065add6b2f3SFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::rsqrt, GL::InverseSqrt); 3066a9a5a18aSTim Gymnich case Intrinsic::spv_sign: 3067a9a5a18aSTim Gymnich return selectSign(ResVReg, ResType, I); 3068fb90733eSSarah Spall case Intrinsic::spv_firstbituhigh: // There is no CL equivalent of FindUMsb 3069fb90733eSSarah Spall return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/false); 3070fb90733eSSarah Spall case Intrinsic::spv_firstbitshigh: // There is no CL equivalent of FindSMsb 3071fb90733eSSarah Spall return selectFirstBitHigh(ResVReg, ResType, I, /*IsSigned=*/true); 30724f48abffSAshley Coleman case Intrinsic::spv_firstbitlow: // There is no CL equivlent of FindILsb 30734f48abffSAshley Coleman return selectFirstBitLow(ResVReg, ResType, I); 30743a1228a5SAdam Yang case Intrinsic::spv_group_memory_barrier_with_group_sync: { 3075a93cbd4eSFinn Plummer bool Result = true; 3076a93cbd4eSFinn Plummer auto MemSemConstant = 30773a1228a5SAdam Yang buildI32Constant(SPIRV::MemorySemantics::SequentiallyConsistent, I); 3078a93cbd4eSFinn Plummer Register MemSemReg = MemSemConstant.first; 3079a93cbd4eSFinn Plummer Result &= MemSemConstant.second; 3080a93cbd4eSFinn Plummer auto ScopeConstant = buildI32Constant(SPIRV::Scope::Workgroup, I); 3081a93cbd4eSFinn Plummer Register ScopeReg = ScopeConstant.first; 3082a93cbd4eSFinn Plummer Result &= ScopeConstant.second; 30833a1228a5SAdam Yang MachineBasicBlock &BB = *I.getParent(); 3084a93cbd4eSFinn Plummer return Result && 3085a93cbd4eSFinn Plummer BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpControlBarrier)) 30863a1228a5SAdam Yang .addUse(ScopeReg) 30873a1228a5SAdam Yang .addUse(ScopeReg) 30883a1228a5SAdam Yang .addUse(MemSemReg) 30893a1228a5SAdam Yang .constrainAllUses(TII, TRI, RBI); 3090a93cbd4eSFinn Plummer } 309159f34e8cSVyacheslav Levytskyy case Intrinsic::spv_lifetime_start: 309259f34e8cSVyacheslav Levytskyy case Intrinsic::spv_lifetime_end: { 309359f34e8cSVyacheslav Levytskyy unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart 309459f34e8cSVyacheslav Levytskyy : SPIRV::OpLifetimeStop; 309559f34e8cSVyacheslav Levytskyy int64_t Size = I.getOperand(I.getNumExplicitDefs() + 1).getImm(); 309659f34e8cSVyacheslav Levytskyy Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 2).getReg(); 3097281f59fdSVyacheslav Levytskyy if (Size == -1) 309859f34e8cSVyacheslav Levytskyy Size = 0; 3099a93cbd4eSFinn Plummer return BuildMI(BB, I, I.getDebugLoc(), TII.get(Op)) 3100a93cbd4eSFinn Plummer .addUse(PtrReg) 3101a93cbd4eSFinn Plummer .addImm(Size) 3102a93cbd4eSFinn Plummer .constrainAllUses(TII, TRI, RBI); 3103a93cbd4eSFinn Plummer } 31046a38e19cSS. Bharadwaj Yadavalli case Intrinsic::spv_saturate: 31056a38e19cSS. Bharadwaj Yadavalli return selectSaturate(ResVReg, ResType, I); 310636d757f8SAdam Yang case Intrinsic::spv_nclamp: 310736d757f8SAdam Yang return selectExtInst(ResVReg, ResType, I, CL::fclamp, GL::NClamp); 310836d757f8SAdam Yang case Intrinsic::spv_uclamp: 310936d757f8SAdam Yang return selectExtInst(ResVReg, ResType, I, CL::u_clamp, GL::UClamp); 311036d757f8SAdam Yang case Intrinsic::spv_sclamp: 311136d757f8SAdam Yang return selectExtInst(ResVReg, ResType, I, CL::s_clamp, GL::SClamp); 3112e520b283SFinn Plummer case Intrinsic::spv_wave_active_countbits: 3113e520b283SFinn Plummer return selectWaveActiveCountBits(ResVReg, ResType, I); 311441a6e9cfSAshley Coleman case Intrinsic::spv_wave_all: 311541a6e9cfSAshley Coleman return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAll); 31166735c5ebSAshley Coleman case Intrinsic::spv_wave_any: 31176735c5ebSAshley Coleman return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformAny); 31186735c5ebSAshley Coleman case Intrinsic::spv_wave_is_first_lane: 31196735c5ebSAshley Coleman return selectWaveOpInst(ResVReg, ResType, I, SPIRV::OpGroupNonUniformElect); 3120*aab25f20SAdam Yang case Intrinsic::spv_wave_reduce_umax: 3121*aab25f20SAdam Yang return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ true); 3122*aab25f20SAdam Yang case Intrinsic::spv_wave_reduce_max: 3123*aab25f20SAdam Yang return selectWaveReduceMax(ResVReg, ResType, I, /*IsUnsigned*/ false); 31244446a984SAdam Yang case Intrinsic::spv_wave_reduce_sum: 31254446a984SAdam Yang return selectWaveReduceSum(ResVReg, ResType, I); 31266d13cc94SFinn Plummer case Intrinsic::spv_wave_readlane: 31276735c5ebSAshley Coleman return selectWaveOpInst(ResVReg, ResType, I, 31286735c5ebSAshley Coleman SPIRV::OpGroupNonUniformShuffle); 31292d47a0baSJoshua Batista case Intrinsic::spv_step: 3130add6b2f3SFarzon Lotfi return selectExtInst(ResVReg, ResType, I, CL::step, GL::Step); 3131b2c615fcSJustin Bogner case Intrinsic::spv_radians: 3132b2c615fcSJustin Bogner return selectExtInst(ResVReg, ResType, I, CL::radians, GL::Radians); 3133c538d5c8SVyacheslav Levytskyy // Discard intrinsics which we do not expect to actually represent code after 3134c538d5c8SVyacheslav Levytskyy // lowering or intrinsics which are not implemented but should not crash when 3135c538d5c8SVyacheslav Levytskyy // found in a customer's LLVM IR input. 3136c538d5c8SVyacheslav Levytskyy case Intrinsic::instrprof_increment: 3137c538d5c8SVyacheslav Levytskyy case Intrinsic::instrprof_increment_step: 3138c538d5c8SVyacheslav Levytskyy case Intrinsic::instrprof_value_profile: 3139c538d5c8SVyacheslav Levytskyy break; 3140c538d5c8SVyacheslav Levytskyy // Discard internal intrinsics. 3141a059b299SVyacheslav Levytskyy case Intrinsic::spv_value_md: 3142a059b299SVyacheslav Levytskyy break; 3143aa07f922SJustin Bogner case Intrinsic::spv_resource_handlefrombinding: { 3144a93cbd4eSFinn Plummer return selectHandleFromBinding(ResVReg, ResType, I); 31455af7ae50SSteven Perron } 3146aa07f922SJustin Bogner case Intrinsic::spv_resource_store_typedbuffer: { 314734ba84feSSteven Perron return selectImageWriteIntrinsic(I); 3148756fe54dSSteven Perron } 3149aa07f922SJustin Bogner case Intrinsic::spv_resource_load_typedbuffer: { 315034ba84feSSteven Perron return selectReadImageIntrinsic(ResVReg, ResType, I); 3151ba572abeSSteven Perron } 31524b692a95SSteven Perron case Intrinsic::spv_resource_getpointer: { 31534b692a95SSteven Perron return selectResourceGetPointer(ResVReg, ResType, I); 31544b692a95SSteven Perron } 3155bc6c0681Sjoaosaffran case Intrinsic::spv_discard: { 3156bc6c0681Sjoaosaffran return selectDiscard(ResVReg, ResType, I); 3157bc6c0681Sjoaosaffran } 315859f34e8cSVyacheslav Levytskyy default: { 315959f34e8cSVyacheslav Levytskyy std::string DiagMsg; 316059f34e8cSVyacheslav Levytskyy raw_string_ostream OS(DiagMsg); 316159f34e8cSVyacheslav Levytskyy I.print(OS); 316259f34e8cSVyacheslav Levytskyy DiagMsg = "Intrinsic selection not implemented: " + DiagMsg; 316359f34e8cSVyacheslav Levytskyy report_fatal_error(DiagMsg.c_str(), false); 316459f34e8cSVyacheslav Levytskyy } 3165eab7d363SIlia Diachkov } 31660098f2aeSIlia Diachkov return true; 31670098f2aeSIlia Diachkov } 3168eab7d363SIlia Diachkov 3169a93cbd4eSFinn Plummer bool SPIRVInstructionSelector::selectHandleFromBinding(Register &ResVReg, 31705af7ae50SSteven Perron const SPIRVType *ResType, 31715af7ae50SSteven Perron MachineInstr &I) const { 31724b692a95SSteven Perron return true; 31735af7ae50SSteven Perron } 31745af7ae50SSteven Perron 317534ba84feSSteven Perron bool SPIRVInstructionSelector::selectReadImageIntrinsic( 3176ba572abeSSteven Perron Register &ResVReg, const SPIRVType *ResType, MachineInstr &I) const { 3177ba572abeSSteven Perron 3178ba572abeSSteven Perron // If the load of the image is in a different basic block, then 3179ba572abeSSteven Perron // this will generate invalid code. A proper solution is to move 3180ba572abeSSteven Perron // the OpLoad from selectHandleFromBinding here. However, to do 3181ba572abeSSteven Perron // that we will need to change the return type of the intrinsic. 3182ba572abeSSteven Perron // We will do that when we can, but for now trying to move forward with other 3183ba572abeSSteven Perron // issues. 3184ba572abeSSteven Perron Register ImageReg = I.getOperand(2).getReg(); 31854b692a95SSteven Perron auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg)); 31864b692a95SSteven Perron Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg)); 31874b692a95SSteven Perron if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg), 31884b692a95SSteven Perron *ImageDef, I)) { 31894b692a95SSteven Perron return false; 31904b692a95SSteven Perron } 3191ba572abeSSteven Perron 31924b692a95SSteven Perron Register IdxReg = I.getOperand(3).getReg(); 31934b692a95SSteven Perron DebugLoc Loc = I.getDebugLoc(); 31944b692a95SSteven Perron MachineInstr &Pos = I; 31954b692a95SSteven Perron 31964b692a95SSteven Perron return generateImageRead(ResVReg, ResType, NewImageReg, IdxReg, Loc, Pos); 31974b692a95SSteven Perron } 31984b692a95SSteven Perron 31994b692a95SSteven Perron bool SPIRVInstructionSelector::generateImageRead(Register &ResVReg, 32004b692a95SSteven Perron const SPIRVType *ResType, 32014b692a95SSteven Perron Register ImageReg, 32024b692a95SSteven Perron Register IdxReg, DebugLoc Loc, 32034b692a95SSteven Perron MachineInstr &Pos) const { 3204ba572abeSSteven Perron uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType); 3205ba572abeSSteven Perron if (ResultSize == 4) { 32064b692a95SSteven Perron return BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpImageRead)) 3207ba572abeSSteven Perron .addDef(ResVReg) 3208ba572abeSSteven Perron .addUse(GR.getSPIRVTypeID(ResType)) 3209ba572abeSSteven Perron .addUse(ImageReg) 32104b692a95SSteven Perron .addUse(IdxReg) 321134ba84feSSteven Perron .constrainAllUses(TII, TRI, RBI); 3212ba572abeSSteven Perron } 3213ba572abeSSteven Perron 32144b692a95SSteven Perron SPIRVType *ReadType = widenTypeToVec4(ResType, Pos); 3215ba572abeSSteven Perron Register ReadReg = MRI->createVirtualRegister(GR.getRegClass(ReadType)); 321634ba84feSSteven Perron bool Succeed = 32174b692a95SSteven Perron BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpImageRead)) 3218ba572abeSSteven Perron .addDef(ReadReg) 3219ba572abeSSteven Perron .addUse(GR.getSPIRVTypeID(ReadType)) 3220ba572abeSSteven Perron .addUse(ImageReg) 32214b692a95SSteven Perron .addUse(IdxReg) 322234ba84feSSteven Perron .constrainAllUses(TII, TRI, RBI); 322334ba84feSSteven Perron if (!Succeed) 322434ba84feSSteven Perron return false; 3225ba572abeSSteven Perron 3226ba572abeSSteven Perron if (ResultSize == 1) { 32274b692a95SSteven Perron return BuildMI(*Pos.getParent(), Pos, Loc, 3228ba572abeSSteven Perron TII.get(SPIRV::OpCompositeExtract)) 3229ba572abeSSteven Perron .addDef(ResVReg) 3230ba572abeSSteven Perron .addUse(GR.getSPIRVTypeID(ResType)) 3231ba572abeSSteven Perron .addUse(ReadReg) 323234ba84feSSteven Perron .addImm(0) 323334ba84feSSteven Perron .constrainAllUses(TII, TRI, RBI); 3234ba572abeSSteven Perron } 32354b692a95SSteven Perron return extractSubvector(ResVReg, ResType, ReadReg, Pos); 32364b692a95SSteven Perron } 32374b692a95SSteven Perron 32384b692a95SSteven Perron bool SPIRVInstructionSelector::selectResourceGetPointer( 32394b692a95SSteven Perron Register &ResVReg, const SPIRVType *ResType, MachineInstr &I) const { 32404b692a95SSteven Perron #ifdef ASSERT 32414b692a95SSteven Perron // For now, the operand is an image. This will change once we start handling 32424b692a95SSteven Perron // more resource types. 32434b692a95SSteven Perron Register ResourcePtr = I.getOperand(2).getReg(); 32444b692a95SSteven Perron SPIRVType *RegType = GR.getResultType(ResourcePtr); 32454b692a95SSteven Perron assert(RegType->getOpcode() == SPIRV::OpTypeImage && 32464b692a95SSteven Perron "Can only handle texel buffers for now."); 32474b692a95SSteven Perron #endif 32484b692a95SSteven Perron 32494b692a95SSteven Perron // For texel buffers, the index into the image is part of the OpImageRead or 32504b692a95SSteven Perron // OpImageWrite instructions. So we will do nothing in this case. This 32514b692a95SSteven Perron // intrinsic will be combined with the load or store when selecting the load 32524b692a95SSteven Perron // or store. 32534b692a95SSteven Perron return true; 3254ba572abeSSteven Perron } 3255ba572abeSSteven Perron 325634ba84feSSteven Perron bool SPIRVInstructionSelector::extractSubvector( 3257ba572abeSSteven Perron Register &ResVReg, const SPIRVType *ResType, Register &ReadReg, 3258ba572abeSSteven Perron MachineInstr &InsertionPoint) const { 3259ba572abeSSteven Perron SPIRVType *InputType = GR.getResultType(ReadReg); 3260c03b6e89SGreg Roth [[maybe_unused]] uint64_t InputSize = 3261c03b6e89SGreg Roth GR.getScalarOrVectorComponentCount(InputType); 3262ba572abeSSteven Perron uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType); 3263ba572abeSSteven Perron assert(InputSize > 1 && "The input must be a vector."); 3264ba572abeSSteven Perron assert(ResultSize > 1 && "The result must be a vector."); 3265ba572abeSSteven Perron assert(ResultSize < InputSize && 3266ba572abeSSteven Perron "Cannot extract more element than there are in the input."); 3267ba572abeSSteven Perron SmallVector<Register> ComponentRegisters; 3268ba572abeSSteven Perron SPIRVType *ScalarType = GR.getScalarOrVectorComponentType(ResType); 3269ba572abeSSteven Perron const TargetRegisterClass *ScalarRegClass = GR.getRegClass(ScalarType); 3270ba572abeSSteven Perron for (uint64_t I = 0; I < ResultSize; I++) { 3271ba572abeSSteven Perron Register ComponentReg = MRI->createVirtualRegister(ScalarRegClass); 327234ba84feSSteven Perron bool Succeed = BuildMI(*InsertionPoint.getParent(), InsertionPoint, 327334ba84feSSteven Perron InsertionPoint.getDebugLoc(), 327434ba84feSSteven Perron TII.get(SPIRV::OpCompositeExtract)) 3275ba572abeSSteven Perron .addDef(ComponentReg) 3276ba572abeSSteven Perron .addUse(ScalarType->getOperand(0).getReg()) 3277ba572abeSSteven Perron .addUse(ReadReg) 327834ba84feSSteven Perron .addImm(I) 327934ba84feSSteven Perron .constrainAllUses(TII, TRI, RBI); 328034ba84feSSteven Perron if (!Succeed) 328134ba84feSSteven Perron return false; 3282ba572abeSSteven Perron ComponentRegisters.emplace_back(ComponentReg); 3283ba572abeSSteven Perron } 3284ba572abeSSteven Perron 3285ba572abeSSteven Perron MachineInstrBuilder MIB = BuildMI(*InsertionPoint.getParent(), InsertionPoint, 3286ba572abeSSteven Perron InsertionPoint.getDebugLoc(), 3287ba572abeSSteven Perron TII.get(SPIRV::OpCompositeConstruct)) 3288ba572abeSSteven Perron .addDef(ResVReg) 3289ba572abeSSteven Perron .addUse(GR.getSPIRVTypeID(ResType)); 3290ba572abeSSteven Perron 3291ba572abeSSteven Perron for (Register ComponentReg : ComponentRegisters) 3292ba572abeSSteven Perron MIB.addUse(ComponentReg); 329334ba84feSSteven Perron return MIB.constrainAllUses(TII, TRI, RBI); 3294ba572abeSSteven Perron } 3295ba572abeSSteven Perron 329634ba84feSSteven Perron bool SPIRVInstructionSelector::selectImageWriteIntrinsic( 3297756fe54dSSteven Perron MachineInstr &I) const { 3298756fe54dSSteven Perron // If the load of the image is in a different basic block, then 3299756fe54dSSteven Perron // this will generate invalid code. A proper solution is to move 3300756fe54dSSteven Perron // the OpLoad from selectHandleFromBinding here. However, to do 3301756fe54dSSteven Perron // that we will need to change the return type of the intrinsic. 3302756fe54dSSteven Perron // We will do that when we can, but for now trying to move forward with other 3303756fe54dSSteven Perron // issues. 3304756fe54dSSteven Perron Register ImageReg = I.getOperand(1).getReg(); 33054b692a95SSteven Perron auto *ImageDef = cast<GIntrinsic>(getVRegDef(*MRI, ImageReg)); 33064b692a95SSteven Perron Register NewImageReg = MRI->createVirtualRegister(MRI->getRegClass(ImageReg)); 33074b692a95SSteven Perron if (!loadHandleBeforePosition(NewImageReg, GR.getSPIRVTypeForVReg(ImageReg), 33084b692a95SSteven Perron *ImageDef, I)) { 33094b692a95SSteven Perron return false; 33104b692a95SSteven Perron } 33114b692a95SSteven Perron 3312756fe54dSSteven Perron Register CoordinateReg = I.getOperand(2).getReg(); 3313756fe54dSSteven Perron Register DataReg = I.getOperand(3).getReg(); 3314756fe54dSSteven Perron assert(GR.getResultType(DataReg)->getOpcode() == SPIRV::OpTypeVector); 3315756fe54dSSteven Perron assert(GR.getScalarOrVectorComponentCount(GR.getResultType(DataReg)) == 4); 331634ba84feSSteven Perron return BuildMI(*I.getParent(), I, I.getDebugLoc(), 331734ba84feSSteven Perron TII.get(SPIRV::OpImageWrite)) 33184b692a95SSteven Perron .addUse(NewImageReg) 3319756fe54dSSteven Perron .addUse(CoordinateReg) 332034ba84feSSteven Perron .addUse(DataReg) 332134ba84feSSteven Perron .constrainAllUses(TII, TRI, RBI); 3322756fe54dSSteven Perron } 3323756fe54dSSteven Perron 33245af7ae50SSteven Perron Register SPIRVInstructionSelector::buildPointerToResource( 33255af7ae50SSteven Perron const SPIRVType *ResType, uint32_t Set, uint32_t Binding, 3326d8295e2eSSteven Perron uint32_t ArraySize, Register IndexReg, bool IsNonUniform, 3327d8295e2eSSteven Perron MachineIRBuilder MIRBuilder) const { 3328d8295e2eSSteven Perron if (ArraySize == 1) 33295af7ae50SSteven Perron return GR.getOrCreateGlobalVariableWithBinding(ResType, Set, Binding, 33305af7ae50SSteven Perron MIRBuilder); 3331d8295e2eSSteven Perron 3332d8295e2eSSteven Perron const SPIRVType *VarType = GR.getOrCreateSPIRVArrayType( 3333d8295e2eSSteven Perron ResType, ArraySize, *MIRBuilder.getInsertPt(), TII); 3334d8295e2eSSteven Perron Register VarReg = GR.getOrCreateGlobalVariableWithBinding( 3335d8295e2eSSteven Perron VarType, Set, Binding, MIRBuilder); 3336d8295e2eSSteven Perron 3337d8295e2eSSteven Perron SPIRVType *ResPointerType = GR.getOrCreateSPIRVPointerType( 3338d8295e2eSSteven Perron ResType, MIRBuilder, SPIRV::StorageClass::UniformConstant); 3339d8295e2eSSteven Perron 3340d8295e2eSSteven Perron Register AcReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 3341d8295e2eSSteven Perron if (IsNonUniform) { 3342d8295e2eSSteven Perron // It is unclear which value needs to be marked an non-uniform, so both 3343d8295e2eSSteven Perron // the index and the access changed are decorated as non-uniform. 3344d8295e2eSSteven Perron buildOpDecorate(IndexReg, MIRBuilder, SPIRV::Decoration::NonUniformEXT, {}); 3345d8295e2eSSteven Perron buildOpDecorate(AcReg, MIRBuilder, SPIRV::Decoration::NonUniformEXT, {}); 3346d8295e2eSSteven Perron } 3347d8295e2eSSteven Perron 3348d8295e2eSSteven Perron MIRBuilder.buildInstr(SPIRV::OpAccessChain) 3349d8295e2eSSteven Perron .addDef(AcReg) 3350d8295e2eSSteven Perron .addUse(GR.getSPIRVTypeID(ResPointerType)) 3351d8295e2eSSteven Perron .addUse(VarReg) 3352d8295e2eSSteven Perron .addUse(IndexReg); 3353d8295e2eSSteven Perron 3354d8295e2eSSteven Perron return AcReg; 33555af7ae50SSteven Perron } 33565af7ae50SSteven Perron 33574f48abffSAshley Coleman bool SPIRVInstructionSelector::selectFirstBitSet16( 33584f48abffSAshley Coleman Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 33594f48abffSAshley Coleman unsigned ExtendOpcode, unsigned BitSetOpcode) const { 3360fb90733eSSarah Spall Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); 33614f48abffSAshley Coleman bool Result = selectOpWithSrcs(ExtReg, ResType, I, {I.getOperand(2).getReg()}, 33624f48abffSAshley Coleman ExtendOpcode); 33634f48abffSAshley Coleman 33644f48abffSAshley Coleman return Result && 33654f48abffSAshley Coleman selectFirstBitSet32(ResVReg, ResType, I, ExtReg, BitSetOpcode); 3366fb90733eSSarah Spall } 3367fb90733eSSarah Spall 33684f48abffSAshley Coleman bool SPIRVInstructionSelector::selectFirstBitSet32( 33694f48abffSAshley Coleman Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 33704f48abffSAshley Coleman Register SrcReg, unsigned BitSetOpcode) const { 3371fb90733eSSarah Spall return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) 3372fb90733eSSarah Spall .addDef(ResVReg) 3373fb90733eSSarah Spall .addUse(GR.getSPIRVTypeID(ResType)) 3374fb90733eSSarah Spall .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450)) 33754f48abffSAshley Coleman .addImm(BitSetOpcode) 3376fb90733eSSarah Spall .addUse(SrcReg) 3377fb90733eSSarah Spall .constrainAllUses(TII, TRI, RBI); 3378fb90733eSSarah Spall } 3379fb90733eSSarah Spall 33804f48abffSAshley Coleman bool SPIRVInstructionSelector::selectFirstBitSet64Overflow( 33814f48abffSAshley Coleman Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 33824f48abffSAshley Coleman Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { 33834f48abffSAshley Coleman 33844f48abffSAshley Coleman // SPIR-V allow vectors of size 2,3,4 only. Calling with a larger vectors 33854f48abffSAshley Coleman // requires creating a param register and return register with an invalid 33864f48abffSAshley Coleman // vector size. If that is resolved, then this function can be used for 33874f48abffSAshley Coleman // vectors of any component size. 33884f48abffSAshley Coleman unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); 33894f48abffSAshley Coleman assert(ComponentCount < 5 && "Vec 5+ will generate invalid SPIR-V ops"); 33904f48abffSAshley Coleman 3391fb90733eSSarah Spall MachineIRBuilder MIRBuilder(I); 33924f48abffSAshley Coleman SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); 33934f48abffSAshley Coleman SPIRVType *I64Type = GR.getOrCreateSPIRVIntegerType(64, MIRBuilder); 33944f48abffSAshley Coleman SPIRVType *I64x2Type = GR.getOrCreateSPIRVVectorType(I64Type, 2, MIRBuilder); 33954f48abffSAshley Coleman SPIRVType *Vec2ResType = 33964f48abffSAshley Coleman GR.getOrCreateSPIRVVectorType(BaseType, 2, MIRBuilder); 3397fb90733eSSarah Spall 33984f48abffSAshley Coleman std::vector<Register> PartialRegs; 3399fb90733eSSarah Spall 34004f48abffSAshley Coleman // Loops 0, 2, 4, ... but stops one loop early when ComponentCount is odd 34014f48abffSAshley Coleman unsigned CurrentComponent = 0; 34024f48abffSAshley Coleman for (; CurrentComponent + 1 < ComponentCount; CurrentComponent += 2) { 34034f48abffSAshley Coleman // This register holds the firstbitX result for each of the i64x2 vectors 34044f48abffSAshley Coleman // extracted from SrcReg 34054f48abffSAshley Coleman Register BitSetResult = 34064f48abffSAshley Coleman MRI->createVirtualRegister(GR.getRegClass(I64x2Type)); 34074f48abffSAshley Coleman 34084f48abffSAshley Coleman auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), 34094f48abffSAshley Coleman TII.get(SPIRV::OpVectorShuffle)) 34104f48abffSAshley Coleman .addDef(BitSetResult) 34114f48abffSAshley Coleman .addUse(GR.getSPIRVTypeID(I64x2Type)) 34124f48abffSAshley Coleman .addUse(SrcReg) 34134f48abffSAshley Coleman .addUse(SrcReg) 34144f48abffSAshley Coleman .addImm(CurrentComponent) 34154f48abffSAshley Coleman .addImm(CurrentComponent + 1); 34164f48abffSAshley Coleman 34174f48abffSAshley Coleman if (!MIB.constrainAllUses(TII, TRI, RBI)) 34184f48abffSAshley Coleman return false; 34194f48abffSAshley Coleman 34204f48abffSAshley Coleman Register SubVecBitSetReg = 34214f48abffSAshley Coleman MRI->createVirtualRegister(GR.getRegClass(Vec2ResType)); 34224f48abffSAshley Coleman 34234f48abffSAshley Coleman if (!selectFirstBitSet64(SubVecBitSetReg, Vec2ResType, I, BitSetResult, 34244f48abffSAshley Coleman BitSetOpcode, SwapPrimarySide)) 34254f48abffSAshley Coleman return false; 34264f48abffSAshley Coleman 34274f48abffSAshley Coleman PartialRegs.push_back(SubVecBitSetReg); 34284f48abffSAshley Coleman } 34294f48abffSAshley Coleman 34304f48abffSAshley Coleman // On odd component counts we need to handle one more component 34314f48abffSAshley Coleman if (CurrentComponent != ComponentCount) { 34324f48abffSAshley Coleman bool ZeroAsNull = STI.isOpenCLEnv(); 34334f48abffSAshley Coleman Register FinalElemReg = MRI->createVirtualRegister(GR.getRegClass(I64Type)); 34344f48abffSAshley Coleman Register ConstIntLastIdx = GR.getOrCreateConstInt( 34354f48abffSAshley Coleman ComponentCount - 1, I, BaseType, TII, ZeroAsNull); 34364f48abffSAshley Coleman 34374f48abffSAshley Coleman if (!selectOpWithSrcs(FinalElemReg, I64Type, I, {SrcReg, ConstIntLastIdx}, 34384f48abffSAshley Coleman SPIRV::OpVectorExtractDynamic)) 34394f48abffSAshley Coleman return false; 34404f48abffSAshley Coleman 34414f48abffSAshley Coleman Register FinalElemBitSetReg = 34424f48abffSAshley Coleman MRI->createVirtualRegister(GR.getRegClass(BaseType)); 34434f48abffSAshley Coleman 34444f48abffSAshley Coleman if (!selectFirstBitSet64(FinalElemBitSetReg, BaseType, I, FinalElemReg, 34454f48abffSAshley Coleman BitSetOpcode, SwapPrimarySide)) 34464f48abffSAshley Coleman return false; 34474f48abffSAshley Coleman 34484f48abffSAshley Coleman PartialRegs.push_back(FinalElemBitSetReg); 34494f48abffSAshley Coleman } 34504f48abffSAshley Coleman 34514f48abffSAshley Coleman // Join all the resulting registers back into the return type in order 34524f48abffSAshley Coleman // (ie i32x2, i32x2, i32x1 -> i32x5) 34534f48abffSAshley Coleman return selectOpWithSrcs(ResVReg, ResType, I, PartialRegs, 34544f48abffSAshley Coleman SPIRV::OpCompositeConstruct); 34554f48abffSAshley Coleman } 34564f48abffSAshley Coleman 34574f48abffSAshley Coleman bool SPIRVInstructionSelector::selectFirstBitSet64( 34584f48abffSAshley Coleman Register ResVReg, const SPIRVType *ResType, MachineInstr &I, 34594f48abffSAshley Coleman Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const { 34604f48abffSAshley Coleman unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType); 34614f48abffSAshley Coleman SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType); 34624f48abffSAshley Coleman bool ZeroAsNull = STI.isOpenCLEnv(); 34634f48abffSAshley Coleman Register ConstIntZero = 34644f48abffSAshley Coleman GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull); 34654f48abffSAshley Coleman Register ConstIntOne = 34664f48abffSAshley Coleman GR.getOrCreateConstInt(1, I, BaseType, TII, ZeroAsNull); 34674f48abffSAshley Coleman 34684f48abffSAshley Coleman // SPIRV doesn't support vectors with more than 4 components. Since the 34694f48abffSAshley Coleman // algoritm below converts i64 -> i32x2 and i64x4 -> i32x8 it can only 34704f48abffSAshley Coleman // operate on vectors with 2 or less components. When largers vectors are 34714f48abffSAshley Coleman // seen. Split them, recurse, then recombine them. 34724f48abffSAshley Coleman if (ComponentCount > 2) { 34734f48abffSAshley Coleman return selectFirstBitSet64Overflow(ResVReg, ResType, I, SrcReg, 34744f48abffSAshley Coleman BitSetOpcode, SwapPrimarySide); 34754f48abffSAshley Coleman } 34764f48abffSAshley Coleman 34774f48abffSAshley Coleman // 1. Split int64 into 2 pieces using a bitcast 34784f48abffSAshley Coleman MachineIRBuilder MIRBuilder(I); 34794f48abffSAshley Coleman SPIRVType *PostCastType = 34804f48abffSAshley Coleman GR.getOrCreateSPIRVVectorType(BaseType, 2 * ComponentCount, MIRBuilder); 34814f48abffSAshley Coleman Register BitcastReg = 34824f48abffSAshley Coleman MRI->createVirtualRegister(GR.getRegClass(PostCastType)); 34834f48abffSAshley Coleman 34844f48abffSAshley Coleman if (!selectOpWithSrcs(BitcastReg, PostCastType, I, {SrcReg}, 34854f48abffSAshley Coleman SPIRV::OpBitcast)) 34864f48abffSAshley Coleman return false; 34874f48abffSAshley Coleman 34884f48abffSAshley Coleman // 2. Find the first set bit from the primary side for all the pieces in #1 34894f48abffSAshley Coleman Register FBSReg = MRI->createVirtualRegister(GR.getRegClass(PostCastType)); 34904f48abffSAshley Coleman if (!selectFirstBitSet32(FBSReg, PostCastType, I, BitcastReg, BitSetOpcode)) 34914f48abffSAshley Coleman return false; 34924f48abffSAshley Coleman 34934f48abffSAshley Coleman // 3. Split result vector into high bits and low bits 3494fb90733eSSarah Spall Register HighReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); 3495fb90733eSSarah Spall Register LowReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); 3496fb90733eSSarah Spall 34974f48abffSAshley Coleman bool IsScalarRes = ResType->getOpcode() != SPIRV::OpTypeVector; 34984f48abffSAshley Coleman if (IsScalarRes) { 3499fb90733eSSarah Spall // if scalar do a vector extract 35004f48abffSAshley Coleman if (!selectOpWithSrcs(HighReg, ResType, I, {FBSReg, ConstIntZero}, 35014f48abffSAshley Coleman SPIRV::OpVectorExtractDynamic)) 35024f48abffSAshley Coleman return false; 35034f48abffSAshley Coleman if (!selectOpWithSrcs(LowReg, ResType, I, {FBSReg, ConstIntOne}, 35044f48abffSAshley Coleman SPIRV::OpVectorExtractDynamic)) 35054f48abffSAshley Coleman return false; 35064f48abffSAshley Coleman } else { 35074f48abffSAshley Coleman // if vector do a shufflevector 3508fb90733eSSarah Spall auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), 3509fb90733eSSarah Spall TII.get(SPIRV::OpVectorShuffle)) 3510fb90733eSSarah Spall .addDef(HighReg) 3511fb90733eSSarah Spall .addUse(GR.getSPIRVTypeID(ResType)) 35124f48abffSAshley Coleman .addUse(FBSReg) 35134f48abffSAshley Coleman // Per the spec, repeat the vector if only one vec is needed 35144f48abffSAshley Coleman .addUse(FBSReg); 3515fb90733eSSarah Spall 35164f48abffSAshley Coleman // high bits are stored in even indexes. Extract them from FBSReg 35174f48abffSAshley Coleman for (unsigned J = 0; J < ComponentCount * 2; J += 2) { 35184f48abffSAshley Coleman MIB.addImm(J); 35194f48abffSAshley Coleman } 35204f48abffSAshley Coleman 35214f48abffSAshley Coleman if (!MIB.constrainAllUses(TII, TRI, RBI)) 35224f48abffSAshley Coleman return false; 35234f48abffSAshley Coleman 3524fb90733eSSarah Spall MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), 3525fb90733eSSarah Spall TII.get(SPIRV::OpVectorShuffle)) 3526fb90733eSSarah Spall .addDef(LowReg) 3527fb90733eSSarah Spall .addUse(GR.getSPIRVTypeID(ResType)) 35284f48abffSAshley Coleman .addUse(FBSReg) 35294f48abffSAshley Coleman // Per the spec, repeat the vector if only one vec is needed 35304f48abffSAshley Coleman .addUse(FBSReg); 35314f48abffSAshley Coleman 35324f48abffSAshley Coleman // low bits are stored in odd indexes. Extract them from FBSReg 35334f48abffSAshley Coleman for (unsigned J = 1; J < ComponentCount * 2; J += 2) { 35344f48abffSAshley Coleman MIB.addImm(J); 3535fb90733eSSarah Spall } 35364f48abffSAshley Coleman if (!MIB.constrainAllUses(TII, TRI, RBI)) 35374f48abffSAshley Coleman return false; 3538fb90733eSSarah Spall } 3539fb90733eSSarah Spall 35404f48abffSAshley Coleman // 4. Check the result. When primary bits == -1 use secondary, otherwise use 35414f48abffSAshley Coleman // primary 3542fb90733eSSarah Spall SPIRVType *BoolType = GR.getOrCreateSPIRVBoolType(I, TII); 3543fb90733eSSarah Spall Register NegOneReg; 3544fb90733eSSarah Spall Register Reg0; 3545fb90733eSSarah Spall Register Reg32; 35464f48abffSAshley Coleman unsigned SelectOp; 35474f48abffSAshley Coleman unsigned AddOp; 35484f48abffSAshley Coleman 35494f48abffSAshley Coleman if (IsScalarRes) { 3550fb90733eSSarah Spall NegOneReg = 3551fb90733eSSarah Spall GR.getOrCreateConstInt((unsigned)-1, I, ResType, TII, ZeroAsNull); 3552fb90733eSSarah Spall Reg0 = GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull); 3553fb90733eSSarah Spall Reg32 = GR.getOrCreateConstInt(32, I, ResType, TII, ZeroAsNull); 35544f48abffSAshley Coleman SelectOp = SPIRV::OpSelectSISCond; 35554f48abffSAshley Coleman AddOp = SPIRV::OpIAddS; 3556fb90733eSSarah Spall } else { 35574f48abffSAshley Coleman BoolType = 35584f48abffSAshley Coleman GR.getOrCreateSPIRVVectorType(BoolType, ComponentCount, MIRBuilder); 3559fb90733eSSarah Spall NegOneReg = 3560fb90733eSSarah Spall GR.getOrCreateConstVector((unsigned)-1, I, ResType, TII, ZeroAsNull); 3561fb90733eSSarah Spall Reg0 = GR.getOrCreateConstVector(0, I, ResType, TII, ZeroAsNull); 3562fb90733eSSarah Spall Reg32 = GR.getOrCreateConstVector(32, I, ResType, TII, ZeroAsNull); 35634f48abffSAshley Coleman SelectOp = SPIRV::OpSelectVIVCond; 35644f48abffSAshley Coleman AddOp = SPIRV::OpIAddV; 3565fb90733eSSarah Spall } 3566fb90733eSSarah Spall 35674f48abffSAshley Coleman Register PrimaryReg = HighReg; 35684f48abffSAshley Coleman Register SecondaryReg = LowReg; 35694f48abffSAshley Coleman Register PrimaryShiftReg = Reg32; 35704f48abffSAshley Coleman Register SecondaryShiftReg = Reg0; 35714f48abffSAshley Coleman 35724f48abffSAshley Coleman // By default the emitted opcodes check for the set bit from the MSB side. 35734f48abffSAshley Coleman // Setting SwapPrimarySide checks the set bit from the LSB side 35744f48abffSAshley Coleman if (SwapPrimarySide) { 35754f48abffSAshley Coleman PrimaryReg = LowReg; 35764f48abffSAshley Coleman SecondaryReg = HighReg; 35774f48abffSAshley Coleman PrimaryShiftReg = Reg0; 35784f48abffSAshley Coleman SecondaryShiftReg = Reg32; 35794f48abffSAshley Coleman } 35804f48abffSAshley Coleman 35814f48abffSAshley Coleman // Check if the primary bits are == -1 3582fb90733eSSarah Spall Register BReg = MRI->createVirtualRegister(GR.getRegClass(BoolType)); 35834f48abffSAshley Coleman if (!selectOpWithSrcs(BReg, BoolType, I, {PrimaryReg, NegOneReg}, 35844f48abffSAshley Coleman SPIRV::OpIEqual)) 35854f48abffSAshley Coleman return false; 3586fb90733eSSarah Spall 35874f48abffSAshley Coleman // Select secondary bits if true in BReg, otherwise primary bits 3588fb90733eSSarah Spall Register TmpReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); 35894f48abffSAshley Coleman if (!selectOpWithSrcs(TmpReg, ResType, I, {BReg, SecondaryReg, PrimaryReg}, 35904f48abffSAshley Coleman SelectOp)) 35914f48abffSAshley Coleman return false; 3592fb90733eSSarah Spall 35934f48abffSAshley Coleman // 5. Add 32 when high bits are used, otherwise 0 for low bits 3594fb90733eSSarah Spall Register ValReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); 35954f48abffSAshley Coleman if (!selectOpWithSrcs(ValReg, ResType, I, 35964f48abffSAshley Coleman {BReg, SecondaryShiftReg, PrimaryShiftReg}, SelectOp)) 35974f48abffSAshley Coleman return false; 3598fb90733eSSarah Spall 35994f48abffSAshley Coleman return selectOpWithSrcs(ResVReg, ResType, I, {ValReg, TmpReg}, AddOp); 3600fb90733eSSarah Spall } 3601fb90733eSSarah Spall 3602fb90733eSSarah Spall bool SPIRVInstructionSelector::selectFirstBitHigh(Register ResVReg, 3603fb90733eSSarah Spall const SPIRVType *ResType, 3604fb90733eSSarah Spall MachineInstr &I, 3605fb90733eSSarah Spall bool IsSigned) const { 3606fb90733eSSarah Spall // FindUMsb and FindSMsb intrinsics only support 32 bit integers 3607fb90733eSSarah Spall Register OpReg = I.getOperand(2).getReg(); 3608fb90733eSSarah Spall SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpReg); 36094f48abffSAshley Coleman // zero or sign extend 36104f48abffSAshley Coleman unsigned ExtendOpcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert; 36114f48abffSAshley Coleman unsigned BitSetOpcode = IsSigned ? GL::FindSMsb : GL::FindUMsb; 3612fb90733eSSarah Spall 3613fb90733eSSarah Spall switch (GR.getScalarOrVectorBitWidth(OpType)) { 3614fb90733eSSarah Spall case 16: 36154f48abffSAshley Coleman return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode); 3616fb90733eSSarah Spall case 32: 36174f48abffSAshley Coleman return selectFirstBitSet32(ResVReg, ResType, I, OpReg, BitSetOpcode); 3618fb90733eSSarah Spall case 64: 36194f48abffSAshley Coleman return selectFirstBitSet64(ResVReg, ResType, I, OpReg, BitSetOpcode, 36204f48abffSAshley Coleman /*SwapPrimarySide=*/false); 3621fb90733eSSarah Spall default: 3622fb90733eSSarah Spall report_fatal_error( 3623fb90733eSSarah Spall "spv_firstbituhigh and spv_firstbitshigh only support 16,32,64 bits."); 3624fb90733eSSarah Spall } 3625fb90733eSSarah Spall } 3626fb90733eSSarah Spall 36274f48abffSAshley Coleman bool SPIRVInstructionSelector::selectFirstBitLow(Register ResVReg, 36284f48abffSAshley Coleman const SPIRVType *ResType, 36294f48abffSAshley Coleman MachineInstr &I) const { 36304f48abffSAshley Coleman // FindILsb intrinsic only supports 32 bit integers 36314f48abffSAshley Coleman Register OpReg = I.getOperand(2).getReg(); 36324f48abffSAshley Coleman SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpReg); 36334f48abffSAshley Coleman // OpUConvert treats the operand bits as an unsigned i16 and zero extends it 36344f48abffSAshley Coleman // to an unsigned i32. As this leaves all the least significant bits unchanged 36354f48abffSAshley Coleman // so the first set bit from the LSB side doesn't change. 36364f48abffSAshley Coleman unsigned ExtendOpcode = SPIRV::OpUConvert; 36374f48abffSAshley Coleman unsigned BitSetOpcode = GL::FindILsb; 36384f48abffSAshley Coleman 36394f48abffSAshley Coleman switch (GR.getScalarOrVectorBitWidth(OpType)) { 36404f48abffSAshley Coleman case 16: 36414f48abffSAshley Coleman return selectFirstBitSet16(ResVReg, ResType, I, ExtendOpcode, BitSetOpcode); 36424f48abffSAshley Coleman case 32: 36434f48abffSAshley Coleman return selectFirstBitSet32(ResVReg, ResType, I, OpReg, BitSetOpcode); 36444f48abffSAshley Coleman case 64: 36454f48abffSAshley Coleman return selectFirstBitSet64(ResVReg, ResType, I, OpReg, BitSetOpcode, 36464f48abffSAshley Coleman /*SwapPrimarySide=*/true); 36474f48abffSAshley Coleman default: 36484f48abffSAshley Coleman report_fatal_error("spv_firstbitlow only supports 16,32,64 bits."); 36494f48abffSAshley Coleman } 36504f48abffSAshley Coleman } 36514f48abffSAshley Coleman 3652ada70f50SVyacheslav Levytskyy bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg, 3653ada70f50SVyacheslav Levytskyy const SPIRVType *ResType, 3654ada70f50SVyacheslav Levytskyy MachineInstr &I) const { 3655ada70f50SVyacheslav Levytskyy // there was an allocation size parameter to the allocation instruction 3656ada70f50SVyacheslav Levytskyy // that is not 1 3657ada70f50SVyacheslav Levytskyy MachineBasicBlock &BB = *I.getParent(); 3658489db653SVyacheslav Levytskyy bool Res = BuildMI(BB, I, I.getDebugLoc(), 3659ada70f50SVyacheslav Levytskyy TII.get(SPIRV::OpVariableLengthArrayINTEL)) 3660ada70f50SVyacheslav Levytskyy .addDef(ResVReg) 3661ada70f50SVyacheslav Levytskyy .addUse(GR.getSPIRVTypeID(ResType)) 3662ada70f50SVyacheslav Levytskyy .addUse(I.getOperand(2).getReg()) 3663ada70f50SVyacheslav Levytskyy .constrainAllUses(TII, TRI, RBI); 3664489db653SVyacheslav Levytskyy if (!STI.isVulkanEnv()) { 3665489db653SVyacheslav Levytskyy unsigned Alignment = I.getOperand(3).getImm(); 3666489db653SVyacheslav Levytskyy buildOpDecorate(ResVReg, I, TII, SPIRV::Decoration::Alignment, {Alignment}); 3667489db653SVyacheslav Levytskyy } 3668489db653SVyacheslav Levytskyy return Res; 3669ada70f50SVyacheslav Levytskyy } 3670ada70f50SVyacheslav Levytskyy 3671eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg, 3672eab7d363SIlia Diachkov const SPIRVType *ResType, 3673eab7d363SIlia Diachkov MachineInstr &I) const { 367447e996d8SVyacheslav Levytskyy // Change order of instructions if needed: all OpVariable instructions in a 367547e996d8SVyacheslav Levytskyy // function must be the first instructions in the first block 36768ac46d6bSVyacheslav Levytskyy auto It = getOpVariableMBBIt(I); 3677489db653SVyacheslav Levytskyy bool Res = BuildMI(*It->getParent(), It, It->getDebugLoc(), 36788ac46d6bSVyacheslav Levytskyy TII.get(SPIRV::OpVariable)) 3679eab7d363SIlia Diachkov .addDef(ResVReg) 3680eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 3681eab7d363SIlia Diachkov .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function)) 3682eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 3683489db653SVyacheslav Levytskyy if (!STI.isVulkanEnv()) { 3684489db653SVyacheslav Levytskyy unsigned Alignment = I.getOperand(2).getImm(); 3685489db653SVyacheslav Levytskyy buildOpDecorate(ResVReg, *It, TII, SPIRV::Decoration::Alignment, 3686489db653SVyacheslav Levytskyy {Alignment}); 3687489db653SVyacheslav Levytskyy } 3688489db653SVyacheslav Levytskyy return Res; 3689eab7d363SIlia Diachkov } 3690eab7d363SIlia Diachkov 3691eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectBranch(MachineInstr &I) const { 3692eab7d363SIlia Diachkov // InstructionSelector walks backwards through the instructions. We can use 3693eab7d363SIlia Diachkov // both a G_BR and a G_BRCOND to create an OpBranchConditional. We hit G_BR 3694eab7d363SIlia Diachkov // first, so can generate an OpBranchConditional here. If there is no 3695eab7d363SIlia Diachkov // G_BRCOND, we just use OpBranch for a regular unconditional branch. 3696eab7d363SIlia Diachkov const MachineInstr *PrevI = I.getPrevNode(); 3697eab7d363SIlia Diachkov MachineBasicBlock &MBB = *I.getParent(); 3698eab7d363SIlia Diachkov if (PrevI != nullptr && PrevI->getOpcode() == TargetOpcode::G_BRCOND) { 3699eab7d363SIlia Diachkov return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional)) 3700eab7d363SIlia Diachkov .addUse(PrevI->getOperand(0).getReg()) 3701eab7d363SIlia Diachkov .addMBB(PrevI->getOperand(1).getMBB()) 3702eab7d363SIlia Diachkov .addMBB(I.getOperand(0).getMBB()) 3703eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 3704eab7d363SIlia Diachkov } 3705eab7d363SIlia Diachkov return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranch)) 3706eab7d363SIlia Diachkov .addMBB(I.getOperand(0).getMBB()) 3707eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 3708eab7d363SIlia Diachkov } 3709eab7d363SIlia Diachkov 3710eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectBranchCond(MachineInstr &I) const { 3711eab7d363SIlia Diachkov // InstructionSelector walks backwards through the instructions. For an 3712eab7d363SIlia Diachkov // explicit conditional branch with no fallthrough, we use both a G_BR and a 3713eab7d363SIlia Diachkov // G_BRCOND to create an OpBranchConditional. We should hit G_BR first, and 3714eab7d363SIlia Diachkov // generate the OpBranchConditional in selectBranch above. 3715eab7d363SIlia Diachkov // 3716eab7d363SIlia Diachkov // If an OpBranchConditional has been generated, we simply return, as the work 3717eab7d363SIlia Diachkov // is alread done. If there is no OpBranchConditional, LLVM must be relying on 3718eab7d363SIlia Diachkov // implicit fallthrough to the next basic block, so we need to create an 3719eab7d363SIlia Diachkov // OpBranchConditional with an explicit "false" argument pointing to the next 3720eab7d363SIlia Diachkov // basic block that LLVM would fall through to. 3721eab7d363SIlia Diachkov const MachineInstr *NextI = I.getNextNode(); 3722eab7d363SIlia Diachkov // Check if this has already been successfully selected. 3723eab7d363SIlia Diachkov if (NextI != nullptr && NextI->getOpcode() == SPIRV::OpBranchConditional) 3724eab7d363SIlia Diachkov return true; 3725eab7d363SIlia Diachkov // Must be relying on implicit block fallthrough, so generate an 3726eab7d363SIlia Diachkov // OpBranchConditional with the "next" basic block as the "false" target. 3727eab7d363SIlia Diachkov MachineBasicBlock &MBB = *I.getParent(); 3728eab7d363SIlia Diachkov unsigned NextMBBNum = MBB.getNextNode()->getNumber(); 3729eab7d363SIlia Diachkov MachineBasicBlock *NextMBB = I.getMF()->getBlockNumbered(NextMBBNum); 3730eab7d363SIlia Diachkov return BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpBranchConditional)) 3731eab7d363SIlia Diachkov .addUse(I.getOperand(0).getReg()) 3732eab7d363SIlia Diachkov .addMBB(I.getOperand(1).getMBB()) 3733eab7d363SIlia Diachkov .addMBB(NextMBB) 3734eab7d363SIlia Diachkov .constrainAllUses(TII, TRI, RBI); 3735eab7d363SIlia Diachkov } 3736eab7d363SIlia Diachkov 3737eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectPhi(Register ResVReg, 3738eab7d363SIlia Diachkov const SPIRVType *ResType, 3739eab7d363SIlia Diachkov MachineInstr &I) const { 3740eab7d363SIlia Diachkov auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpPhi)) 3741eab7d363SIlia Diachkov .addDef(ResVReg) 3742eab7d363SIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)); 3743eab7d363SIlia Diachkov const unsigned NumOps = I.getNumOperands(); 3744eab7d363SIlia Diachkov for (unsigned i = 1; i < NumOps; i += 2) { 3745eab7d363SIlia Diachkov MIB.addUse(I.getOperand(i + 0).getReg()); 3746eab7d363SIlia Diachkov MIB.addMBB(I.getOperand(i + 1).getMBB()); 3747eab7d363SIlia Diachkov } 374842633cf2SVyacheslav Levytskyy bool Res = MIB.constrainAllUses(TII, TRI, RBI); 374942633cf2SVyacheslav Levytskyy MIB->setDesc(TII.get(TargetOpcode::PHI)); 375042633cf2SVyacheslav Levytskyy MIB->removeOperand(1); 375142633cf2SVyacheslav Levytskyy return Res; 3752eab7d363SIlia Diachkov } 3753eab7d363SIlia Diachkov 3754eab7d363SIlia Diachkov bool SPIRVInstructionSelector::selectGlobalValue( 3755eab7d363SIlia Diachkov Register ResVReg, MachineInstr &I, const MachineInstr *Init) const { 3756eab7d363SIlia Diachkov // FIXME: don't use MachineIRBuilder here, replace it with BuildMI. 3757eab7d363SIlia Diachkov MachineIRBuilder MIRBuilder(I); 3758eab7d363SIlia Diachkov const GlobalValue *GV = I.getOperand(1).getGlobal(); 3759dbd00a59SVyacheslav Levytskyy Type *GVType = toTypedPointer(GR.getDeducedGlobalValueType(GV)); 3760ec7baca1SMichal Paszkowski SPIRVType *PointerBaseType; 3761ec7baca1SMichal Paszkowski if (GVType->isArrayTy()) { 3762ec7baca1SMichal Paszkowski SPIRVType *ArrayElementType = 3763ec7baca1SMichal Paszkowski GR.getOrCreateSPIRVType(GVType->getArrayElementType(), MIRBuilder, 3764ec7baca1SMichal Paszkowski SPIRV::AccessQualifier::ReadWrite, false); 3765ec7baca1SMichal Paszkowski PointerBaseType = GR.getOrCreateSPIRVArrayType( 3766ec7baca1SMichal Paszkowski ArrayElementType, GVType->getArrayNumElements(), I, TII); 3767ec7baca1SMichal Paszkowski } else { 3768ec7baca1SMichal Paszkowski PointerBaseType = GR.getOrCreateSPIRVType( 3769ec7baca1SMichal Paszkowski GVType, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false); 3770ec7baca1SMichal Paszkowski } 3771b9d62310SVyacheslav Levytskyy 3772b9d62310SVyacheslav Levytskyy std::string GlobalIdent; 3773b9d62310SVyacheslav Levytskyy if (!GV->hasName()) { 3774b9d62310SVyacheslav Levytskyy unsigned &ID = UnnamedGlobalIDs[GV]; 3775b9d62310SVyacheslav Levytskyy if (ID == 0) 3776b9d62310SVyacheslav Levytskyy ID = UnnamedGlobalIDs.size(); 3777b9d62310SVyacheslav Levytskyy GlobalIdent = "__unnamed_" + Twine(ID).str(); 3778b9d62310SVyacheslav Levytskyy } else { 3779a774e7f7SVyacheslav Levytskyy GlobalIdent = GV->getName(); 3780b9d62310SVyacheslav Levytskyy } 3781b9d62310SVyacheslav Levytskyy 3782d153ef6aSVyacheslav Levytskyy // Behaviour of functions as operands depends on availability of the 3783d153ef6aSVyacheslav Levytskyy // corresponding extension (SPV_INTEL_function_pointers): 3784d153ef6aSVyacheslav Levytskyy // - If there is an extension to operate with functions as operands: 3785d153ef6aSVyacheslav Levytskyy // We create a proper constant operand and evaluate a correct type for a 3786d153ef6aSVyacheslav Levytskyy // function pointer. 3787d153ef6aSVyacheslav Levytskyy // - Without the required extension: 3788b8e1544bSIlia Diachkov // We have functions as operands in tests with blocks of instruction e.g. in 3789b8e1544bSIlia Diachkov // transcoding/global_block.ll. These operands are not used and should be 3790b8e1544bSIlia Diachkov // substituted by zero constants. Their type is expected to be always 3791b8e1544bSIlia Diachkov // OpTypePointer Function %uchar. 3792b8e1544bSIlia Diachkov if (isa<Function>(GV)) { 3793b8e1544bSIlia Diachkov const Constant *ConstVal = GV; 3794b8e1544bSIlia Diachkov MachineBasicBlock &BB = *I.getParent(); 3795b8e1544bSIlia Diachkov Register NewReg = GR.find(ConstVal, GR.CurMF); 3796b8e1544bSIlia Diachkov if (!NewReg.isValid()) { 3797b8e1544bSIlia Diachkov Register NewReg = ResVReg; 3798b8e1544bSIlia Diachkov GR.add(ConstVal, GR.CurMF, NewReg); 3799d153ef6aSVyacheslav Levytskyy const Function *GVFun = 3800d153ef6aSVyacheslav Levytskyy STI.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers) 3801d153ef6aSVyacheslav Levytskyy ? dyn_cast<Function>(GV) 3802d153ef6aSVyacheslav Levytskyy : nullptr; 380386b69c31SVyacheslav Levytskyy SPIRVType *ResType = GR.getOrCreateSPIRVPointerType( 380486b69c31SVyacheslav Levytskyy PointerBaseType, I, TII, 380586b69c31SVyacheslav Levytskyy GVFun ? SPIRV::StorageClass::CodeSectionINTEL 380686b69c31SVyacheslav Levytskyy : addressSpaceToStorageClass(GV->getAddressSpace(), STI)); 3807d153ef6aSVyacheslav Levytskyy if (GVFun) { 3808d153ef6aSVyacheslav Levytskyy // References to a function via function pointers generate virtual 3809d153ef6aSVyacheslav Levytskyy // registers without a definition. We will resolve it later, during 3810d153ef6aSVyacheslav Levytskyy // module analysis stage. 381183c1d003SVyacheslav Levytskyy Register ResTypeReg = GR.getSPIRVTypeID(ResType); 3812d153ef6aSVyacheslav Levytskyy MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 381383c1d003SVyacheslav Levytskyy Register FuncVReg = 381483c1d003SVyacheslav Levytskyy MRI->createGenericVirtualRegister(GR.getRegType(ResType)); 381583c1d003SVyacheslav Levytskyy MRI->setRegClass(FuncVReg, &SPIRV::pIDRegClass); 381683c1d003SVyacheslav Levytskyy MachineInstrBuilder MIB1 = 381783c1d003SVyacheslav Levytskyy BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpUndef)) 381883c1d003SVyacheslav Levytskyy .addDef(FuncVReg) 381983c1d003SVyacheslav Levytskyy .addUse(ResTypeReg); 382083c1d003SVyacheslav Levytskyy MachineInstrBuilder MIB2 = 3821d153ef6aSVyacheslav Levytskyy BuildMI(BB, I, I.getDebugLoc(), 3822d153ef6aSVyacheslav Levytskyy TII.get(SPIRV::OpConstantFunctionPointerINTEL)) 3823d153ef6aSVyacheslav Levytskyy .addDef(NewReg) 382483c1d003SVyacheslav Levytskyy .addUse(ResTypeReg) 3825d153ef6aSVyacheslav Levytskyy .addUse(FuncVReg); 3826d153ef6aSVyacheslav Levytskyy // mapping the function pointer to the used Function 382783c1d003SVyacheslav Levytskyy GR.recordFunctionPointer(&MIB2.getInstr()->getOperand(2), GVFun); 382883c1d003SVyacheslav Levytskyy return MIB1.constrainAllUses(TII, TRI, RBI) && 382983c1d003SVyacheslav Levytskyy MIB2.constrainAllUses(TII, TRI, RBI); 3830d153ef6aSVyacheslav Levytskyy } 3831b8e1544bSIlia Diachkov return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull)) 3832b8e1544bSIlia Diachkov .addDef(NewReg) 3833b8e1544bSIlia Diachkov .addUse(GR.getSPIRVTypeID(ResType)) 3834b8e1544bSIlia Diachkov .constrainAllUses(TII, TRI, RBI); 3835b8e1544bSIlia Diachkov } 3836b8e1544bSIlia Diachkov assert(NewReg != ResVReg); 383742633cf2SVyacheslav Levytskyy return BuildCOPY(ResVReg, NewReg, I); 3838b8e1544bSIlia Diachkov } 3839eab7d363SIlia Diachkov auto GlobalVar = cast<GlobalVariable>(GV); 3840b8e1544bSIlia Diachkov assert(GlobalVar->getName() != "llvm.global.annotations"); 3841eab7d363SIlia Diachkov 3842a774e7f7SVyacheslav Levytskyy // Skip empty declaration for GVs with initializers till we get the decl with 3843eab7d363SIlia Diachkov // passed initializer. 3844a774e7f7SVyacheslav Levytskyy if (hasInitializer(GlobalVar) && !Init) 3845eab7d363SIlia Diachkov return true; 3846eab7d363SIlia Diachkov 3847a774e7f7SVyacheslav Levytskyy bool HasLnkTy = !GV->hasInternalLinkage() && !GV->hasPrivateLinkage(); 3848b25b507cSIlia Diachkov SPIRV::LinkageType::LinkageType LnkType = 3849a774e7f7SVyacheslav Levytskyy GV->isDeclarationForLinker() 3850eab7d363SIlia Diachkov ? SPIRV::LinkageType::Import 3851a774e7f7SVyacheslav Levytskyy : (GV->hasLinkOnceODRLinkage() && 38529552a396SVyacheslav Levytskyy STI.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr) 38539552a396SVyacheslav Levytskyy ? SPIRV::LinkageType::LinkOnceODR 38549552a396SVyacheslav Levytskyy : SPIRV::LinkageType::Export); 3855eab7d363SIlia Diachkov 38565f99eb9bSNathan Gauër const unsigned AddrSpace = GV->getAddressSpace(); 38575f99eb9bSNathan Gauër SPIRV::StorageClass::StorageClass StorageClass = 38585f99eb9bSNathan Gauër addressSpaceToStorageClass(AddrSpace, STI); 38595f99eb9bSNathan Gauër SPIRVType *ResType = 38605f99eb9bSNathan Gauër GR.getOrCreateSPIRVPointerType(PointerBaseType, I, TII, StorageClass); 38615f99eb9bSNathan Gauër Register Reg = GR.buildGlobalVariable( 38625f99eb9bSNathan Gauër ResVReg, ResType, GlobalIdent, GV, StorageClass, Init, 38635f99eb9bSNathan Gauër GlobalVar->isConstant(), HasLnkTy, LnkType, MIRBuilder, true); 3864eab7d363SIlia Diachkov return Reg.isValid(); 3865eab7d363SIlia Diachkov } 3866eab7d363SIlia Diachkov 38670a2aaab5SNatalie Chouinard bool SPIRVInstructionSelector::selectLog10(Register ResVReg, 38680a2aaab5SNatalie Chouinard const SPIRVType *ResType, 38690a2aaab5SNatalie Chouinard MachineInstr &I) const { 38700a2aaab5SNatalie Chouinard if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) { 38710a2aaab5SNatalie Chouinard return selectExtInst(ResVReg, ResType, I, CL::log10); 38720a2aaab5SNatalie Chouinard } 38730a2aaab5SNatalie Chouinard 38740a2aaab5SNatalie Chouinard // There is no log10 instruction in the GLSL Extended Instruction set, so it 38750a2aaab5SNatalie Chouinard // is implemented as: 38760a2aaab5SNatalie Chouinard // log10(x) = log2(x) * (1 / log2(10)) 38770a2aaab5SNatalie Chouinard // = log2(x) * 0.30103 38780a2aaab5SNatalie Chouinard 38790a2aaab5SNatalie Chouinard MachineIRBuilder MIRBuilder(I); 38800a2aaab5SNatalie Chouinard MachineBasicBlock &BB = *I.getParent(); 38810a2aaab5SNatalie Chouinard 38820a2aaab5SNatalie Chouinard // Build log2(x). 388367d3ef74SVyacheslav Levytskyy Register VarReg = MRI->createVirtualRegister(GR.getRegClass(ResType)); 38840a2aaab5SNatalie Chouinard bool Result = 38850a2aaab5SNatalie Chouinard BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) 38860a2aaab5SNatalie Chouinard .addDef(VarReg) 38870a2aaab5SNatalie Chouinard .addUse(GR.getSPIRVTypeID(ResType)) 38880a2aaab5SNatalie Chouinard .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450)) 38890a2aaab5SNatalie Chouinard .addImm(GL::Log2) 38900a2aaab5SNatalie Chouinard .add(I.getOperand(1)) 38910a2aaab5SNatalie Chouinard .constrainAllUses(TII, TRI, RBI); 38920a2aaab5SNatalie Chouinard 38930a2aaab5SNatalie Chouinard // Build 0.30103. 38940a2aaab5SNatalie Chouinard assert(ResType->getOpcode() == SPIRV::OpTypeVector || 38950a2aaab5SNatalie Chouinard ResType->getOpcode() == SPIRV::OpTypeFloat); 38960a2aaab5SNatalie Chouinard // TODO: Add matrix implementation once supported by the HLSL frontend. 38970a2aaab5SNatalie Chouinard const SPIRVType *SpirvScalarType = 38980a2aaab5SNatalie Chouinard ResType->getOpcode() == SPIRV::OpTypeVector 38990a2aaab5SNatalie Chouinard ? GR.getSPIRVTypeForVReg(ResType->getOperand(1).getReg()) 39000a2aaab5SNatalie Chouinard : ResType; 39010a2aaab5SNatalie Chouinard Register ScaleReg = 39020a2aaab5SNatalie Chouinard GR.buildConstantFP(APFloat(0.30103f), MIRBuilder, SpirvScalarType); 39030a2aaab5SNatalie Chouinard 39040a2aaab5SNatalie Chouinard // Multiply log2(x) by 0.30103 to get log10(x) result. 39050a2aaab5SNatalie Chouinard auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector 39060a2aaab5SNatalie Chouinard ? SPIRV::OpVectorTimesScalar 39070a2aaab5SNatalie Chouinard : SPIRV::OpFMulS; 3908a93cbd4eSFinn Plummer return Result && BuildMI(BB, I, I.getDebugLoc(), TII.get(Opcode)) 39090a2aaab5SNatalie Chouinard .addDef(ResVReg) 39100a2aaab5SNatalie Chouinard .addUse(GR.getSPIRVTypeID(ResType)) 39110a2aaab5SNatalie Chouinard .addUse(VarReg) 39120a2aaab5SNatalie Chouinard .addUse(ScaleReg) 39130a2aaab5SNatalie Chouinard .constrainAllUses(TII, TRI, RBI); 39140a2aaab5SNatalie Chouinard } 39150a2aaab5SNatalie Chouinard 3916951a284fSZhengxing li // Generate the instructions to load 3-element vector builtin input 3917951a284fSZhengxing li // IDs/Indices. 3918951a284fSZhengxing li // Like: GlobalInvocationId, LocalInvocationId, etc.... 3919951a284fSZhengxing li bool SPIRVInstructionSelector::loadVec3BuiltinInputID( 3920951a284fSZhengxing li SPIRV::BuiltIn::BuiltIn BuiltInValue, Register ResVReg, 3921951a284fSZhengxing li const SPIRVType *ResType, MachineInstr &I) const { 39226325dd57SNatalie Chouinard MachineIRBuilder MIRBuilder(I); 39236325dd57SNatalie Chouinard const SPIRVType *U32Type = GR.getOrCreateSPIRVIntegerType(32, MIRBuilder); 39246325dd57SNatalie Chouinard const SPIRVType *Vec3Ty = 39256325dd57SNatalie Chouinard GR.getOrCreateSPIRVVectorType(U32Type, 3, MIRBuilder); 39266325dd57SNatalie Chouinard const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType( 39276325dd57SNatalie Chouinard Vec3Ty, MIRBuilder, SPIRV::StorageClass::Input); 39286325dd57SNatalie Chouinard 3929951a284fSZhengxing li // Create new register for the input ID builtin variable. 39306325dd57SNatalie Chouinard Register NewRegister = 3931f9c98068SVyacheslav Levytskyy MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass); 393267d3ef74SVyacheslav Levytskyy MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 64)); 39336325dd57SNatalie Chouinard GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF()); 39346325dd57SNatalie Chouinard 3935951a284fSZhengxing li // Build global variable with the necessary decorations for the input ID 3936951a284fSZhengxing li // builtin variable. 39376325dd57SNatalie Chouinard Register Variable = GR.buildGlobalVariable( 3938951a284fSZhengxing li NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr, 39396325dd57SNatalie Chouinard SPIRV::StorageClass::Input, nullptr, true, true, 39406325dd57SNatalie Chouinard SPIRV::LinkageType::Import, MIRBuilder, false); 39416325dd57SNatalie Chouinard 39426325dd57SNatalie Chouinard // Create new register for loading value. 39436325dd57SNatalie Chouinard MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 3944f9c98068SVyacheslav Levytskyy Register LoadedRegister = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 394567d3ef74SVyacheslav Levytskyy MIRBuilder.getMRI()->setType(LoadedRegister, LLT::pointer(0, 64)); 39466325dd57SNatalie Chouinard GR.assignSPIRVTypeToVReg(Vec3Ty, LoadedRegister, MIRBuilder.getMF()); 39476325dd57SNatalie Chouinard 39486325dd57SNatalie Chouinard // Load v3uint value from the global variable. 3949a93cbd4eSFinn Plummer bool Result = 39506325dd57SNatalie Chouinard BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad)) 39516325dd57SNatalie Chouinard .addDef(LoadedRegister) 39526325dd57SNatalie Chouinard .addUse(GR.getSPIRVTypeID(Vec3Ty)) 39536325dd57SNatalie Chouinard .addUse(Variable); 39546325dd57SNatalie Chouinard 3955951a284fSZhengxing li // Get the input ID index. Expecting operand is a constant immediate value, 39566325dd57SNatalie Chouinard // wrapped in a type assignment. 39576325dd57SNatalie Chouinard assert(I.getOperand(2).isReg()); 39585af7ae50SSteven Perron const uint32_t ThreadId = foldImm(I.getOperand(2), MRI); 39596325dd57SNatalie Chouinard 3960951a284fSZhengxing li // Extract the input ID from the loaded vector value. 39616325dd57SNatalie Chouinard MachineBasicBlock &BB = *I.getParent(); 39626325dd57SNatalie Chouinard auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract)) 39636325dd57SNatalie Chouinard .addDef(ResVReg) 39646325dd57SNatalie Chouinard .addUse(GR.getSPIRVTypeID(ResType)) 39656325dd57SNatalie Chouinard .addUse(LoadedRegister) 39666325dd57SNatalie Chouinard .addImm(ThreadId); 3967a93cbd4eSFinn Plummer return Result && MIB.constrainAllUses(TII, TRI, RBI); 39686325dd57SNatalie Chouinard } 39696325dd57SNatalie Chouinard 3970ba572abeSSteven Perron SPIRVType *SPIRVInstructionSelector::widenTypeToVec4(const SPIRVType *Type, 3971ba572abeSSteven Perron MachineInstr &I) const { 3972ba572abeSSteven Perron MachineIRBuilder MIRBuilder(I); 3973ba572abeSSteven Perron if (Type->getOpcode() != SPIRV::OpTypeVector) 3974ba572abeSSteven Perron return GR.getOrCreateSPIRVVectorType(Type, 4, MIRBuilder); 3975ba572abeSSteven Perron 3976ba572abeSSteven Perron uint64_t VectorSize = Type->getOperand(2).getImm(); 3977ba572abeSSteven Perron if (VectorSize == 4) 3978ba572abeSSteven Perron return Type; 3979ba572abeSSteven Perron 3980ba572abeSSteven Perron Register ScalarTypeReg = Type->getOperand(1).getReg(); 3981ba572abeSSteven Perron const SPIRVType *ScalarType = GR.getSPIRVTypeForVReg(ScalarTypeReg); 3982ba572abeSSteven Perron return GR.getOrCreateSPIRVVectorType(ScalarType, 4, MIRBuilder); 3983ba572abeSSteven Perron } 3984ba572abeSSteven Perron 39854b692a95SSteven Perron bool SPIRVInstructionSelector::loadHandleBeforePosition( 39864b692a95SSteven Perron Register &HandleReg, const SPIRVType *ResType, GIntrinsic &HandleDef, 39874b692a95SSteven Perron MachineInstr &Pos) const { 39884b692a95SSteven Perron 39894b692a95SSteven Perron assert(HandleDef.getIntrinsicID() == 39904b692a95SSteven Perron Intrinsic::spv_resource_handlefrombinding); 39914b692a95SSteven Perron uint32_t Set = foldImm(HandleDef.getOperand(2), MRI); 39924b692a95SSteven Perron uint32_t Binding = foldImm(HandleDef.getOperand(3), MRI); 39934b692a95SSteven Perron uint32_t ArraySize = foldImm(HandleDef.getOperand(4), MRI); 39944b692a95SSteven Perron Register IndexReg = HandleDef.getOperand(5).getReg(); 39954b692a95SSteven Perron bool IsNonUniform = ArraySize > 1 && foldImm(HandleDef.getOperand(6), MRI); 39964b692a95SSteven Perron 39974b692a95SSteven Perron MachineIRBuilder MIRBuilder(HandleDef); 39984b692a95SSteven Perron Register VarReg = buildPointerToResource(ResType, Set, Binding, ArraySize, 39994b692a95SSteven Perron IndexReg, IsNonUniform, MIRBuilder); 40004b692a95SSteven Perron 40014b692a95SSteven Perron if (IsNonUniform) 40024b692a95SSteven Perron buildOpDecorate(HandleReg, HandleDef, TII, SPIRV::Decoration::NonUniformEXT, 40034b692a95SSteven Perron {}); 40044b692a95SSteven Perron 40054b692a95SSteven Perron // TODO: For now we assume the resource is an image, which needs to be 40064b692a95SSteven Perron // loaded to get the handle. That will not be true for storage buffers. 40074b692a95SSteven Perron return BuildMI(*Pos.getParent(), Pos, HandleDef.getDebugLoc(), 40084b692a95SSteven Perron TII.get(SPIRV::OpLoad)) 40094b692a95SSteven Perron .addDef(HandleReg) 40104b692a95SSteven Perron .addUse(GR.getSPIRVTypeID(ResType)) 40114b692a95SSteven Perron .addUse(VarReg) 40124b692a95SSteven Perron .constrainAllUses(TII, TRI, RBI); 40134b692a95SSteven Perron } 40144b692a95SSteven Perron 4015eab7d363SIlia Diachkov namespace llvm { 4016eab7d363SIlia Diachkov InstructionSelector * 4017eab7d363SIlia Diachkov createSPIRVInstructionSelector(const SPIRVTargetMachine &TM, 4018eab7d363SIlia Diachkov const SPIRVSubtarget &Subtarget, 4019eab7d363SIlia Diachkov const RegisterBankInfo &RBI) { 4020eab7d363SIlia Diachkov return new SPIRVInstructionSelector(TM, Subtarget, RBI); 4021eab7d363SIlia Diachkov } 4022eab7d363SIlia Diachkov } // namespace llvm 4023