xref: /llvm-project/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp (revision b5132b7d044a5bc83eba9b09bd158cd77a511403)
1ec259036SIlia Diachkov //===- SPIRVISelLowering.cpp - SPIR-V DAG Lowering Impl ---------*- C++ -*-===//
2ec259036SIlia Diachkov //
3ec259036SIlia Diachkov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ec259036SIlia Diachkov // See https://llvm.org/LICENSE.txt for license information.
5ec259036SIlia Diachkov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ec259036SIlia Diachkov //
7ec259036SIlia Diachkov //===----------------------------------------------------------------------===//
8ec259036SIlia Diachkov //
9ec259036SIlia Diachkov // This file implements the SPIRVTargetLowering class.
10ec259036SIlia Diachkov //
11ec259036SIlia Diachkov //===----------------------------------------------------------------------===//
12ec259036SIlia Diachkov 
13ec259036SIlia Diachkov #include "SPIRVISelLowering.h"
14ec259036SIlia Diachkov #include "SPIRV.h"
15fb1be9b3SVyacheslav Levytskyy #include "SPIRVInstrInfo.h"
16fb1be9b3SVyacheslav Levytskyy #include "SPIRVRegisterBankInfo.h"
17fb1be9b3SVyacheslav Levytskyy #include "SPIRVRegisterInfo.h"
18fb1be9b3SVyacheslav Levytskyy #include "SPIRVSubtarget.h"
19fb1be9b3SVyacheslav Levytskyy #include "SPIRVTargetMachine.h"
20fb1be9b3SVyacheslav Levytskyy #include "llvm/CodeGen/MachineInstrBuilder.h"
21fb1be9b3SVyacheslav Levytskyy #include "llvm/CodeGen/MachineRegisterInfo.h"
223544d200SIlia Diachkov #include "llvm/IR/IntrinsicsSPIRV.h"
23ec259036SIlia Diachkov 
24ec259036SIlia Diachkov #define DEBUG_TYPE "spirv-lower"
25ec259036SIlia Diachkov 
26ec259036SIlia Diachkov using namespace llvm;
27ec259036SIlia Diachkov 
28ec259036SIlia Diachkov unsigned SPIRVTargetLowering::getNumRegistersForCallingConv(
29ec259036SIlia Diachkov     LLVMContext &Context, CallingConv::ID CC, EVT VT) const {
30ec259036SIlia Diachkov   // This code avoids CallLowering fail inside getVectorTypeBreakdown
31ec259036SIlia Diachkov   // on v3i1 arguments. Maybe we need to return 1 for all types.
32ec259036SIlia Diachkov   // TODO: remove it once this case is supported by the default implementation.
33ec259036SIlia Diachkov   if (VT.isVector() && VT.getVectorNumElements() == 3 &&
34ec259036SIlia Diachkov       (VT.getVectorElementType() == MVT::i1 ||
35ec259036SIlia Diachkov        VT.getVectorElementType() == MVT::i8))
36ec259036SIlia Diachkov     return 1;
37dc4330a9SMichal Paszkowski   if (!VT.isVector() && VT.isInteger() && VT.getSizeInBits() <= 64)
38dc4330a9SMichal Paszkowski     return 1;
39ec259036SIlia Diachkov   return getNumRegisters(Context, VT);
40ec259036SIlia Diachkov }
41ec259036SIlia Diachkov 
42ec259036SIlia Diachkov MVT SPIRVTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
43ec259036SIlia Diachkov                                                        CallingConv::ID CC,
44ec259036SIlia Diachkov                                                        EVT VT) const {
45ec259036SIlia Diachkov   // This code avoids CallLowering fail inside getVectorTypeBreakdown
46ec259036SIlia Diachkov   // on v3i1 arguments. Maybe we need to return i32 for all types.
47ec259036SIlia Diachkov   // TODO: remove it once this case is supported by the default implementation.
48ec259036SIlia Diachkov   if (VT.isVector() && VT.getVectorNumElements() == 3) {
49ec259036SIlia Diachkov     if (VT.getVectorElementType() == MVT::i1)
50ec259036SIlia Diachkov       return MVT::v4i1;
51ec259036SIlia Diachkov     else if (VT.getVectorElementType() == MVT::i8)
52ec259036SIlia Diachkov       return MVT::v4i8;
53ec259036SIlia Diachkov   }
54ec259036SIlia Diachkov   return getRegisterType(Context, VT);
55ec259036SIlia Diachkov }
563544d200SIlia Diachkov 
573544d200SIlia Diachkov bool SPIRVTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
583544d200SIlia Diachkov                                              const CallInst &I,
593544d200SIlia Diachkov                                              MachineFunction &MF,
603544d200SIlia Diachkov                                              unsigned Intrinsic) const {
613544d200SIlia Diachkov   unsigned AlignIdx = 3;
623544d200SIlia Diachkov   switch (Intrinsic) {
633544d200SIlia Diachkov   case Intrinsic::spv_load:
643544d200SIlia Diachkov     AlignIdx = 2;
656006d43eSCraig Topper     [[fallthrough]];
663544d200SIlia Diachkov   case Intrinsic::spv_store: {
673544d200SIlia Diachkov     if (I.getNumOperands() >= AlignIdx + 1) {
683544d200SIlia Diachkov       auto *AlignOp = cast<ConstantInt>(I.getOperand(AlignIdx));
693544d200SIlia Diachkov       Info.align = Align(AlignOp->getZExtValue());
703544d200SIlia Diachkov     }
713544d200SIlia Diachkov     Info.flags = static_cast<MachineMemOperand::Flags>(
723544d200SIlia Diachkov         cast<ConstantInt>(I.getOperand(AlignIdx - 1))->getZExtValue());
733544d200SIlia Diachkov     Info.memVT = MVT::i64;
743544d200SIlia Diachkov     // TODO: take into account opaque pointers (don't use getElementType).
753544d200SIlia Diachkov     // MVT::getVT(PtrTy->getElementType());
763544d200SIlia Diachkov     return true;
773544d200SIlia Diachkov     break;
783544d200SIlia Diachkov   }
793544d200SIlia Diachkov   default:
803544d200SIlia Diachkov     break;
813544d200SIlia Diachkov   }
823544d200SIlia Diachkov   return false;
833544d200SIlia Diachkov }
84fb1be9b3SVyacheslav Levytskyy 
85214e6b40SVyacheslav Levytskyy std::pair<unsigned, const TargetRegisterClass *>
86214e6b40SVyacheslav Levytskyy SPIRVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
87214e6b40SVyacheslav Levytskyy                                                   StringRef Constraint,
88214e6b40SVyacheslav Levytskyy                                                   MVT VT) const {
89214e6b40SVyacheslav Levytskyy   const TargetRegisterClass *RC = nullptr;
90214e6b40SVyacheslav Levytskyy   if (Constraint.starts_with("{"))
91214e6b40SVyacheslav Levytskyy     return std::make_pair(0u, RC);
92214e6b40SVyacheslav Levytskyy 
93214e6b40SVyacheslav Levytskyy   if (VT.isFloatingPoint())
9467d3ef74SVyacheslav Levytskyy     RC = VT.isVector() ? &SPIRV::vfIDRegClass : &SPIRV::fIDRegClass;
95214e6b40SVyacheslav Levytskyy   else if (VT.isInteger())
9667d3ef74SVyacheslav Levytskyy     RC = VT.isVector() ? &SPIRV::vIDRegClass : &SPIRV::iIDRegClass;
97214e6b40SVyacheslav Levytskyy   else
98f9c98068SVyacheslav Levytskyy     RC = &SPIRV::iIDRegClass;
99214e6b40SVyacheslav Levytskyy 
100214e6b40SVyacheslav Levytskyy   return std::make_pair(0u, RC);
101214e6b40SVyacheslav Levytskyy }
102214e6b40SVyacheslav Levytskyy 
103ce73e17eSVyacheslav Levytskyy inline Register getTypeReg(MachineRegisterInfo *MRI, Register OpReg) {
104ce73e17eSVyacheslav Levytskyy   SPIRVType *TypeInst = MRI->getVRegDef(OpReg);
105ce73e17eSVyacheslav Levytskyy   return TypeInst && TypeInst->getOpcode() == SPIRV::OpFunctionParameter
106ce73e17eSVyacheslav Levytskyy              ? TypeInst->getOperand(1).getReg()
107ce73e17eSVyacheslav Levytskyy              : OpReg;
108ce73e17eSVyacheslav Levytskyy }
109ce73e17eSVyacheslav Levytskyy 
110ce73e17eSVyacheslav Levytskyy static void doInsertBitcast(const SPIRVSubtarget &STI, MachineRegisterInfo *MRI,
111ce73e17eSVyacheslav Levytskyy                             SPIRVGlobalRegistry &GR, MachineInstr &I,
112ce73e17eSVyacheslav Levytskyy                             Register OpReg, unsigned OpIdx,
113ce73e17eSVyacheslav Levytskyy                             SPIRVType *NewPtrType) {
114ce73e17eSVyacheslav Levytskyy   MachineIRBuilder MIB(I);
115*b5132b7dSVyacheslav Levytskyy   Register NewReg = createVirtualRegister(NewPtrType, &GR, MRI, MIB.getMF());
116ce73e17eSVyacheslav Levytskyy   bool Res = MIB.buildInstr(SPIRV::OpBitcast)
117ce73e17eSVyacheslav Levytskyy                  .addDef(NewReg)
118ce73e17eSVyacheslav Levytskyy                  .addUse(GR.getSPIRVTypeID(NewPtrType))
119ce73e17eSVyacheslav Levytskyy                  .addUse(OpReg)
120ce73e17eSVyacheslav Levytskyy                  .constrainAllUses(*STI.getInstrInfo(), *STI.getRegisterInfo(),
121ce73e17eSVyacheslav Levytskyy                                    *STI.getRegBankInfo());
122ce73e17eSVyacheslav Levytskyy   if (!Res)
123ce73e17eSVyacheslav Levytskyy     report_fatal_error("insert validation bitcast: cannot constrain all uses");
124ce73e17eSVyacheslav Levytskyy   I.getOperand(OpIdx).setReg(NewReg);
125ce73e17eSVyacheslav Levytskyy }
126ce73e17eSVyacheslav Levytskyy 
127ce73e17eSVyacheslav Levytskyy static SPIRVType *createNewPtrType(SPIRVGlobalRegistry &GR, MachineInstr &I,
128ce73e17eSVyacheslav Levytskyy                                    SPIRVType *OpType, bool ReuseType,
129ce73e17eSVyacheslav Levytskyy                                    bool EmitIR, SPIRVType *ResType,
130ce73e17eSVyacheslav Levytskyy                                    const Type *ResTy) {
131ce73e17eSVyacheslav Levytskyy   SPIRV::StorageClass::StorageClass SC =
132ce73e17eSVyacheslav Levytskyy       static_cast<SPIRV::StorageClass::StorageClass>(
133ce73e17eSVyacheslav Levytskyy           OpType->getOperand(1).getImm());
134ce73e17eSVyacheslav Levytskyy   MachineIRBuilder MIB(I);
135ce73e17eSVyacheslav Levytskyy   SPIRVType *NewBaseType =
136ce73e17eSVyacheslav Levytskyy       ReuseType ? ResType
137ce73e17eSVyacheslav Levytskyy                 : GR.getOrCreateSPIRVType(
138ce73e17eSVyacheslav Levytskyy                       ResTy, MIB, SPIRV::AccessQualifier::ReadWrite, EmitIR);
139ce73e17eSVyacheslav Levytskyy   return GR.getOrCreateSPIRVPointerType(NewBaseType, MIB, SC);
140ce73e17eSVyacheslav Levytskyy }
141ce73e17eSVyacheslav Levytskyy 
142fb1be9b3SVyacheslav Levytskyy // Insert a bitcast before the instruction to keep SPIR-V code valid
143fb1be9b3SVyacheslav Levytskyy // when there is a type mismatch between results and operand types.
144fb1be9b3SVyacheslav Levytskyy static void validatePtrTypes(const SPIRVSubtarget &STI,
145fb1be9b3SVyacheslav Levytskyy                              MachineRegisterInfo *MRI, SPIRVGlobalRegistry &GR,
146b7ac8fddSVyacheslav Levytskyy                              MachineInstr &I, unsigned OpIdx,
147b7ac8fddSVyacheslav Levytskyy                              SPIRVType *ResType, const Type *ResTy = nullptr) {
148f7680835SVyacheslav Levytskyy   // Get operand type
149f7680835SVyacheslav Levytskyy   MachineFunction *MF = I.getParent()->getParent();
150fb1be9b3SVyacheslav Levytskyy   Register OpReg = I.getOperand(OpIdx).getReg();
151ce73e17eSVyacheslav Levytskyy   Register OpTypeReg = getTypeReg(MRI, OpReg);
152f7680835SVyacheslav Levytskyy   SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpTypeReg, MF);
153fb1be9b3SVyacheslav Levytskyy   if (!ResType || !OpType || OpType->getOpcode() != SPIRV::OpTypePointer)
154fb1be9b3SVyacheslav Levytskyy     return;
155f7680835SVyacheslav Levytskyy   // Get operand's pointee type
156f7680835SVyacheslav Levytskyy   Register ElemTypeReg = OpType->getOperand(2).getReg();
157f7680835SVyacheslav Levytskyy   SPIRVType *ElemType = GR.getSPIRVTypeForVReg(ElemTypeReg, MF);
158b7ac8fddSVyacheslav Levytskyy   if (!ElemType)
159b7ac8fddSVyacheslav Levytskyy     return;
160f7680835SVyacheslav Levytskyy   // Check if we need a bitcast to make a statement valid
161f7680835SVyacheslav Levytskyy   bool IsSameMF = MF == ResType->getParent()->getParent();
162b7ac8fddSVyacheslav Levytskyy   bool IsEqualTypes = IsSameMF ? ElemType == ResType
163b7ac8fddSVyacheslav Levytskyy                                : GR.getTypeForSPIRVType(ElemType) == ResTy;
164b7ac8fddSVyacheslav Levytskyy   if (IsEqualTypes)
165fb1be9b3SVyacheslav Levytskyy     return;
166fb1be9b3SVyacheslav Levytskyy   // There is a type mismatch between results and operand types
167fb1be9b3SVyacheslav Levytskyy   // and we insert a bitcast before the instruction to keep SPIR-V code valid
168ce73e17eSVyacheslav Levytskyy   SPIRVType *NewPtrType =
169ce73e17eSVyacheslav Levytskyy       createNewPtrType(GR, I, OpType, IsSameMF, false, ResType, ResTy);
170fb1be9b3SVyacheslav Levytskyy   if (!GR.isBitcastCompatible(NewPtrType, OpType))
171fb1be9b3SVyacheslav Levytskyy     report_fatal_error(
172fb1be9b3SVyacheslav Levytskyy         "insert validation bitcast: incompatible result and operand types");
173ce73e17eSVyacheslav Levytskyy   doInsertBitcast(STI, MRI, GR, I, OpReg, OpIdx, NewPtrType);
174ce73e17eSVyacheslav Levytskyy }
175ce73e17eSVyacheslav Levytskyy 
176ce73e17eSVyacheslav Levytskyy // Insert a bitcast before OpGroupWaitEvents if the last argument is a pointer
177ce73e17eSVyacheslav Levytskyy // that doesn't point to OpTypeEvent.
178ce73e17eSVyacheslav Levytskyy static void validateGroupWaitEventsPtr(const SPIRVSubtarget &STI,
179ce73e17eSVyacheslav Levytskyy                                        MachineRegisterInfo *MRI,
180ce73e17eSVyacheslav Levytskyy                                        SPIRVGlobalRegistry &GR,
181ce73e17eSVyacheslav Levytskyy                                        MachineInstr &I) {
182ce73e17eSVyacheslav Levytskyy   constexpr unsigned OpIdx = 2;
183ce73e17eSVyacheslav Levytskyy   MachineFunction *MF = I.getParent()->getParent();
184ce73e17eSVyacheslav Levytskyy   Register OpReg = I.getOperand(OpIdx).getReg();
185ce73e17eSVyacheslav Levytskyy   Register OpTypeReg = getTypeReg(MRI, OpReg);
186ce73e17eSVyacheslav Levytskyy   SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpTypeReg, MF);
187ce73e17eSVyacheslav Levytskyy   if (!OpType || OpType->getOpcode() != SPIRV::OpTypePointer)
188ce73e17eSVyacheslav Levytskyy     return;
189ce73e17eSVyacheslav Levytskyy   SPIRVType *ElemType = GR.getSPIRVTypeForVReg(OpType->getOperand(2).getReg());
190ce73e17eSVyacheslav Levytskyy   if (!ElemType || ElemType->getOpcode() == SPIRV::OpTypeEvent)
191ce73e17eSVyacheslav Levytskyy     return;
192ce73e17eSVyacheslav Levytskyy   // Insert a bitcast before the instruction to keep SPIR-V code valid.
1930f0cfcffSMatt Arsenault   LLVMContext &Context = MF->getFunction().getContext();
194ce73e17eSVyacheslav Levytskyy   SPIRVType *NewPtrType =
195ce73e17eSVyacheslav Levytskyy       createNewPtrType(GR, I, OpType, false, true, nullptr,
196ce73e17eSVyacheslav Levytskyy                        TargetExtType::get(Context, "spirv.Event"));
197ce73e17eSVyacheslav Levytskyy   doInsertBitcast(STI, MRI, GR, I, OpReg, OpIdx, NewPtrType);
198fb1be9b3SVyacheslav Levytskyy }
199fb1be9b3SVyacheslav Levytskyy 
200281f59fdSVyacheslav Levytskyy static void validateLifetimeStart(const SPIRVSubtarget &STI,
201281f59fdSVyacheslav Levytskyy                                   MachineRegisterInfo *MRI,
202281f59fdSVyacheslav Levytskyy                                   SPIRVGlobalRegistry &GR, MachineInstr &I) {
203281f59fdSVyacheslav Levytskyy   Register PtrReg = I.getOperand(0).getReg();
204281f59fdSVyacheslav Levytskyy   MachineFunction *MF = I.getParent()->getParent();
205281f59fdSVyacheslav Levytskyy   Register PtrTypeReg = getTypeReg(MRI, PtrReg);
206281f59fdSVyacheslav Levytskyy   SPIRVType *PtrType = GR.getSPIRVTypeForVReg(PtrTypeReg, MF);
207281f59fdSVyacheslav Levytskyy   SPIRVType *PonteeElemType = PtrType ? GR.getPointeeType(PtrType) : nullptr;
208281f59fdSVyacheslav Levytskyy   if (!PonteeElemType || PonteeElemType->getOpcode() == SPIRV::OpTypeVoid ||
209281f59fdSVyacheslav Levytskyy       (PonteeElemType->getOpcode() == SPIRV::OpTypeInt &&
210281f59fdSVyacheslav Levytskyy        PonteeElemType->getOperand(1).getImm() == 8))
211281f59fdSVyacheslav Levytskyy     return;
212281f59fdSVyacheslav Levytskyy   // To keep the code valid a bitcast must be inserted
213281f59fdSVyacheslav Levytskyy   SPIRV::StorageClass::StorageClass SC =
214281f59fdSVyacheslav Levytskyy       static_cast<SPIRV::StorageClass::StorageClass>(
215281f59fdSVyacheslav Levytskyy           PtrType->getOperand(1).getImm());
216281f59fdSVyacheslav Levytskyy   MachineIRBuilder MIB(I);
217281f59fdSVyacheslav Levytskyy   LLVMContext &Context = MF->getFunction().getContext();
218281f59fdSVyacheslav Levytskyy   SPIRVType *ElemType =
219281f59fdSVyacheslav Levytskyy       GR.getOrCreateSPIRVType(IntegerType::getInt8Ty(Context), MIB);
220281f59fdSVyacheslav Levytskyy   SPIRVType *NewPtrType = GR.getOrCreateSPIRVPointerType(ElemType, MIB, SC);
221281f59fdSVyacheslav Levytskyy   doInsertBitcast(STI, MRI, GR, I, PtrReg, 0, NewPtrType);
222281f59fdSVyacheslav Levytskyy }
223281f59fdSVyacheslav Levytskyy 
2245a062191SVyacheslav Levytskyy static void validatePtrUnwrapStructField(const SPIRVSubtarget &STI,
225bf9e9e5eSVyacheslav Levytskyy                                          MachineRegisterInfo *MRI,
2265a062191SVyacheslav Levytskyy                                          SPIRVGlobalRegistry &GR,
2275a062191SVyacheslav Levytskyy                                          MachineInstr &I, unsigned OpIdx) {
228bf9e9e5eSVyacheslav Levytskyy   MachineFunction *MF = I.getParent()->getParent();
229bf9e9e5eSVyacheslav Levytskyy   Register OpReg = I.getOperand(OpIdx).getReg();
230bf9e9e5eSVyacheslav Levytskyy   Register OpTypeReg = getTypeReg(MRI, OpReg);
231bf9e9e5eSVyacheslav Levytskyy   SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpTypeReg, MF);
232bf9e9e5eSVyacheslav Levytskyy   if (!OpType || OpType->getOpcode() != SPIRV::OpTypePointer)
233bf9e9e5eSVyacheslav Levytskyy     return;
234bf9e9e5eSVyacheslav Levytskyy   SPIRVType *ElemType = GR.getSPIRVTypeForVReg(OpType->getOperand(2).getReg());
235bf9e9e5eSVyacheslav Levytskyy   if (!ElemType || ElemType->getOpcode() != SPIRV::OpTypeStruct ||
236bf9e9e5eSVyacheslav Levytskyy       ElemType->getNumOperands() != 2)
237bf9e9e5eSVyacheslav Levytskyy     return;
238bf9e9e5eSVyacheslav Levytskyy   // It's a structure-wrapper around another type with a single member field.
239bf9e9e5eSVyacheslav Levytskyy   SPIRVType *MemberType =
240bf9e9e5eSVyacheslav Levytskyy       GR.getSPIRVTypeForVReg(ElemType->getOperand(1).getReg());
241bf9e9e5eSVyacheslav Levytskyy   if (!MemberType)
242bf9e9e5eSVyacheslav Levytskyy     return;
243bf9e9e5eSVyacheslav Levytskyy   unsigned MemberTypeOp = MemberType->getOpcode();
244bf9e9e5eSVyacheslav Levytskyy   if (MemberTypeOp != SPIRV::OpTypeVector && MemberTypeOp != SPIRV::OpTypeInt &&
245bf9e9e5eSVyacheslav Levytskyy       MemberTypeOp != SPIRV::OpTypeFloat && MemberTypeOp != SPIRV::OpTypeBool)
246bf9e9e5eSVyacheslav Levytskyy     return;
247bf9e9e5eSVyacheslav Levytskyy   // It's a structure-wrapper around a valid type. Insert a bitcast before the
248bf9e9e5eSVyacheslav Levytskyy   // instruction to keep SPIR-V code valid.
249bf9e9e5eSVyacheslav Levytskyy   SPIRV::StorageClass::StorageClass SC =
250bf9e9e5eSVyacheslav Levytskyy       static_cast<SPIRV::StorageClass::StorageClass>(
251bf9e9e5eSVyacheslav Levytskyy           OpType->getOperand(1).getImm());
252bf9e9e5eSVyacheslav Levytskyy   MachineIRBuilder MIB(I);
253bf9e9e5eSVyacheslav Levytskyy   SPIRVType *NewPtrType = GR.getOrCreateSPIRVPointerType(MemberType, MIB, SC);
254bf9e9e5eSVyacheslav Levytskyy   doInsertBitcast(STI, MRI, GR, I, OpReg, OpIdx, NewPtrType);
255bf9e9e5eSVyacheslav Levytskyy }
256bf9e9e5eSVyacheslav Levytskyy 
257b7ac8fddSVyacheslav Levytskyy // Insert a bitcast before the function call instruction to keep SPIR-V code
258b7ac8fddSVyacheslav Levytskyy // valid when there is a type mismatch between actual and expected types of an
259b7ac8fddSVyacheslav Levytskyy // argument:
260b7ac8fddSVyacheslav Levytskyy // %formal = OpFunctionParameter %formal_type
261b7ac8fddSVyacheslav Levytskyy // ...
262b7ac8fddSVyacheslav Levytskyy // %res = OpFunctionCall %ty %fun %actual ...
263b7ac8fddSVyacheslav Levytskyy // implies that %actual is of %formal_type, and in case of opaque pointers.
264b7ac8fddSVyacheslav Levytskyy // We may need to insert a bitcast to ensure this.
265b7ac8fddSVyacheslav Levytskyy void validateFunCallMachineDef(const SPIRVSubtarget &STI,
266b7ac8fddSVyacheslav Levytskyy                                MachineRegisterInfo *DefMRI,
267b7ac8fddSVyacheslav Levytskyy                                MachineRegisterInfo *CallMRI,
268b7ac8fddSVyacheslav Levytskyy                                SPIRVGlobalRegistry &GR, MachineInstr &FunCall,
269b7ac8fddSVyacheslav Levytskyy                                MachineInstr *FunDef) {
270b7ac8fddSVyacheslav Levytskyy   if (FunDef->getOpcode() != SPIRV::OpFunction)
271b7ac8fddSVyacheslav Levytskyy     return;
272b7ac8fddSVyacheslav Levytskyy   unsigned OpIdx = 3;
273b7ac8fddSVyacheslav Levytskyy   for (FunDef = FunDef->getNextNode();
274b7ac8fddSVyacheslav Levytskyy        FunDef && FunDef->getOpcode() == SPIRV::OpFunctionParameter &&
275b7ac8fddSVyacheslav Levytskyy        OpIdx < FunCall.getNumOperands();
276b7ac8fddSVyacheslav Levytskyy        FunDef = FunDef->getNextNode(), OpIdx++) {
277b7ac8fddSVyacheslav Levytskyy     SPIRVType *DefPtrType = DefMRI->getVRegDef(FunDef->getOperand(1).getReg());
278b7ac8fddSVyacheslav Levytskyy     SPIRVType *DefElemType =
279b7ac8fddSVyacheslav Levytskyy         DefPtrType && DefPtrType->getOpcode() == SPIRV::OpTypePointer
280f7680835SVyacheslav Levytskyy             ? GR.getSPIRVTypeForVReg(DefPtrType->getOperand(2).getReg(),
281f7680835SVyacheslav Levytskyy                                      DefPtrType->getParent()->getParent())
282b7ac8fddSVyacheslav Levytskyy             : nullptr;
283b7ac8fddSVyacheslav Levytskyy     if (DefElemType) {
284b7ac8fddSVyacheslav Levytskyy       const Type *DefElemTy = GR.getTypeForSPIRVType(DefElemType);
28523b058cbSVyacheslav Levytskyy       // validatePtrTypes() works in the context if the call site
28623b058cbSVyacheslav Levytskyy       // When we process historical records about forward calls
28723b058cbSVyacheslav Levytskyy       // we need to switch context to the (forward) call site and
28823b058cbSVyacheslav Levytskyy       // then restore it back to the current machine function.
28923b058cbSVyacheslav Levytskyy       MachineFunction *CurMF =
290b7ac8fddSVyacheslav Levytskyy           GR.setCurrentFunc(*FunCall.getParent()->getParent());
291b7ac8fddSVyacheslav Levytskyy       validatePtrTypes(STI, CallMRI, GR, FunCall, OpIdx, DefElemType,
292b7ac8fddSVyacheslav Levytskyy                        DefElemTy);
29323b058cbSVyacheslav Levytskyy       GR.setCurrentFunc(*CurMF);
294b7ac8fddSVyacheslav Levytskyy     }
295b7ac8fddSVyacheslav Levytskyy   }
296b7ac8fddSVyacheslav Levytskyy }
297b7ac8fddSVyacheslav Levytskyy 
298b7ac8fddSVyacheslav Levytskyy // Ensure there is no mismatch between actual and expected arg types: calls
299b7ac8fddSVyacheslav Levytskyy // with a processed definition. Return Function pointer if it's a forward
300b7ac8fddSVyacheslav Levytskyy // call (ahead of definition), and nullptr otherwise.
301b7ac8fddSVyacheslav Levytskyy const Function *validateFunCall(const SPIRVSubtarget &STI,
302f7680835SVyacheslav Levytskyy                                 MachineRegisterInfo *CallMRI,
303b7ac8fddSVyacheslav Levytskyy                                 SPIRVGlobalRegistry &GR,
304b7ac8fddSVyacheslav Levytskyy                                 MachineInstr &FunCall) {
305b7ac8fddSVyacheslav Levytskyy   const GlobalValue *GV = FunCall.getOperand(2).getGlobal();
306b7ac8fddSVyacheslav Levytskyy   const Function *F = dyn_cast<Function>(GV);
307b7ac8fddSVyacheslav Levytskyy   MachineInstr *FunDef =
308b7ac8fddSVyacheslav Levytskyy       const_cast<MachineInstr *>(GR.getFunctionDefinition(F));
309b7ac8fddSVyacheslav Levytskyy   if (!FunDef)
310b7ac8fddSVyacheslav Levytskyy     return F;
311f7680835SVyacheslav Levytskyy   MachineRegisterInfo *DefMRI = &FunDef->getParent()->getParent()->getRegInfo();
312f7680835SVyacheslav Levytskyy   validateFunCallMachineDef(STI, DefMRI, CallMRI, GR, FunCall, FunDef);
313b7ac8fddSVyacheslav Levytskyy   return nullptr;
314b7ac8fddSVyacheslav Levytskyy }
315b7ac8fddSVyacheslav Levytskyy 
316b7ac8fddSVyacheslav Levytskyy // Ensure there is no mismatch between actual and expected arg types: calls
317b7ac8fddSVyacheslav Levytskyy // ahead of a processed definition.
318b7ac8fddSVyacheslav Levytskyy void validateForwardCalls(const SPIRVSubtarget &STI,
319b7ac8fddSVyacheslav Levytskyy                           MachineRegisterInfo *DefMRI, SPIRVGlobalRegistry &GR,
320b7ac8fddSVyacheslav Levytskyy                           MachineInstr &FunDef) {
321b7ac8fddSVyacheslav Levytskyy   const Function *F = GR.getFunctionByDefinition(&FunDef);
32247e996d8SVyacheslav Levytskyy   if (SmallPtrSet<MachineInstr *, 8> *FwdCalls = GR.getForwardCalls(F))
323b7ac8fddSVyacheslav Levytskyy     for (MachineInstr *FunCall : *FwdCalls) {
324b7ac8fddSVyacheslav Levytskyy       MachineRegisterInfo *CallMRI =
325b7ac8fddSVyacheslav Levytskyy           &FunCall->getParent()->getParent()->getRegInfo();
326b7ac8fddSVyacheslav Levytskyy       validateFunCallMachineDef(STI, DefMRI, CallMRI, GR, *FunCall, &FunDef);
327b7ac8fddSVyacheslav Levytskyy     }
328b7ac8fddSVyacheslav Levytskyy }
329b7ac8fddSVyacheslav Levytskyy 
3306cce67a8SVyacheslav Levytskyy // Validation of an access chain.
3316cce67a8SVyacheslav Levytskyy void validateAccessChain(const SPIRVSubtarget &STI, MachineRegisterInfo *MRI,
3326cce67a8SVyacheslav Levytskyy                          SPIRVGlobalRegistry &GR, MachineInstr &I) {
3336cce67a8SVyacheslav Levytskyy   SPIRVType *BaseTypeInst = GR.getSPIRVTypeForVReg(I.getOperand(0).getReg());
3346cce67a8SVyacheslav Levytskyy   if (BaseTypeInst && BaseTypeInst->getOpcode() == SPIRV::OpTypePointer) {
3356cce67a8SVyacheslav Levytskyy     SPIRVType *BaseElemType =
3366cce67a8SVyacheslav Levytskyy         GR.getSPIRVTypeForVReg(BaseTypeInst->getOperand(2).getReg());
3376cce67a8SVyacheslav Levytskyy     validatePtrTypes(STI, MRI, GR, I, 2, BaseElemType);
3386cce67a8SVyacheslav Levytskyy   }
3396cce67a8SVyacheslav Levytskyy }
3406cce67a8SVyacheslav Levytskyy 
341fb1be9b3SVyacheslav Levytskyy // TODO: the logic of inserting additional bitcast's is to be moved
342fb1be9b3SVyacheslav Levytskyy // to pre-IRTranslation passes eventually
343fb1be9b3SVyacheslav Levytskyy void SPIRVTargetLowering::finalizeLowering(MachineFunction &MF) const {
34423b058cbSVyacheslav Levytskyy   // finalizeLowering() is called twice (see GlobalISel/InstructionSelect.cpp)
34523b058cbSVyacheslav Levytskyy   // We'd like to avoid the needless second processing pass.
34623b058cbSVyacheslav Levytskyy   if (ProcessedMF.find(&MF) != ProcessedMF.end())
34723b058cbSVyacheslav Levytskyy     return;
34823b058cbSVyacheslav Levytskyy 
349fb1be9b3SVyacheslav Levytskyy   MachineRegisterInfo *MRI = &MF.getRegInfo();
350fb1be9b3SVyacheslav Levytskyy   SPIRVGlobalRegistry &GR = *STI.getSPIRVGlobalRegistry();
351fb1be9b3SVyacheslav Levytskyy   GR.setCurrentFunc(MF);
352fb1be9b3SVyacheslav Levytskyy   for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) {
353fb1be9b3SVyacheslav Levytskyy     MachineBasicBlock *MBB = &*I;
354ebdadcfeSVyacheslav Levytskyy     SmallPtrSet<MachineInstr *, 8> ToMove;
355fb1be9b3SVyacheslav Levytskyy     for (MachineBasicBlock::iterator MBBI = MBB->begin(), MBBE = MBB->end();
356fb1be9b3SVyacheslav Levytskyy          MBBI != MBBE;) {
357fb1be9b3SVyacheslav Levytskyy       MachineInstr &MI = *MBBI++;
358fb1be9b3SVyacheslav Levytskyy       switch (MI.getOpcode()) {
3596cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicLoad:
3606cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicExchange:
3616cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicCompareExchange:
3626cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicCompareExchangeWeak:
3636cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicIIncrement:
3646cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicIDecrement:
3656cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicIAdd:
3666cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicISub:
3676cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicSMin:
3686cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicUMin:
3696cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicSMax:
3706cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicUMax:
3716cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicAnd:
3726cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicOr:
3736cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicXor:
3746cce67a8SVyacheslav Levytskyy         // for the above listed instructions
3756cce67a8SVyacheslav Levytskyy         // OpAtomicXXX <ResType>, ptr %Op, ...
3766cce67a8SVyacheslav Levytskyy         // implies that %Op is a pointer to <ResType>
377fb1be9b3SVyacheslav Levytskyy       case SPIRV::OpLoad:
378fb1be9b3SVyacheslav Levytskyy         // OpLoad <ResType>, ptr %Op implies that %Op is a pointer to <ResType>
379b7ac8fddSVyacheslav Levytskyy         validatePtrTypes(STI, MRI, GR, MI, 2,
380b7ac8fddSVyacheslav Levytskyy                          GR.getSPIRVTypeForVReg(MI.getOperand(0).getReg()));
381fb1be9b3SVyacheslav Levytskyy         break;
3826cce67a8SVyacheslav Levytskyy       case SPIRV::OpAtomicStore:
3836cce67a8SVyacheslav Levytskyy         // OpAtomicStore ptr %Op, <Scope>, <Mem>, <Obj>
3846cce67a8SVyacheslav Levytskyy         // implies that %Op points to the <Obj>'s type
3856cce67a8SVyacheslav Levytskyy         validatePtrTypes(STI, MRI, GR, MI, 0,
3866cce67a8SVyacheslav Levytskyy                          GR.getSPIRVTypeForVReg(MI.getOperand(3).getReg()));
3876cce67a8SVyacheslav Levytskyy         break;
388fb1be9b3SVyacheslav Levytskyy       case SPIRV::OpStore:
389fb1be9b3SVyacheslav Levytskyy         // OpStore ptr %Op, <Obj> implies that %Op points to the <Obj>'s type
390b7ac8fddSVyacheslav Levytskyy         validatePtrTypes(STI, MRI, GR, MI, 0,
391b7ac8fddSVyacheslav Levytskyy                          GR.getSPIRVTypeForVReg(MI.getOperand(1).getReg()));
392fb1be9b3SVyacheslav Levytskyy         break;
3936cce67a8SVyacheslav Levytskyy       case SPIRV::OpPtrCastToGeneric:
39457520985SVyacheslav Levytskyy       case SPIRV::OpGenericCastToPtr:
3956cce67a8SVyacheslav Levytskyy         validateAccessChain(STI, MRI, GR, MI);
3966cce67a8SVyacheslav Levytskyy         break;
397*b5132b7dSVyacheslav Levytskyy       case SPIRV::OpPtrAccessChain:
3986cce67a8SVyacheslav Levytskyy       case SPIRV::OpInBoundsPtrAccessChain:
3996cce67a8SVyacheslav Levytskyy         if (MI.getNumOperands() == 4)
4006cce67a8SVyacheslav Levytskyy           validateAccessChain(STI, MRI, GR, MI);
4016cce67a8SVyacheslav Levytskyy         break;
402b7ac8fddSVyacheslav Levytskyy 
403b7ac8fddSVyacheslav Levytskyy       case SPIRV::OpFunctionCall:
404b7ac8fddSVyacheslav Levytskyy         // ensure there is no mismatch between actual and expected arg types:
405b7ac8fddSVyacheslav Levytskyy         // calls with a processed definition
406b7ac8fddSVyacheslav Levytskyy         if (MI.getNumOperands() > 3)
407b7ac8fddSVyacheslav Levytskyy           if (const Function *F = validateFunCall(STI, MRI, GR, MI))
408b7ac8fddSVyacheslav Levytskyy             GR.addForwardCall(F, &MI);
409b7ac8fddSVyacheslav Levytskyy         break;
410b7ac8fddSVyacheslav Levytskyy       case SPIRV::OpFunction:
411b7ac8fddSVyacheslav Levytskyy         // ensure there is no mismatch between actual and expected arg types:
412b7ac8fddSVyacheslav Levytskyy         // calls ahead of a processed definition
413b7ac8fddSVyacheslav Levytskyy         validateForwardCalls(STI, MRI, GR, MI);
414b7ac8fddSVyacheslav Levytskyy         break;
415b7ac8fddSVyacheslav Levytskyy 
4168ac46d6bSVyacheslav Levytskyy       // ensure that LLVM IR add/sub instructions result in logical SPIR-V
4178ac46d6bSVyacheslav Levytskyy       // instructions when applied to bool type
4188ac46d6bSVyacheslav Levytskyy       case SPIRV::OpIAddS:
4198ac46d6bSVyacheslav Levytskyy       case SPIRV::OpIAddV:
4208ac46d6bSVyacheslav Levytskyy       case SPIRV::OpISubS:
4218ac46d6bSVyacheslav Levytskyy       case SPIRV::OpISubV:
4228ac46d6bSVyacheslav Levytskyy         if (GR.isScalarOrVectorOfType(MI.getOperand(1).getReg(),
4238ac46d6bSVyacheslav Levytskyy                                       SPIRV::OpTypeBool))
4248ac46d6bSVyacheslav Levytskyy           MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalNotEqual));
4258ac46d6bSVyacheslav Levytskyy         break;
4268ac46d6bSVyacheslav Levytskyy 
427949d70d5SVyacheslav Levytskyy       // ensure that LLVM IR bitwise instructions result in logical SPIR-V
428949d70d5SVyacheslav Levytskyy       // instructions when applied to bool type
429949d70d5SVyacheslav Levytskyy       case SPIRV::OpBitwiseOrS:
430949d70d5SVyacheslav Levytskyy       case SPIRV::OpBitwiseOrV:
431949d70d5SVyacheslav Levytskyy         if (GR.isScalarOrVectorOfType(MI.getOperand(1).getReg(),
432949d70d5SVyacheslav Levytskyy                                       SPIRV::OpTypeBool))
433949d70d5SVyacheslav Levytskyy           MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalOr));
434949d70d5SVyacheslav Levytskyy         break;
435949d70d5SVyacheslav Levytskyy       case SPIRV::OpBitwiseAndS:
436949d70d5SVyacheslav Levytskyy       case SPIRV::OpBitwiseAndV:
437949d70d5SVyacheslav Levytskyy         if (GR.isScalarOrVectorOfType(MI.getOperand(1).getReg(),
438949d70d5SVyacheslav Levytskyy                                       SPIRV::OpTypeBool))
439949d70d5SVyacheslav Levytskyy           MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalAnd));
440949d70d5SVyacheslav Levytskyy         break;
441949d70d5SVyacheslav Levytskyy       case SPIRV::OpBitwiseXorS:
442949d70d5SVyacheslav Levytskyy       case SPIRV::OpBitwiseXorV:
443949d70d5SVyacheslav Levytskyy         if (GR.isScalarOrVectorOfType(MI.getOperand(1).getReg(),
444949d70d5SVyacheslav Levytskyy                                       SPIRV::OpTypeBool))
445949d70d5SVyacheslav Levytskyy           MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalNotEqual));
446949d70d5SVyacheslav Levytskyy         break;
447281f59fdSVyacheslav Levytskyy       case SPIRV::OpLifetimeStart:
448281f59fdSVyacheslav Levytskyy       case SPIRV::OpLifetimeStop:
449281f59fdSVyacheslav Levytskyy         if (MI.getOperand(1).getImm() > 0)
450281f59fdSVyacheslav Levytskyy           validateLifetimeStart(STI, MRI, GR, MI);
451281f59fdSVyacheslav Levytskyy         break;
452bf9e9e5eSVyacheslav Levytskyy       case SPIRV::OpGroupAsyncCopy:
4535a062191SVyacheslav Levytskyy         validatePtrUnwrapStructField(STI, MRI, GR, MI, 3);
4545a062191SVyacheslav Levytskyy         validatePtrUnwrapStructField(STI, MRI, GR, MI, 4);
455bf9e9e5eSVyacheslav Levytskyy         break;
456ce73e17eSVyacheslav Levytskyy       case SPIRV::OpGroupWaitEvents:
457ce73e17eSVyacheslav Levytskyy         // OpGroupWaitEvents ..., ..., <pointer to OpTypeEvent>
458ce73e17eSVyacheslav Levytskyy         validateGroupWaitEventsPtr(STI, MRI, GR, MI);
459ce73e17eSVyacheslav Levytskyy         break;
4601ed1ec9aSVyacheslav Levytskyy       case SPIRV::OpConstantI: {
4611ed1ec9aSVyacheslav Levytskyy         SPIRVType *Type = GR.getSPIRVTypeForVReg(MI.getOperand(1).getReg());
4621ed1ec9aSVyacheslav Levytskyy         if (Type->getOpcode() != SPIRV::OpTypeInt && MI.getOperand(2).isImm() &&
4631ed1ec9aSVyacheslav Levytskyy             MI.getOperand(2).getImm() == 0) {
4641ed1ec9aSVyacheslav Levytskyy           // Validate the null constant of a target extension type
4651ed1ec9aSVyacheslav Levytskyy           MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpConstantNull));
4661ed1ec9aSVyacheslav Levytskyy           for (unsigned i = MI.getNumOperands() - 1; i > 1; --i)
4671ed1ec9aSVyacheslav Levytskyy             MI.removeOperand(i);
4681ed1ec9aSVyacheslav Levytskyy         }
4691ed1ec9aSVyacheslav Levytskyy       } break;
470ebdadcfeSVyacheslav Levytskyy       case SPIRV::OpPhi: {
471ebdadcfeSVyacheslav Levytskyy         // Phi refers to a type definition that goes after the Phi
472ebdadcfeSVyacheslav Levytskyy         // instruction, so that the virtual register definition of the type
473ebdadcfeSVyacheslav Levytskyy         // doesn't dominate all uses. Let's place the type definition
474ebdadcfeSVyacheslav Levytskyy         // instruction at the end of the predecessor.
475ebdadcfeSVyacheslav Levytskyy         MachineBasicBlock *Curr = MI.getParent();
476ebdadcfeSVyacheslav Levytskyy         SPIRVType *Type = GR.getSPIRVTypeForVReg(MI.getOperand(1).getReg());
477ebdadcfeSVyacheslav Levytskyy         if (Type->getParent() == Curr && !Curr->pred_empty())
478ebdadcfeSVyacheslav Levytskyy           ToMove.insert(const_cast<MachineInstr *>(Type));
479ebdadcfeSVyacheslav Levytskyy       } break;
4805a062191SVyacheslav Levytskyy       case SPIRV::OpExtInst: {
4815a062191SVyacheslav Levytskyy         // prefetch
4825a062191SVyacheslav Levytskyy         if (!MI.getOperand(2).isImm() || !MI.getOperand(3).isImm() ||
4835a062191SVyacheslav Levytskyy             MI.getOperand(2).getImm() != SPIRV::InstructionSet::OpenCL_std)
4845a062191SVyacheslav Levytskyy           continue;
4855a062191SVyacheslav Levytskyy         switch (MI.getOperand(3).getImm()) {
4868ac46d6bSVyacheslav Levytskyy         case SPIRV::OpenCLExtInst::frexp:
4878ac46d6bSVyacheslav Levytskyy         case SPIRV::OpenCLExtInst::lgamma_r:
4885a062191SVyacheslav Levytskyy         case SPIRV::OpenCLExtInst::remquo: {
4898ac46d6bSVyacheslav Levytskyy           // The last operand must be of a pointer to i32 or vector of i32
4908ac46d6bSVyacheslav Levytskyy           // values.
4915a062191SVyacheslav Levytskyy           MachineIRBuilder MIB(MI);
4925a062191SVyacheslav Levytskyy           SPIRVType *Int32Type = GR.getOrCreateSPIRVIntegerType(32, MIB);
4935a062191SVyacheslav Levytskyy           SPIRVType *RetType = MRI->getVRegDef(MI.getOperand(1).getReg());
4945a062191SVyacheslav Levytskyy           assert(RetType && "Expected return type");
4955a062191SVyacheslav Levytskyy           validatePtrTypes(
4965a062191SVyacheslav Levytskyy               STI, MRI, GR, MI, MI.getNumOperands() - 1,
4975a062191SVyacheslav Levytskyy               RetType->getOpcode() != SPIRV::OpTypeVector
4985a062191SVyacheslav Levytskyy                   ? Int32Type
4995a062191SVyacheslav Levytskyy                   : GR.getOrCreateSPIRVVectorType(
5005a062191SVyacheslav Levytskyy                         Int32Type, RetType->getOperand(2).getImm(), MIB));
5015a062191SVyacheslav Levytskyy         } break;
5025a062191SVyacheslav Levytskyy         case SPIRV::OpenCLExtInst::fract:
5035a062191SVyacheslav Levytskyy         case SPIRV::OpenCLExtInst::modf:
5045a062191SVyacheslav Levytskyy         case SPIRV::OpenCLExtInst::sincos:
5055a062191SVyacheslav Levytskyy           // The last operand must be of a pointer to the base type represented
5065a062191SVyacheslav Levytskyy           // by the previous operand.
5075a062191SVyacheslav Levytskyy           assert(MI.getOperand(MI.getNumOperands() - 2).isReg() &&
5085a062191SVyacheslav Levytskyy                  "Expected v-reg");
5095a062191SVyacheslav Levytskyy           validatePtrTypes(
5105a062191SVyacheslav Levytskyy               STI, MRI, GR, MI, MI.getNumOperands() - 1,
5115a062191SVyacheslav Levytskyy               GR.getSPIRVTypeForVReg(
5125a062191SVyacheslav Levytskyy                   MI.getOperand(MI.getNumOperands() - 2).getReg()));
5135a062191SVyacheslav Levytskyy           break;
5145a062191SVyacheslav Levytskyy         case SPIRV::OpenCLExtInst::prefetch:
5155a062191SVyacheslav Levytskyy           // Expected `ptr` type is a pointer to float, integer or vector, but
5165a062191SVyacheslav Levytskyy           // the pontee value can be wrapped into a struct.
5175a062191SVyacheslav Levytskyy           assert(MI.getOperand(MI.getNumOperands() - 2).isReg() &&
5185a062191SVyacheslav Levytskyy                  "Expected v-reg");
5195a062191SVyacheslav Levytskyy           validatePtrUnwrapStructField(STI, MRI, GR, MI,
5205a062191SVyacheslav Levytskyy                                        MI.getNumOperands() - 2);
5215a062191SVyacheslav Levytskyy           break;
5225a062191SVyacheslav Levytskyy         }
5235a062191SVyacheslav Levytskyy       } break;
524fb1be9b3SVyacheslav Levytskyy       }
525fb1be9b3SVyacheslav Levytskyy     }
526ebdadcfeSVyacheslav Levytskyy     for (MachineInstr *MI : ToMove) {
527ebdadcfeSVyacheslav Levytskyy       MachineBasicBlock *Curr = MI->getParent();
528ebdadcfeSVyacheslav Levytskyy       MachineBasicBlock *Pred = *Curr->pred_begin();
529ebdadcfeSVyacheslav Levytskyy       Pred->insert(Pred->getFirstTerminator(), Curr->remove_instr(MI));
530ebdadcfeSVyacheslav Levytskyy     }
531fb1be9b3SVyacheslav Levytskyy   }
53223b058cbSVyacheslav Levytskyy   ProcessedMF.insert(&MF);
533fb1be9b3SVyacheslav Levytskyy   TargetLowering::finalizeLowering(MF);
534fb1be9b3SVyacheslav Levytskyy }
535