xref: /llvm-project/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (revision aab25f20f6c06bab7aac6fb83d54705ec4cdfadd)
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