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
SPIRVCallLowering(const SPIRVTargetLowering & TLI,SPIRVGlobalRegistry * GR)3181ad6265SDimitry Andric SPIRVCallLowering::SPIRVCallLowering(const SPIRVTargetLowering &TLI,
3281ad6265SDimitry Andric SPIRVGlobalRegistry *GR)
33fcaf7f86SDimitry Andric : CallLowering(&TLI), GR(GR) {}
3481ad6265SDimitry Andric
lowerReturn(MachineIRBuilder & MIRBuilder,const Value * Val,ArrayRef<Register> VRegs,FunctionLoweringInfo & FLI,Register SwiftErrorVReg) const3581ad6265SDimitry 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.
getFunctionControl(const Function & F)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
getConstInt(MDNode * MD,unsigned NumOp)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 *
fixFunctionTypeIfPtrArgs(SPIRVGlobalRegistry * GR,const Function & F,FunctionType * FTy,const SPIRVType * SRetTy,const SmallVector<SPIRVType *,4> & SArgTys)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.
getOriginalFunctionType(const Function & F)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
getArgAccessQual(const Function & F,unsigned ArgIdx)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>
getKernelArgTypeQual(const Function & F,unsigned ArgIdx)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
getArgSPIRVType(const Function & F,unsigned ArgIdx,SPIRVGlobalRegistry * GR,MachineIRBuilder & MIRBuilder,const SPIRVSubtarget & ST)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
getExecutionModel(const SPIRVSubtarget & STI,const Function & F)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
lowerFormalArguments(MachineIRBuilder & MIRBuilder,const Function & F,ArrayRef<ArrayRef<Register>> VRegs,FunctionLoweringInfo & FLI) const27981ad6265SDimitry 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
produceIndirectPtrTypes(MachineIRBuilder & MIRBuilder) const462*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
lowerCall(MachineIRBuilder & MIRBuilder,CallLoweringInfo & Info) const48881ad6265SDimitry 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