xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===--- SPIRVCallLowering.cpp - Call lowering ------------------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file implements the lowering of LLVM calls to machine code calls for
1081ad6265SDimitry Andric // GlobalISel.
1181ad6265SDimitry Andric //
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #include "SPIRVCallLowering.h"
1581ad6265SDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h"
1681ad6265SDimitry Andric #include "SPIRV.h"
17bdd1243dSDimitry Andric #include "SPIRVBuiltins.h"
1881ad6265SDimitry Andric #include "SPIRVGlobalRegistry.h"
1981ad6265SDimitry Andric #include "SPIRVISelLowering.h"
20*0fca6ea1SDimitry Andric #include "SPIRVMetadata.h"
2181ad6265SDimitry Andric #include "SPIRVRegisterInfo.h"
2281ad6265SDimitry Andric #include "SPIRVSubtarget.h"
2381ad6265SDimitry Andric #include "SPIRVUtils.h"
2481ad6265SDimitry Andric #include "llvm/CodeGen/FunctionLoweringInfo.h"
25*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
26*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h"
27bdd1243dSDimitry Andric #include "llvm/Support/ModRef.h"
2881ad6265SDimitry Andric 
2981ad6265SDimitry Andric using namespace llvm;
3081ad6265SDimitry Andric 
3181ad6265SDimitry Andric SPIRVCallLowering::SPIRVCallLowering(const SPIRVTargetLowering &TLI,
3281ad6265SDimitry Andric                                      SPIRVGlobalRegistry *GR)
33fcaf7f86SDimitry Andric     : CallLowering(&TLI), GR(GR) {}
3481ad6265SDimitry Andric 
3581ad6265SDimitry Andric bool SPIRVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
3681ad6265SDimitry Andric                                     const Value *Val, ArrayRef<Register> VRegs,
3781ad6265SDimitry Andric                                     FunctionLoweringInfo &FLI,
3881ad6265SDimitry Andric                                     Register SwiftErrorVReg) const {
39*0fca6ea1SDimitry Andric   // Maybe run postponed production of types for function pointers
40*0fca6ea1SDimitry Andric   if (IndirectCalls.size() > 0) {
41*0fca6ea1SDimitry Andric     produceIndirectPtrTypes(MIRBuilder);
42*0fca6ea1SDimitry Andric     IndirectCalls.clear();
43*0fca6ea1SDimitry Andric   }
44*0fca6ea1SDimitry Andric 
4581ad6265SDimitry Andric   // Currently all return types should use a single register.
4681ad6265SDimitry Andric   // TODO: handle the case of multiple registers.
4781ad6265SDimitry Andric   if (VRegs.size() > 1)
4881ad6265SDimitry Andric     return false;
49fcaf7f86SDimitry Andric   if (Val) {
50fcaf7f86SDimitry Andric     const auto &STI = MIRBuilder.getMF().getSubtarget();
5181ad6265SDimitry Andric     return MIRBuilder.buildInstr(SPIRV::OpReturnValue)
5281ad6265SDimitry Andric         .addUse(VRegs[0])
53fcaf7f86SDimitry Andric         .constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
54fcaf7f86SDimitry Andric                           *STI.getRegBankInfo());
55fcaf7f86SDimitry Andric   }
5681ad6265SDimitry Andric   MIRBuilder.buildInstr(SPIRV::OpReturn);
5781ad6265SDimitry Andric   return true;
5881ad6265SDimitry Andric }
5981ad6265SDimitry Andric 
6081ad6265SDimitry Andric // Based on the LLVM function attributes, get a SPIR-V FunctionControl.
6181ad6265SDimitry Andric static uint32_t getFunctionControl(const Function &F) {
62bdd1243dSDimitry Andric   MemoryEffects MemEffects = F.getMemoryEffects();
63bdd1243dSDimitry Andric 
6481ad6265SDimitry Andric   uint32_t FuncControl = static_cast<uint32_t>(SPIRV::FunctionControl::None);
65bdd1243dSDimitry Andric 
66bdd1243dSDimitry Andric   if (F.hasFnAttribute(Attribute::AttrKind::NoInline))
6781ad6265SDimitry Andric     FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::DontInline);
68bdd1243dSDimitry Andric   else if (F.hasFnAttribute(Attribute::AttrKind::AlwaysInline))
69bdd1243dSDimitry Andric     FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Inline);
70bdd1243dSDimitry Andric 
71bdd1243dSDimitry Andric   if (MemEffects.doesNotAccessMemory())
72bdd1243dSDimitry Andric     FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Pure);
73bdd1243dSDimitry Andric   else if (MemEffects.onlyReadsMemory())
74bdd1243dSDimitry Andric     FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Const);
75bdd1243dSDimitry Andric 
7681ad6265SDimitry Andric   return FuncControl;
7781ad6265SDimitry Andric }
7881ad6265SDimitry Andric 
79fcaf7f86SDimitry Andric static ConstantInt *getConstInt(MDNode *MD, unsigned NumOp) {
80fcaf7f86SDimitry Andric   if (MD->getNumOperands() > NumOp) {
81fcaf7f86SDimitry Andric     auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(NumOp));
82fcaf7f86SDimitry Andric     if (CMeta)
83fcaf7f86SDimitry Andric       return dyn_cast<ConstantInt>(CMeta->getValue());
84fcaf7f86SDimitry Andric   }
85fcaf7f86SDimitry Andric   return nullptr;
86fcaf7f86SDimitry Andric }
87fcaf7f86SDimitry Andric 
88*0fca6ea1SDimitry Andric // If the function has pointer arguments, we are forced to re-create this
89*0fca6ea1SDimitry Andric // function type from the very beginning, changing PointerType by
90*0fca6ea1SDimitry Andric // TypedPointerType for each pointer argument. Otherwise, the same `Type*`
91*0fca6ea1SDimitry Andric // potentially corresponds to different SPIR-V function type, effectively
92*0fca6ea1SDimitry Andric // invalidating logic behind global registry and duplicates tracker.
93*0fca6ea1SDimitry Andric static FunctionType *
94*0fca6ea1SDimitry Andric fixFunctionTypeIfPtrArgs(SPIRVGlobalRegistry *GR, const Function &F,
95*0fca6ea1SDimitry Andric                          FunctionType *FTy, const SPIRVType *SRetTy,
96*0fca6ea1SDimitry Andric                          const SmallVector<SPIRVType *, 4> &SArgTys) {
97*0fca6ea1SDimitry Andric   if (F.getParent()->getNamedMetadata("spv.cloned_funcs"))
98*0fca6ea1SDimitry Andric     return FTy;
99*0fca6ea1SDimitry Andric 
100*0fca6ea1SDimitry Andric   bool hasArgPtrs = false;
101*0fca6ea1SDimitry Andric   for (auto &Arg : F.args()) {
102*0fca6ea1SDimitry Andric     // check if it's an instance of a non-typed PointerType
103*0fca6ea1SDimitry Andric     if (Arg.getType()->isPointerTy()) {
104*0fca6ea1SDimitry Andric       hasArgPtrs = true;
105*0fca6ea1SDimitry Andric       break;
106*0fca6ea1SDimitry Andric     }
107*0fca6ea1SDimitry Andric   }
108*0fca6ea1SDimitry Andric   if (!hasArgPtrs) {
109*0fca6ea1SDimitry Andric     Type *RetTy = FTy->getReturnType();
110*0fca6ea1SDimitry Andric     // check if it's an instance of a non-typed PointerType
111*0fca6ea1SDimitry Andric     if (!RetTy->isPointerTy())
112*0fca6ea1SDimitry Andric       return FTy;
113*0fca6ea1SDimitry Andric   }
114*0fca6ea1SDimitry Andric 
115*0fca6ea1SDimitry Andric   // re-create function type, using TypedPointerType instead of PointerType to
116*0fca6ea1SDimitry Andric   // properly trace argument types
117*0fca6ea1SDimitry Andric   const Type *RetTy = GR->getTypeForSPIRVType(SRetTy);
118*0fca6ea1SDimitry Andric   SmallVector<Type *, 4> ArgTys;
119*0fca6ea1SDimitry Andric   for (auto SArgTy : SArgTys)
120*0fca6ea1SDimitry Andric     ArgTys.push_back(const_cast<Type *>(GR->getTypeForSPIRVType(SArgTy)));
121*0fca6ea1SDimitry Andric   return FunctionType::get(const_cast<Type *>(RetTy), ArgTys, false);
122*0fca6ea1SDimitry Andric }
123*0fca6ea1SDimitry Andric 
124fcaf7f86SDimitry Andric // This code restores function args/retvalue types for composite cases
125fcaf7f86SDimitry Andric // because the final types should still be aggregate whereas they're i32
126fcaf7f86SDimitry Andric // during the translation to cope with aggregate flattening etc.
127fcaf7f86SDimitry Andric static FunctionType *getOriginalFunctionType(const Function &F) {
128fcaf7f86SDimitry Andric   auto *NamedMD = F.getParent()->getNamedMetadata("spv.cloned_funcs");
129fcaf7f86SDimitry Andric   if (NamedMD == nullptr)
130fcaf7f86SDimitry Andric     return F.getFunctionType();
131fcaf7f86SDimitry Andric 
132fcaf7f86SDimitry Andric   Type *RetTy = F.getFunctionType()->getReturnType();
133fcaf7f86SDimitry Andric   SmallVector<Type *, 4> ArgTypes;
134fcaf7f86SDimitry Andric   for (auto &Arg : F.args())
135fcaf7f86SDimitry Andric     ArgTypes.push_back(Arg.getType());
136fcaf7f86SDimitry Andric 
137fcaf7f86SDimitry Andric   auto ThisFuncMDIt =
138fcaf7f86SDimitry Andric       std::find_if(NamedMD->op_begin(), NamedMD->op_end(), [&F](MDNode *N) {
139fcaf7f86SDimitry Andric         return isa<MDString>(N->getOperand(0)) &&
140fcaf7f86SDimitry Andric                cast<MDString>(N->getOperand(0))->getString() == F.getName();
141fcaf7f86SDimitry Andric       });
142fcaf7f86SDimitry Andric   // TODO: probably one function can have numerous type mutations,
143fcaf7f86SDimitry Andric   // so we should support this.
144fcaf7f86SDimitry Andric   if (ThisFuncMDIt != NamedMD->op_end()) {
145fcaf7f86SDimitry Andric     auto *ThisFuncMD = *ThisFuncMDIt;
146fcaf7f86SDimitry Andric     MDNode *MD = dyn_cast<MDNode>(ThisFuncMD->getOperand(1));
147fcaf7f86SDimitry Andric     assert(MD && "MDNode operand is expected");
148fcaf7f86SDimitry Andric     ConstantInt *Const = getConstInt(MD, 0);
149fcaf7f86SDimitry Andric     if (Const) {
150fcaf7f86SDimitry Andric       auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(1));
151fcaf7f86SDimitry Andric       assert(CMeta && "ConstantAsMetadata operand is expected");
152fcaf7f86SDimitry Andric       assert(Const->getSExtValue() >= -1);
153fcaf7f86SDimitry Andric       // Currently -1 indicates return value, greater values mean
154fcaf7f86SDimitry Andric       // argument numbers.
155fcaf7f86SDimitry Andric       if (Const->getSExtValue() == -1)
156fcaf7f86SDimitry Andric         RetTy = CMeta->getType();
157fcaf7f86SDimitry Andric       else
158fcaf7f86SDimitry Andric         ArgTypes[Const->getSExtValue()] = CMeta->getType();
159fcaf7f86SDimitry Andric     }
160fcaf7f86SDimitry Andric   }
161fcaf7f86SDimitry Andric 
162fcaf7f86SDimitry Andric   return FunctionType::get(RetTy, ArgTypes, F.isVarArg());
163fcaf7f86SDimitry Andric }
164fcaf7f86SDimitry Andric 
165bdd1243dSDimitry Andric static SPIRV::AccessQualifier::AccessQualifier
166bdd1243dSDimitry Andric getArgAccessQual(const Function &F, unsigned ArgIdx) {
167bdd1243dSDimitry Andric   if (F.getCallingConv() != CallingConv::SPIR_KERNEL)
168bdd1243dSDimitry Andric     return SPIRV::AccessQualifier::ReadWrite;
169bdd1243dSDimitry Andric 
170*0fca6ea1SDimitry Andric   MDString *ArgAttribute = getOCLKernelArgAccessQual(F, ArgIdx);
171bdd1243dSDimitry Andric   if (!ArgAttribute)
172bdd1243dSDimitry Andric     return SPIRV::AccessQualifier::ReadWrite;
173bdd1243dSDimitry Andric 
174*0fca6ea1SDimitry Andric   if (ArgAttribute->getString() == "read_only")
175bdd1243dSDimitry Andric     return SPIRV::AccessQualifier::ReadOnly;
176*0fca6ea1SDimitry Andric   if (ArgAttribute->getString() == "write_only")
177bdd1243dSDimitry Andric     return SPIRV::AccessQualifier::WriteOnly;
178bdd1243dSDimitry Andric   return SPIRV::AccessQualifier::ReadWrite;
179bdd1243dSDimitry Andric }
180bdd1243dSDimitry Andric 
181bdd1243dSDimitry Andric static std::vector<SPIRV::Decoration::Decoration>
182*0fca6ea1SDimitry Andric getKernelArgTypeQual(const Function &F, unsigned ArgIdx) {
183*0fca6ea1SDimitry Andric   MDString *ArgAttribute = getOCLKernelArgTypeQual(F, ArgIdx);
184*0fca6ea1SDimitry Andric   if (ArgAttribute && ArgAttribute->getString() == "volatile")
185bdd1243dSDimitry Andric     return {SPIRV::Decoration::Volatile};
186bdd1243dSDimitry Andric   return {};
187bdd1243dSDimitry Andric }
188bdd1243dSDimitry Andric 
1895f757f3fSDimitry Andric static SPIRVType *getArgSPIRVType(const Function &F, unsigned ArgIdx,
1905f757f3fSDimitry Andric                                   SPIRVGlobalRegistry *GR,
191*0fca6ea1SDimitry Andric                                   MachineIRBuilder &MIRBuilder,
192*0fca6ea1SDimitry Andric                                   const SPIRVSubtarget &ST) {
1935f757f3fSDimitry Andric   // Read argument's access qualifier from metadata or default.
1945f757f3fSDimitry Andric   SPIRV::AccessQualifier::AccessQualifier ArgAccessQual =
1955f757f3fSDimitry Andric       getArgAccessQual(F, ArgIdx);
1965f757f3fSDimitry Andric 
197bdd1243dSDimitry Andric   Type *OriginalArgType = getOriginalFunctionType(F)->getParamType(ArgIdx);
1985f757f3fSDimitry Andric 
199*0fca6ea1SDimitry Andric   // If OriginalArgType is non-pointer, use the OriginalArgType (the type cannot
200*0fca6ea1SDimitry Andric   // be legally reassigned later).
201*0fca6ea1SDimitry Andric   if (!isPointerTy(OriginalArgType))
2025f757f3fSDimitry Andric     return GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder, ArgAccessQual);
203bdd1243dSDimitry Andric 
204*0fca6ea1SDimitry Andric   Argument *Arg = F.getArg(ArgIdx);
205*0fca6ea1SDimitry Andric   Type *ArgType = Arg->getType();
206*0fca6ea1SDimitry Andric   if (isTypedPointerTy(ArgType)) {
207*0fca6ea1SDimitry Andric     SPIRVType *ElementType = GR->getOrCreateSPIRVType(
208*0fca6ea1SDimitry Andric         cast<TypedPointerType>(ArgType)->getElementType(), MIRBuilder);
209*0fca6ea1SDimitry Andric     return GR->getOrCreateSPIRVPointerType(
210*0fca6ea1SDimitry Andric         ElementType, MIRBuilder,
211*0fca6ea1SDimitry Andric         addressSpaceToStorageClass(getPointerAddressSpace(ArgType), ST));
2125f757f3fSDimitry Andric   }
2135f757f3fSDimitry Andric 
214*0fca6ea1SDimitry Andric   // In case OriginalArgType is of untyped pointer type, there are three
215*0fca6ea1SDimitry Andric   // possibilities:
216*0fca6ea1SDimitry Andric   // 1) This is a pointer of an LLVM IR element type, passed byval/byref.
217*0fca6ea1SDimitry Andric   // 2) This is an OpenCL/SPIR-V builtin type if there is spv_assign_type
218*0fca6ea1SDimitry Andric   //    intrinsic assigning a TargetExtType.
219*0fca6ea1SDimitry Andric   // 3) This is a pointer, try to retrieve pointer element type from a
220*0fca6ea1SDimitry Andric   // spv_assign_ptr_type intrinsic or otherwise use default pointer element
221*0fca6ea1SDimitry Andric   // type.
222*0fca6ea1SDimitry Andric   if (hasPointeeTypeAttr(Arg)) {
223*0fca6ea1SDimitry Andric     SPIRVType *ElementType =
224*0fca6ea1SDimitry Andric         GR->getOrCreateSPIRVType(getPointeeTypeByAttr(Arg), MIRBuilder);
225*0fca6ea1SDimitry Andric     return GR->getOrCreateSPIRVPointerType(
226*0fca6ea1SDimitry Andric         ElementType, MIRBuilder,
227*0fca6ea1SDimitry Andric         addressSpaceToStorageClass(getPointerAddressSpace(ArgType), ST));
228*0fca6ea1SDimitry Andric   }
2295f757f3fSDimitry Andric 
230*0fca6ea1SDimitry Andric   for (auto User : Arg->users()) {
231*0fca6ea1SDimitry Andric     auto *II = dyn_cast<IntrinsicInst>(User);
232*0fca6ea1SDimitry Andric     // Check if this is spv_assign_type assigning OpenCL/SPIR-V builtin type.
233*0fca6ea1SDimitry Andric     if (II && II->getIntrinsicID() == Intrinsic::spv_assign_type) {
234*0fca6ea1SDimitry Andric       MetadataAsValue *VMD = cast<MetadataAsValue>(II->getOperand(1));
235*0fca6ea1SDimitry Andric       Type *BuiltinType =
236*0fca6ea1SDimitry Andric           cast<ConstantAsMetadata>(VMD->getMetadata())->getType();
237*0fca6ea1SDimitry Andric       assert(BuiltinType->isTargetExtTy() && "Expected TargetExtType");
238*0fca6ea1SDimitry Andric       return GR->getOrCreateSPIRVType(BuiltinType, MIRBuilder, ArgAccessQual);
239*0fca6ea1SDimitry Andric     }
2405f757f3fSDimitry Andric 
241*0fca6ea1SDimitry Andric     // Check if this is spv_assign_ptr_type assigning pointer element type.
242*0fca6ea1SDimitry Andric     if (!II || II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type)
243*0fca6ea1SDimitry Andric       continue;
244*0fca6ea1SDimitry Andric 
245*0fca6ea1SDimitry Andric     MetadataAsValue *VMD = cast<MetadataAsValue>(II->getOperand(1));
246*0fca6ea1SDimitry Andric     Type *ElementTy =
247*0fca6ea1SDimitry Andric         toTypedPointer(cast<ConstantAsMetadata>(VMD->getMetadata())->getType());
248*0fca6ea1SDimitry Andric     SPIRVType *ElementType = GR->getOrCreateSPIRVType(ElementTy, MIRBuilder);
249*0fca6ea1SDimitry Andric     return GR->getOrCreateSPIRVPointerType(
250*0fca6ea1SDimitry Andric         ElementType, MIRBuilder,
251*0fca6ea1SDimitry Andric         addressSpaceToStorageClass(
252*0fca6ea1SDimitry Andric             cast<ConstantInt>(II->getOperand(2))->getZExtValue(), ST));
253*0fca6ea1SDimitry Andric   }
254*0fca6ea1SDimitry Andric 
255*0fca6ea1SDimitry Andric   // Replace PointerType with TypedPointerType to be able to map SPIR-V types to
256*0fca6ea1SDimitry Andric   // LLVM types in a consistent manner
257*0fca6ea1SDimitry Andric   return GR->getOrCreateSPIRVType(toTypedPointer(OriginalArgType), MIRBuilder,
258*0fca6ea1SDimitry Andric                                   ArgAccessQual);
2595f757f3fSDimitry Andric }
2605f757f3fSDimitry Andric 
2615f757f3fSDimitry Andric static SPIRV::ExecutionModel::ExecutionModel
2625f757f3fSDimitry Andric getExecutionModel(const SPIRVSubtarget &STI, const Function &F) {
2635f757f3fSDimitry Andric   if (STI.isOpenCLEnv())
2645f757f3fSDimitry Andric     return SPIRV::ExecutionModel::Kernel;
2655f757f3fSDimitry Andric 
2665f757f3fSDimitry Andric   auto attribute = F.getFnAttribute("hlsl.shader");
2675f757f3fSDimitry Andric   if (!attribute.isValid()) {
2685f757f3fSDimitry Andric     report_fatal_error(
2695f757f3fSDimitry Andric         "This entry point lacks mandatory hlsl.shader attribute.");
2705f757f3fSDimitry Andric   }
2715f757f3fSDimitry Andric 
2725f757f3fSDimitry Andric   const auto value = attribute.getValueAsString();
2735f757f3fSDimitry Andric   if (value == "compute")
2745f757f3fSDimitry Andric     return SPIRV::ExecutionModel::GLCompute;
2755f757f3fSDimitry Andric 
2765f757f3fSDimitry Andric   report_fatal_error("This HLSL entry point is not supported by this backend.");
277bdd1243dSDimitry Andric }
278bdd1243dSDimitry Andric 
27981ad6265SDimitry Andric bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
28081ad6265SDimitry Andric                                              const Function &F,
28181ad6265SDimitry Andric                                              ArrayRef<ArrayRef<Register>> VRegs,
28281ad6265SDimitry Andric                                              FunctionLoweringInfo &FLI) const {
28381ad6265SDimitry Andric   assert(GR && "Must initialize the SPIRV type registry before lowering args.");
284753f127fSDimitry Andric   GR->setCurrentFunc(MIRBuilder.getMF());
28581ad6265SDimitry Andric 
286*0fca6ea1SDimitry Andric   // Get access to information about available extensions
287*0fca6ea1SDimitry Andric   const SPIRVSubtarget *ST =
288*0fca6ea1SDimitry Andric       static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget());
289*0fca6ea1SDimitry Andric 
29081ad6265SDimitry Andric   // Assign types and names to all args, and store their types for later.
291fcaf7f86SDimitry Andric   SmallVector<SPIRVType *, 4> ArgTypeVRegs;
29281ad6265SDimitry Andric   if (VRegs.size() > 0) {
29381ad6265SDimitry Andric     unsigned i = 0;
29481ad6265SDimitry Andric     for (const auto &Arg : F.args()) {
29581ad6265SDimitry Andric       // Currently formal args should use single registers.
29681ad6265SDimitry Andric       // TODO: handle the case of multiple registers.
29781ad6265SDimitry Andric       if (VRegs[i].size() > 1)
29881ad6265SDimitry Andric         return false;
299*0fca6ea1SDimitry Andric       auto *SpirvTy = getArgSPIRVType(F, i, GR, MIRBuilder, *ST);
3005f757f3fSDimitry Andric       GR->assignSPIRVTypeToVReg(SpirvTy, VRegs[i][0], MIRBuilder.getMF());
301fcaf7f86SDimitry Andric       ArgTypeVRegs.push_back(SpirvTy);
30281ad6265SDimitry Andric 
30381ad6265SDimitry Andric       if (Arg.hasName())
30481ad6265SDimitry Andric         buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder);
305*0fca6ea1SDimitry Andric       if (isPointerTy(Arg.getType())) {
30681ad6265SDimitry Andric         auto DerefBytes = static_cast<unsigned>(Arg.getDereferenceableBytes());
30781ad6265SDimitry Andric         if (DerefBytes != 0)
30881ad6265SDimitry Andric           buildOpDecorate(VRegs[i][0], MIRBuilder,
30981ad6265SDimitry Andric                           SPIRV::Decoration::MaxByteOffset, {DerefBytes});
31081ad6265SDimitry Andric       }
31181ad6265SDimitry Andric       if (Arg.hasAttribute(Attribute::Alignment)) {
312fcaf7f86SDimitry Andric         auto Alignment = static_cast<unsigned>(
313fcaf7f86SDimitry Andric             Arg.getAttribute(Attribute::Alignment).getValueAsInt());
31481ad6265SDimitry Andric         buildOpDecorate(VRegs[i][0], MIRBuilder, SPIRV::Decoration::Alignment,
315fcaf7f86SDimitry Andric                         {Alignment});
31681ad6265SDimitry Andric       }
31781ad6265SDimitry Andric       if (Arg.hasAttribute(Attribute::ReadOnly)) {
31881ad6265SDimitry Andric         auto Attr =
31981ad6265SDimitry Andric             static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite);
32081ad6265SDimitry Andric         buildOpDecorate(VRegs[i][0], MIRBuilder,
32181ad6265SDimitry Andric                         SPIRV::Decoration::FuncParamAttr, {Attr});
32281ad6265SDimitry Andric       }
32381ad6265SDimitry Andric       if (Arg.hasAttribute(Attribute::ZExt)) {
32481ad6265SDimitry Andric         auto Attr =
32581ad6265SDimitry Andric             static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext);
32681ad6265SDimitry Andric         buildOpDecorate(VRegs[i][0], MIRBuilder,
32781ad6265SDimitry Andric                         SPIRV::Decoration::FuncParamAttr, {Attr});
32881ad6265SDimitry Andric       }
329fcaf7f86SDimitry Andric       if (Arg.hasAttribute(Attribute::NoAlias)) {
330fcaf7f86SDimitry Andric         auto Attr =
331fcaf7f86SDimitry Andric             static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoAlias);
332fcaf7f86SDimitry Andric         buildOpDecorate(VRegs[i][0], MIRBuilder,
333fcaf7f86SDimitry Andric                         SPIRV::Decoration::FuncParamAttr, {Attr});
334fcaf7f86SDimitry Andric       }
335*0fca6ea1SDimitry Andric       if (Arg.hasAttribute(Attribute::ByVal)) {
336*0fca6ea1SDimitry Andric         auto Attr =
337*0fca6ea1SDimitry Andric             static_cast<unsigned>(SPIRV::FunctionParameterAttribute::ByVal);
338*0fca6ea1SDimitry Andric         buildOpDecorate(VRegs[i][0], MIRBuilder,
339*0fca6ea1SDimitry Andric                         SPIRV::Decoration::FuncParamAttr, {Attr});
340*0fca6ea1SDimitry Andric       }
341bdd1243dSDimitry Andric 
342bdd1243dSDimitry Andric       if (F.getCallingConv() == CallingConv::SPIR_KERNEL) {
343bdd1243dSDimitry Andric         std::vector<SPIRV::Decoration::Decoration> ArgTypeQualDecs =
344bdd1243dSDimitry Andric             getKernelArgTypeQual(F, i);
345bdd1243dSDimitry Andric         for (SPIRV::Decoration::Decoration Decoration : ArgTypeQualDecs)
346bdd1243dSDimitry Andric           buildOpDecorate(VRegs[i][0], MIRBuilder, Decoration, {});
347fcaf7f86SDimitry Andric       }
348bdd1243dSDimitry Andric 
349bdd1243dSDimitry Andric       MDNode *Node = F.getMetadata("spirv.ParameterDecorations");
350fcaf7f86SDimitry Andric       if (Node && i < Node->getNumOperands() &&
351fcaf7f86SDimitry Andric           isa<MDNode>(Node->getOperand(i))) {
352fcaf7f86SDimitry Andric         MDNode *MD = cast<MDNode>(Node->getOperand(i));
353fcaf7f86SDimitry Andric         for (const MDOperand &MDOp : MD->operands()) {
354fcaf7f86SDimitry Andric           MDNode *MD2 = dyn_cast<MDNode>(MDOp);
355fcaf7f86SDimitry Andric           assert(MD2 && "Metadata operand is expected");
356fcaf7f86SDimitry Andric           ConstantInt *Const = getConstInt(MD2, 0);
357fcaf7f86SDimitry Andric           assert(Const && "MDOperand should be ConstantInt");
358bdd1243dSDimitry Andric           auto Dec =
359bdd1243dSDimitry Andric               static_cast<SPIRV::Decoration::Decoration>(Const->getZExtValue());
360fcaf7f86SDimitry Andric           std::vector<uint32_t> DecVec;
361fcaf7f86SDimitry Andric           for (unsigned j = 1; j < MD2->getNumOperands(); j++) {
362fcaf7f86SDimitry Andric             ConstantInt *Const = getConstInt(MD2, j);
363fcaf7f86SDimitry Andric             assert(Const && "MDOperand should be ConstantInt");
364fcaf7f86SDimitry Andric             DecVec.push_back(static_cast<uint32_t>(Const->getZExtValue()));
365fcaf7f86SDimitry Andric           }
366fcaf7f86SDimitry Andric           buildOpDecorate(VRegs[i][0], MIRBuilder, Dec, DecVec);
367fcaf7f86SDimitry Andric         }
368fcaf7f86SDimitry Andric       }
36981ad6265SDimitry Andric       ++i;
37081ad6265SDimitry Andric     }
37181ad6265SDimitry Andric   }
37281ad6265SDimitry Andric 
37381ad6265SDimitry Andric   auto MRI = MIRBuilder.getMRI();
37481ad6265SDimitry Andric   Register FuncVReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
37581ad6265SDimitry Andric   MRI->setRegClass(FuncVReg, &SPIRV::IDRegClass);
376753f127fSDimitry Andric   if (F.isDeclaration())
377753f127fSDimitry Andric     GR->add(&F, &MIRBuilder.getMF(), FuncVReg);
378*0fca6ea1SDimitry Andric   FunctionType *FTy = getOriginalFunctionType(F);
379*0fca6ea1SDimitry Andric   Type *FRetTy = FTy->getReturnType();
380*0fca6ea1SDimitry Andric   if (isUntypedPointerTy(FRetTy)) {
381*0fca6ea1SDimitry Andric     if (Type *FRetElemTy = GR->findDeducedElementType(&F)) {
382*0fca6ea1SDimitry Andric       TypedPointerType *DerivedTy = TypedPointerType::get(
383*0fca6ea1SDimitry Andric           toTypedPointer(FRetElemTy), getPointerAddressSpace(FRetTy));
384*0fca6ea1SDimitry Andric       GR->addReturnType(&F, DerivedTy);
385*0fca6ea1SDimitry Andric       FRetTy = DerivedTy;
386*0fca6ea1SDimitry Andric     }
387*0fca6ea1SDimitry Andric   }
388*0fca6ea1SDimitry Andric   SPIRVType *RetTy = GR->getOrCreateSPIRVType(FRetTy, MIRBuilder);
389*0fca6ea1SDimitry Andric   FTy = fixFunctionTypeIfPtrArgs(GR, F, FTy, RetTy, ArgTypeVRegs);
390fcaf7f86SDimitry Andric   SPIRVType *FuncTy = GR->getOrCreateOpTypeFunctionWithArgs(
391fcaf7f86SDimitry Andric       FTy, RetTy, ArgTypeVRegs, MIRBuilder);
39281ad6265SDimitry Andric   uint32_t FuncControl = getFunctionControl(F);
39381ad6265SDimitry Andric 
394*0fca6ea1SDimitry Andric   // Add OpFunction instruction
395*0fca6ea1SDimitry Andric   MachineInstrBuilder MB = MIRBuilder.buildInstr(SPIRV::OpFunction)
39681ad6265SDimitry Andric                                .addDef(FuncVReg)
397fcaf7f86SDimitry Andric                                .addUse(GR->getSPIRVTypeID(RetTy))
39881ad6265SDimitry Andric                                .addImm(FuncControl)
39981ad6265SDimitry Andric                                .addUse(GR->getSPIRVTypeID(FuncTy));
400*0fca6ea1SDimitry Andric   GR->recordFunctionDefinition(&F, &MB.getInstr()->getOperand(0));
40181ad6265SDimitry Andric 
402*0fca6ea1SDimitry Andric   // Add OpFunctionParameter instructions
403fcaf7f86SDimitry Andric   int i = 0;
404fcaf7f86SDimitry Andric   for (const auto &Arg : F.args()) {
40581ad6265SDimitry Andric     assert(VRegs[i].size() == 1 && "Formal arg has multiple vregs");
40681ad6265SDimitry Andric     MRI->setRegClass(VRegs[i][0], &SPIRV::IDRegClass);
40781ad6265SDimitry Andric     MIRBuilder.buildInstr(SPIRV::OpFunctionParameter)
40881ad6265SDimitry Andric         .addDef(VRegs[i][0])
409fcaf7f86SDimitry Andric         .addUse(GR->getSPIRVTypeID(ArgTypeVRegs[i]));
410753f127fSDimitry Andric     if (F.isDeclaration())
411fcaf7f86SDimitry Andric       GR->add(&Arg, &MIRBuilder.getMF(), VRegs[i][0]);
412fcaf7f86SDimitry Andric     i++;
41381ad6265SDimitry Andric   }
41481ad6265SDimitry Andric   // Name the function.
41581ad6265SDimitry Andric   if (F.hasName())
41681ad6265SDimitry Andric     buildOpName(FuncVReg, F.getName(), MIRBuilder);
41781ad6265SDimitry Andric 
41881ad6265SDimitry Andric   // Handle entry points and function linkage.
4195f757f3fSDimitry Andric   if (isEntryPoint(F)) {
4205f757f3fSDimitry Andric     const auto &STI = MIRBuilder.getMF().getSubtarget<SPIRVSubtarget>();
4215f757f3fSDimitry Andric     auto executionModel = getExecutionModel(STI, F);
42281ad6265SDimitry Andric     auto MIB = MIRBuilder.buildInstr(SPIRV::OpEntryPoint)
4235f757f3fSDimitry Andric                    .addImm(static_cast<uint32_t>(executionModel))
42481ad6265SDimitry Andric                    .addUse(FuncVReg);
42581ad6265SDimitry Andric     addStringImm(F.getName(), MIB);
426*0fca6ea1SDimitry Andric   } else if (F.getLinkage() != GlobalValue::InternalLinkage &&
427*0fca6ea1SDimitry Andric              F.getLinkage() != GlobalValue::PrivateLinkage) {
428*0fca6ea1SDimitry Andric     SPIRV::LinkageType::LinkageType LnkTy =
429*0fca6ea1SDimitry Andric         F.isDeclaration()
430*0fca6ea1SDimitry Andric             ? SPIRV::LinkageType::Import
431*0fca6ea1SDimitry Andric             : (F.getLinkage() == GlobalValue::LinkOnceODRLinkage &&
432*0fca6ea1SDimitry Andric                        ST->canUseExtension(
433*0fca6ea1SDimitry Andric                            SPIRV::Extension::SPV_KHR_linkonce_odr)
434*0fca6ea1SDimitry Andric                    ? SPIRV::LinkageType::LinkOnceODR
435*0fca6ea1SDimitry Andric                    : SPIRV::LinkageType::Export);
43681ad6265SDimitry Andric     buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes,
43781ad6265SDimitry Andric                     {static_cast<uint32_t>(LnkTy)}, F.getGlobalIdentifier());
43881ad6265SDimitry Andric   }
43981ad6265SDimitry Andric 
440*0fca6ea1SDimitry Andric   // Handle function pointers decoration
441*0fca6ea1SDimitry Andric   bool hasFunctionPointers =
442*0fca6ea1SDimitry Andric       ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
443*0fca6ea1SDimitry Andric   if (hasFunctionPointers) {
444*0fca6ea1SDimitry Andric     if (F.hasFnAttribute("referenced-indirectly")) {
445*0fca6ea1SDimitry Andric       assert((F.getCallingConv() != CallingConv::SPIR_KERNEL) &&
446*0fca6ea1SDimitry Andric              "Unexpected 'referenced-indirectly' attribute of the kernel "
447*0fca6ea1SDimitry Andric              "function");
448*0fca6ea1SDimitry Andric       buildOpDecorate(FuncVReg, MIRBuilder,
449*0fca6ea1SDimitry Andric                       SPIRV::Decoration::ReferencedIndirectlyINTEL, {});
450*0fca6ea1SDimitry Andric     }
451*0fca6ea1SDimitry Andric   }
452*0fca6ea1SDimitry Andric 
45381ad6265SDimitry Andric   return true;
45481ad6265SDimitry Andric }
45581ad6265SDimitry Andric 
456*0fca6ea1SDimitry Andric // Used to postpone producing of indirect function pointer types after all
457*0fca6ea1SDimitry Andric // indirect calls info is collected
458*0fca6ea1SDimitry Andric // TODO:
459*0fca6ea1SDimitry Andric // - add a topological sort of IndirectCalls to ensure the best types knowledge
460*0fca6ea1SDimitry Andric // - we may need to fix function formal parameter types if they are opaque
461*0fca6ea1SDimitry Andric //   pointers used as function pointers in these indirect calls
462*0fca6ea1SDimitry Andric void SPIRVCallLowering::produceIndirectPtrTypes(
463*0fca6ea1SDimitry Andric     MachineIRBuilder &MIRBuilder) const {
464*0fca6ea1SDimitry Andric   // Create indirect call data types if any
465*0fca6ea1SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
466*0fca6ea1SDimitry Andric   for (auto const &IC : IndirectCalls) {
467*0fca6ea1SDimitry Andric     SPIRVType *SpirvRetTy = GR->getOrCreateSPIRVType(IC.RetTy, MIRBuilder);
468*0fca6ea1SDimitry Andric     SmallVector<SPIRVType *, 4> SpirvArgTypes;
469*0fca6ea1SDimitry Andric     for (size_t i = 0; i < IC.ArgTys.size(); ++i) {
470*0fca6ea1SDimitry Andric       SPIRVType *SPIRVTy = GR->getOrCreateSPIRVType(IC.ArgTys[i], MIRBuilder);
471*0fca6ea1SDimitry Andric       SpirvArgTypes.push_back(SPIRVTy);
472*0fca6ea1SDimitry Andric       if (!GR->getSPIRVTypeForVReg(IC.ArgRegs[i]))
473*0fca6ea1SDimitry Andric         GR->assignSPIRVTypeToVReg(SPIRVTy, IC.ArgRegs[i], MF);
474*0fca6ea1SDimitry Andric     }
475*0fca6ea1SDimitry Andric     // SPIR-V function type:
476*0fca6ea1SDimitry Andric     FunctionType *FTy =
477*0fca6ea1SDimitry Andric         FunctionType::get(const_cast<Type *>(IC.RetTy), IC.ArgTys, false);
478*0fca6ea1SDimitry Andric     SPIRVType *SpirvFuncTy = GR->getOrCreateOpTypeFunctionWithArgs(
479*0fca6ea1SDimitry Andric         FTy, SpirvRetTy, SpirvArgTypes, MIRBuilder);
480*0fca6ea1SDimitry Andric     // SPIR-V pointer to function type:
481*0fca6ea1SDimitry Andric     SPIRVType *IndirectFuncPtrTy = GR->getOrCreateSPIRVPointerType(
482*0fca6ea1SDimitry Andric         SpirvFuncTy, MIRBuilder, SPIRV::StorageClass::Function);
483*0fca6ea1SDimitry Andric     // Correct the Callee type
484*0fca6ea1SDimitry Andric     GR->assignSPIRVTypeToVReg(IndirectFuncPtrTy, IC.Callee, MF);
485*0fca6ea1SDimitry Andric   }
486*0fca6ea1SDimitry Andric }
487*0fca6ea1SDimitry Andric 
48881ad6265SDimitry Andric bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
48981ad6265SDimitry Andric                                   CallLoweringInfo &Info) const {
49081ad6265SDimitry Andric   // Currently call returns should have single vregs.
49181ad6265SDimitry Andric   // TODO: handle the case of multiple registers.
49281ad6265SDimitry Andric   if (Info.OrigRet.Regs.size() > 1)
49381ad6265SDimitry Andric     return false;
494fcaf7f86SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
495fcaf7f86SDimitry Andric   GR->setCurrentFunc(MF);
496fcaf7f86SDimitry Andric   const Function *CF = nullptr;
497*0fca6ea1SDimitry Andric   std::string DemangledName;
498*0fca6ea1SDimitry Andric   const Type *OrigRetTy = Info.OrigRet.Ty;
49981ad6265SDimitry Andric 
50081ad6265SDimitry Andric   // Emit a regular OpFunctionCall. If it's an externally declared function,
501fcaf7f86SDimitry Andric   // be sure to emit its type and function declaration here. It will be hoisted
502fcaf7f86SDimitry Andric   // globally later.
50381ad6265SDimitry Andric   if (Info.Callee.isGlobal()) {
504*0fca6ea1SDimitry Andric     std::string FuncName = Info.Callee.getGlobal()->getName().str();
505*0fca6ea1SDimitry Andric     DemangledName = getOclOrSpirvBuiltinDemangledName(FuncName);
506fcaf7f86SDimitry Andric     CF = dyn_cast_or_null<const Function>(Info.Callee.getGlobal());
50781ad6265SDimitry Andric     // TODO: support constexpr casts and indirect calls.
50881ad6265SDimitry Andric     if (CF == nullptr)
50981ad6265SDimitry Andric       return false;
510*0fca6ea1SDimitry Andric     if (FunctionType *FTy = getOriginalFunctionType(*CF)) {
511*0fca6ea1SDimitry Andric       OrigRetTy = FTy->getReturnType();
512*0fca6ea1SDimitry Andric       if (isUntypedPointerTy(OrigRetTy)) {
513*0fca6ea1SDimitry Andric         if (auto *DerivedRetTy = GR->findReturnType(CF))
514*0fca6ea1SDimitry Andric           OrigRetTy = DerivedRetTy;
515*0fca6ea1SDimitry Andric       }
516*0fca6ea1SDimitry Andric     }
517fcaf7f86SDimitry Andric   }
518fcaf7f86SDimitry Andric 
51906c3fb27SDimitry Andric   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
520fcaf7f86SDimitry Andric   Register ResVReg =
521fcaf7f86SDimitry Andric       Info.OrigRet.Regs.empty() ? Register(0) : Info.OrigRet.Regs[0];
522bdd1243dSDimitry Andric   const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget());
523*0fca6ea1SDimitry Andric 
524*0fca6ea1SDimitry Andric   bool isFunctionDecl = CF && CF->isDeclaration();
525*0fca6ea1SDimitry Andric   bool canUseOpenCL = ST->canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std);
526*0fca6ea1SDimitry Andric   bool canUseGLSL = ST->canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450);
527*0fca6ea1SDimitry Andric   assert(canUseGLSL != canUseOpenCL &&
528*0fca6ea1SDimitry Andric          "Scenario where both sets are enabled is not supported.");
529*0fca6ea1SDimitry Andric 
530*0fca6ea1SDimitry Andric   if (isFunctionDecl && !DemangledName.empty() &&
531*0fca6ea1SDimitry Andric       (canUseGLSL || canUseOpenCL)) {
532bdd1243dSDimitry Andric     SmallVector<Register, 8> ArgVRegs;
533bdd1243dSDimitry Andric     for (auto Arg : Info.OrigArgs) {
534bdd1243dSDimitry Andric       assert(Arg.Regs.size() == 1 && "Call arg has multiple VRegs");
535bdd1243dSDimitry Andric       ArgVRegs.push_back(Arg.Regs[0]);
536bdd1243dSDimitry Andric       SPIRVType *SPIRVTy = GR->getOrCreateSPIRVType(Arg.Ty, MIRBuilder);
5371db9f3b2SDimitry Andric       if (!GR->getSPIRVTypeForVReg(Arg.Regs[0]))
538*0fca6ea1SDimitry Andric         GR->assignSPIRVTypeToVReg(SPIRVTy, Arg.Regs[0], MF);
539bdd1243dSDimitry Andric     }
540*0fca6ea1SDimitry Andric     auto instructionSet = canUseOpenCL ? SPIRV::InstructionSet::OpenCL_std
541*0fca6ea1SDimitry Andric                                        : SPIRV::InstructionSet::GLSL_std_450;
542*0fca6ea1SDimitry Andric     if (auto Res =
543*0fca6ea1SDimitry Andric             SPIRV::lowerBuiltin(DemangledName, instructionSet, MIRBuilder,
544bdd1243dSDimitry Andric                                 ResVReg, OrigRetTy, ArgVRegs, GR))
545bdd1243dSDimitry Andric       return *Res;
546bdd1243dSDimitry Andric   }
547*0fca6ea1SDimitry Andric 
548*0fca6ea1SDimitry Andric   if (isFunctionDecl && !GR->find(CF, &MF).isValid()) {
54981ad6265SDimitry Andric     // Emit the type info and forward function declaration to the first MBB
55081ad6265SDimitry Andric     // to ensure VReg definition dependencies are valid across all MBBs.
551fcaf7f86SDimitry Andric     MachineIRBuilder FirstBlockBuilder;
552fcaf7f86SDimitry Andric     FirstBlockBuilder.setMF(MF);
553fcaf7f86SDimitry Andric     FirstBlockBuilder.setMBB(*MF.getBlockNumbered(0));
55481ad6265SDimitry Andric 
55581ad6265SDimitry Andric     SmallVector<ArrayRef<Register>, 8> VRegArgs;
55681ad6265SDimitry Andric     SmallVector<SmallVector<Register, 1>, 8> ToInsert;
55781ad6265SDimitry Andric     for (const Argument &Arg : CF->args()) {
55881ad6265SDimitry Andric       if (MIRBuilder.getDataLayout().getTypeStoreSize(Arg.getType()).isZero())
55981ad6265SDimitry Andric         continue; // Don't handle zero sized types.
56006c3fb27SDimitry Andric       Register Reg = MRI->createGenericVirtualRegister(LLT::scalar(32));
56106c3fb27SDimitry Andric       MRI->setRegClass(Reg, &SPIRV::IDRegClass);
56206c3fb27SDimitry Andric       ToInsert.push_back({Reg});
56381ad6265SDimitry Andric       VRegArgs.push_back(ToInsert.back());
56481ad6265SDimitry Andric     }
565fcaf7f86SDimitry Andric     // TODO: Reuse FunctionLoweringInfo
56681ad6265SDimitry Andric     FunctionLoweringInfo FuncInfo;
567fcaf7f86SDimitry Andric     lowerFormalArguments(FirstBlockBuilder, *CF, VRegArgs, FuncInfo);
56881ad6265SDimitry Andric   }
56981ad6265SDimitry Andric 
570*0fca6ea1SDimitry Andric   unsigned CallOp;
571*0fca6ea1SDimitry Andric   if (Info.CB->isIndirectCall()) {
572*0fca6ea1SDimitry Andric     if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
573*0fca6ea1SDimitry Andric       report_fatal_error("An indirect call is encountered but SPIR-V without "
574*0fca6ea1SDimitry Andric                          "extensions does not support it",
575*0fca6ea1SDimitry Andric                          false);
576*0fca6ea1SDimitry Andric     // Set instruction operation according to SPV_INTEL_function_pointers
577*0fca6ea1SDimitry Andric     CallOp = SPIRV::OpFunctionPointerCallINTEL;
578*0fca6ea1SDimitry Andric     // Collect information about the indirect call to support possible
579*0fca6ea1SDimitry Andric     // specification of opaque ptr types of parent function's parameters
580*0fca6ea1SDimitry Andric     Register CalleeReg = Info.Callee.getReg();
581*0fca6ea1SDimitry Andric     if (CalleeReg.isValid()) {
582*0fca6ea1SDimitry Andric       SPIRVCallLowering::SPIRVIndirectCall IndirectCall;
583*0fca6ea1SDimitry Andric       IndirectCall.Callee = CalleeReg;
584*0fca6ea1SDimitry Andric       IndirectCall.RetTy = OrigRetTy;
585*0fca6ea1SDimitry Andric       for (const auto &Arg : Info.OrigArgs) {
586*0fca6ea1SDimitry Andric         assert(Arg.Regs.size() == 1 && "Call arg has multiple VRegs");
587*0fca6ea1SDimitry Andric         IndirectCall.ArgTys.push_back(Arg.Ty);
588*0fca6ea1SDimitry Andric         IndirectCall.ArgRegs.push_back(Arg.Regs[0]);
589*0fca6ea1SDimitry Andric       }
590*0fca6ea1SDimitry Andric       IndirectCalls.push_back(IndirectCall);
591*0fca6ea1SDimitry Andric     }
592*0fca6ea1SDimitry Andric   } else {
593*0fca6ea1SDimitry Andric     // Emit a regular OpFunctionCall
594*0fca6ea1SDimitry Andric     CallOp = SPIRV::OpFunctionCall;
595*0fca6ea1SDimitry Andric   }
596*0fca6ea1SDimitry Andric 
59781ad6265SDimitry Andric   // Make sure there's a valid return reg, even for functions returning void.
598fcaf7f86SDimitry Andric   if (!ResVReg.isValid())
59981ad6265SDimitry Andric     ResVReg = MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::IDRegClass);
600*0fca6ea1SDimitry Andric   SPIRVType *RetType = GR->assignTypeToVReg(OrigRetTy, ResVReg, MIRBuilder);
60181ad6265SDimitry Andric 
602*0fca6ea1SDimitry Andric   // Emit the call instruction and its args.
603*0fca6ea1SDimitry Andric   auto MIB = MIRBuilder.buildInstr(CallOp)
60481ad6265SDimitry Andric                  .addDef(ResVReg)
60581ad6265SDimitry Andric                  .addUse(GR->getSPIRVTypeID(RetType))
60681ad6265SDimitry Andric                  .add(Info.Callee);
60781ad6265SDimitry Andric 
60881ad6265SDimitry Andric   for (const auto &Arg : Info.OrigArgs) {
60981ad6265SDimitry Andric     // Currently call args should have single vregs.
61081ad6265SDimitry Andric     if (Arg.Regs.size() > 1)
61181ad6265SDimitry Andric       return false;
61281ad6265SDimitry Andric     MIB.addUse(Arg.Regs[0]);
61381ad6265SDimitry Andric   }
614bdd1243dSDimitry Andric   return MIB.constrainAllUses(MIRBuilder.getTII(), *ST->getRegisterInfo(),
615bdd1243dSDimitry Andric                               *ST->getRegBankInfo());
61681ad6265SDimitry Andric }
617