1ec259036SIlia Diachkov //===--- SPIRVCallLowering.cpp - Call lowering ------------------*- 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 lowering of LLVM calls to machine code calls for
10ec259036SIlia Diachkov // GlobalISel.
11ec259036SIlia Diachkov //
12ec259036SIlia Diachkov //===----------------------------------------------------------------------===//
13ec259036SIlia Diachkov 
14ec259036SIlia Diachkov #include "SPIRVCallLowering.h"
15eab7d363SIlia Diachkov #include "MCTargetDesc/SPIRVBaseInfo.h"
16ec259036SIlia Diachkov #include "SPIRV.h"
17eab7d363SIlia Diachkov #include "SPIRVGlobalRegistry.h"
18ec259036SIlia Diachkov #include "SPIRVISelLowering.h"
19ec259036SIlia Diachkov #include "SPIRVRegisterInfo.h"
20ec259036SIlia Diachkov #include "SPIRVSubtarget.h"
21eab7d363SIlia Diachkov #include "SPIRVUtils.h"
22ec259036SIlia Diachkov #include "llvm/CodeGen/FunctionLoweringInfo.h"
23ec259036SIlia Diachkov 
24ec259036SIlia Diachkov using namespace llvm;
25ec259036SIlia Diachkov 
SPIRVCallLowering(const SPIRVTargetLowering & TLI,SPIRVGlobalRegistry * GR)26eab7d363SIlia Diachkov SPIRVCallLowering::SPIRVCallLowering(const SPIRVTargetLowering &TLI,
27eab7d363SIlia Diachkov                                      SPIRVGlobalRegistry *GR)
28*b8e1544bSIlia Diachkov     : CallLowering(&TLI), GR(GR) {}
29ec259036SIlia Diachkov 
lowerReturn(MachineIRBuilder & MIRBuilder,const Value * Val,ArrayRef<Register> VRegs,FunctionLoweringInfo & FLI,Register SwiftErrorVReg) const30ec259036SIlia Diachkov bool SPIRVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
31ec259036SIlia Diachkov                                     const Value *Val, ArrayRef<Register> VRegs,
32ec259036SIlia Diachkov                                     FunctionLoweringInfo &FLI,
33ec259036SIlia Diachkov                                     Register SwiftErrorVReg) const {
34ec259036SIlia Diachkov   // Currently all return types should use a single register.
35ec259036SIlia Diachkov   // TODO: handle the case of multiple registers.
36ec259036SIlia Diachkov   if (VRegs.size() > 1)
37ec259036SIlia Diachkov     return false;
38*b8e1544bSIlia Diachkov   if (Val) {
39*b8e1544bSIlia Diachkov     const auto &STI = MIRBuilder.getMF().getSubtarget();
40eab7d363SIlia Diachkov     return MIRBuilder.buildInstr(SPIRV::OpReturnValue)
41eab7d363SIlia Diachkov         .addUse(VRegs[0])
42*b8e1544bSIlia Diachkov         .constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
43*b8e1544bSIlia Diachkov                           *STI.getRegBankInfo());
44*b8e1544bSIlia Diachkov   }
45ec259036SIlia Diachkov   MIRBuilder.buildInstr(SPIRV::OpReturn);
46ec259036SIlia Diachkov   return true;
47ec259036SIlia Diachkov }
48ec259036SIlia Diachkov 
49eab7d363SIlia Diachkov // Based on the LLVM function attributes, get a SPIR-V FunctionControl.
getFunctionControl(const Function & F)50eab7d363SIlia Diachkov static uint32_t getFunctionControl(const Function &F) {
51eab7d363SIlia Diachkov   uint32_t FuncControl = static_cast<uint32_t>(SPIRV::FunctionControl::None);
52eab7d363SIlia Diachkov   if (F.hasFnAttribute(Attribute::AttrKind::AlwaysInline)) {
53eab7d363SIlia Diachkov     FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Inline);
54eab7d363SIlia Diachkov   }
55eab7d363SIlia Diachkov   if (F.hasFnAttribute(Attribute::AttrKind::ReadNone)) {
56eab7d363SIlia Diachkov     FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Pure);
57eab7d363SIlia Diachkov   }
58eab7d363SIlia Diachkov   if (F.hasFnAttribute(Attribute::AttrKind::ReadOnly)) {
59eab7d363SIlia Diachkov     FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Const);
60eab7d363SIlia Diachkov   }
61eab7d363SIlia Diachkov   if (F.hasFnAttribute(Attribute::AttrKind::NoInline)) {
62eab7d363SIlia Diachkov     FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::DontInline);
63eab7d363SIlia Diachkov   }
64eab7d363SIlia Diachkov   return FuncControl;
65eab7d363SIlia Diachkov }
66eab7d363SIlia Diachkov 
getConstInt(MDNode * MD,unsigned NumOp)67*b8e1544bSIlia Diachkov static ConstantInt *getConstInt(MDNode *MD, unsigned NumOp) {
68*b8e1544bSIlia Diachkov   if (MD->getNumOperands() > NumOp) {
69*b8e1544bSIlia Diachkov     auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(NumOp));
70*b8e1544bSIlia Diachkov     if (CMeta)
71*b8e1544bSIlia Diachkov       return dyn_cast<ConstantInt>(CMeta->getValue());
72*b8e1544bSIlia Diachkov   }
73*b8e1544bSIlia Diachkov   return nullptr;
74*b8e1544bSIlia Diachkov }
75*b8e1544bSIlia Diachkov 
76*b8e1544bSIlia Diachkov // This code restores function args/retvalue types for composite cases
77*b8e1544bSIlia Diachkov // because the final types should still be aggregate whereas they're i32
78*b8e1544bSIlia Diachkov // during the translation to cope with aggregate flattening etc.
getOriginalFunctionType(const Function & F)79*b8e1544bSIlia Diachkov static FunctionType *getOriginalFunctionType(const Function &F) {
80*b8e1544bSIlia Diachkov   auto *NamedMD = F.getParent()->getNamedMetadata("spv.cloned_funcs");
81*b8e1544bSIlia Diachkov   if (NamedMD == nullptr)
82*b8e1544bSIlia Diachkov     return F.getFunctionType();
83*b8e1544bSIlia Diachkov 
84*b8e1544bSIlia Diachkov   Type *RetTy = F.getFunctionType()->getReturnType();
85*b8e1544bSIlia Diachkov   SmallVector<Type *, 4> ArgTypes;
86*b8e1544bSIlia Diachkov   for (auto &Arg : F.args())
87*b8e1544bSIlia Diachkov     ArgTypes.push_back(Arg.getType());
88*b8e1544bSIlia Diachkov 
89*b8e1544bSIlia Diachkov   auto ThisFuncMDIt =
90*b8e1544bSIlia Diachkov       std::find_if(NamedMD->op_begin(), NamedMD->op_end(), [&F](MDNode *N) {
91*b8e1544bSIlia Diachkov         return isa<MDString>(N->getOperand(0)) &&
92*b8e1544bSIlia Diachkov                cast<MDString>(N->getOperand(0))->getString() == F.getName();
93*b8e1544bSIlia Diachkov       });
94*b8e1544bSIlia Diachkov   // TODO: probably one function can have numerous type mutations,
95*b8e1544bSIlia Diachkov   // so we should support this.
96*b8e1544bSIlia Diachkov   if (ThisFuncMDIt != NamedMD->op_end()) {
97*b8e1544bSIlia Diachkov     auto *ThisFuncMD = *ThisFuncMDIt;
98*b8e1544bSIlia Diachkov     MDNode *MD = dyn_cast<MDNode>(ThisFuncMD->getOperand(1));
99*b8e1544bSIlia Diachkov     assert(MD && "MDNode operand is expected");
100*b8e1544bSIlia Diachkov     ConstantInt *Const = getConstInt(MD, 0);
101*b8e1544bSIlia Diachkov     if (Const) {
102*b8e1544bSIlia Diachkov       auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(1));
103*b8e1544bSIlia Diachkov       assert(CMeta && "ConstantAsMetadata operand is expected");
104*b8e1544bSIlia Diachkov       assert(Const->getSExtValue() >= -1);
105*b8e1544bSIlia Diachkov       // Currently -1 indicates return value, greater values mean
106*b8e1544bSIlia Diachkov       // argument numbers.
107*b8e1544bSIlia Diachkov       if (Const->getSExtValue() == -1)
108*b8e1544bSIlia Diachkov         RetTy = CMeta->getType();
109*b8e1544bSIlia Diachkov       else
110*b8e1544bSIlia Diachkov         ArgTypes[Const->getSExtValue()] = CMeta->getType();
111*b8e1544bSIlia Diachkov     }
112*b8e1544bSIlia Diachkov   }
113*b8e1544bSIlia Diachkov 
114*b8e1544bSIlia Diachkov   return FunctionType::get(RetTy, ArgTypes, F.isVarArg());
115*b8e1544bSIlia Diachkov }
116*b8e1544bSIlia Diachkov 
lowerFormalArguments(MachineIRBuilder & MIRBuilder,const Function & F,ArrayRef<ArrayRef<Register>> VRegs,FunctionLoweringInfo & FLI) const117ec259036SIlia Diachkov bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
118ec259036SIlia Diachkov                                              const Function &F,
119ec259036SIlia Diachkov                                              ArrayRef<ArrayRef<Register>> VRegs,
120ec259036SIlia Diachkov                                              FunctionLoweringInfo &FLI) const {
121eab7d363SIlia Diachkov   assert(GR && "Must initialize the SPIRV type registry before lowering args.");
122fa2a7a25SAleksandr Bezzubikov   GR->setCurrentFunc(MIRBuilder.getMF());
123eab7d363SIlia Diachkov 
124ec259036SIlia Diachkov   // Assign types and names to all args, and store their types for later.
125*b8e1544bSIlia Diachkov   FunctionType *FTy = getOriginalFunctionType(F);
126*b8e1544bSIlia Diachkov   SmallVector<SPIRVType *, 4> ArgTypeVRegs;
127ec259036SIlia Diachkov   if (VRegs.size() > 0) {
128ec259036SIlia Diachkov     unsigned i = 0;
129ec259036SIlia Diachkov     for (const auto &Arg : F.args()) {
130ec259036SIlia Diachkov       // Currently formal args should use single registers.
131ec259036SIlia Diachkov       // TODO: handle the case of multiple registers.
132ec259036SIlia Diachkov       if (VRegs[i].size() > 1)
133ec259036SIlia Diachkov         return false;
134*b8e1544bSIlia Diachkov       Type *ArgTy = FTy->getParamType(i);
135*b8e1544bSIlia Diachkov       SPIRV::AccessQualifier AQ = SPIRV::AccessQualifier::ReadWrite;
136*b8e1544bSIlia Diachkov       MDNode *Node = F.getMetadata("kernel_arg_access_qual");
137*b8e1544bSIlia Diachkov       if (Node && i < Node->getNumOperands()) {
138*b8e1544bSIlia Diachkov         StringRef AQString = cast<MDString>(Node->getOperand(i))->getString();
139*b8e1544bSIlia Diachkov         if (AQString.compare("read_only") == 0)
140*b8e1544bSIlia Diachkov           AQ = SPIRV::AccessQualifier::ReadOnly;
141*b8e1544bSIlia Diachkov         else if (AQString.compare("write_only") == 0)
142*b8e1544bSIlia Diachkov           AQ = SPIRV::AccessQualifier::WriteOnly;
143*b8e1544bSIlia Diachkov       }
144*b8e1544bSIlia Diachkov       auto *SpirvTy = GR->assignTypeToVReg(ArgTy, VRegs[i][0], MIRBuilder, AQ);
145*b8e1544bSIlia Diachkov       ArgTypeVRegs.push_back(SpirvTy);
146eab7d363SIlia Diachkov 
147eab7d363SIlia Diachkov       if (Arg.hasName())
148eab7d363SIlia Diachkov         buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder);
149eab7d363SIlia Diachkov       if (Arg.getType()->isPointerTy()) {
150eab7d363SIlia Diachkov         auto DerefBytes = static_cast<unsigned>(Arg.getDereferenceableBytes());
151eab7d363SIlia Diachkov         if (DerefBytes != 0)
152eab7d363SIlia Diachkov           buildOpDecorate(VRegs[i][0], MIRBuilder,
153eab7d363SIlia Diachkov                           SPIRV::Decoration::MaxByteOffset, {DerefBytes});
154eab7d363SIlia Diachkov       }
155eab7d363SIlia Diachkov       if (Arg.hasAttribute(Attribute::Alignment)) {
156*b8e1544bSIlia Diachkov         auto Alignment = static_cast<unsigned>(
157*b8e1544bSIlia Diachkov             Arg.getAttribute(Attribute::Alignment).getValueAsInt());
158eab7d363SIlia Diachkov         buildOpDecorate(VRegs[i][0], MIRBuilder, SPIRV::Decoration::Alignment,
159*b8e1544bSIlia Diachkov                         {Alignment});
160eab7d363SIlia Diachkov       }
161eab7d363SIlia Diachkov       if (Arg.hasAttribute(Attribute::ReadOnly)) {
162eab7d363SIlia Diachkov         auto Attr =
163eab7d363SIlia Diachkov             static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite);
164eab7d363SIlia Diachkov         buildOpDecorate(VRegs[i][0], MIRBuilder,
165eab7d363SIlia Diachkov                         SPIRV::Decoration::FuncParamAttr, {Attr});
166eab7d363SIlia Diachkov       }
167eab7d363SIlia Diachkov       if (Arg.hasAttribute(Attribute::ZExt)) {
168eab7d363SIlia Diachkov         auto Attr =
169eab7d363SIlia Diachkov             static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext);
170eab7d363SIlia Diachkov         buildOpDecorate(VRegs[i][0], MIRBuilder,
171eab7d363SIlia Diachkov                         SPIRV::Decoration::FuncParamAttr, {Attr});
172eab7d363SIlia Diachkov       }
173*b8e1544bSIlia Diachkov       if (Arg.hasAttribute(Attribute::NoAlias)) {
174*b8e1544bSIlia Diachkov         auto Attr =
175*b8e1544bSIlia Diachkov             static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoAlias);
176*b8e1544bSIlia Diachkov         buildOpDecorate(VRegs[i][0], MIRBuilder,
177*b8e1544bSIlia Diachkov                         SPIRV::Decoration::FuncParamAttr, {Attr});
178*b8e1544bSIlia Diachkov       }
179*b8e1544bSIlia Diachkov       Node = F.getMetadata("kernel_arg_type_qual");
180*b8e1544bSIlia Diachkov       if (Node && i < Node->getNumOperands()) {
181*b8e1544bSIlia Diachkov         StringRef TypeQual = cast<MDString>(Node->getOperand(i))->getString();
182*b8e1544bSIlia Diachkov         if (TypeQual.compare("volatile") == 0)
183*b8e1544bSIlia Diachkov           buildOpDecorate(VRegs[i][0], MIRBuilder, SPIRV::Decoration::Volatile,
184*b8e1544bSIlia Diachkov                           {});
185*b8e1544bSIlia Diachkov       }
186*b8e1544bSIlia Diachkov       Node = F.getMetadata("spirv.ParameterDecorations");
187*b8e1544bSIlia Diachkov       if (Node && i < Node->getNumOperands() &&
188*b8e1544bSIlia Diachkov           isa<MDNode>(Node->getOperand(i))) {
189*b8e1544bSIlia Diachkov         MDNode *MD = cast<MDNode>(Node->getOperand(i));
190*b8e1544bSIlia Diachkov         for (const MDOperand &MDOp : MD->operands()) {
191*b8e1544bSIlia Diachkov           MDNode *MD2 = dyn_cast<MDNode>(MDOp);
192*b8e1544bSIlia Diachkov           assert(MD2 && "Metadata operand is expected");
193*b8e1544bSIlia Diachkov           ConstantInt *Const = getConstInt(MD2, 0);
194*b8e1544bSIlia Diachkov           assert(Const && "MDOperand should be ConstantInt");
195*b8e1544bSIlia Diachkov           auto Dec = static_cast<SPIRV::Decoration>(Const->getZExtValue());
196*b8e1544bSIlia Diachkov           std::vector<uint32_t> DecVec;
197*b8e1544bSIlia Diachkov           for (unsigned j = 1; j < MD2->getNumOperands(); j++) {
198*b8e1544bSIlia Diachkov             ConstantInt *Const = getConstInt(MD2, j);
199*b8e1544bSIlia Diachkov             assert(Const && "MDOperand should be ConstantInt");
200*b8e1544bSIlia Diachkov             DecVec.push_back(static_cast<uint32_t>(Const->getZExtValue()));
201*b8e1544bSIlia Diachkov           }
202*b8e1544bSIlia Diachkov           buildOpDecorate(VRegs[i][0], MIRBuilder, Dec, DecVec);
203*b8e1544bSIlia Diachkov         }
204*b8e1544bSIlia Diachkov       }
205ec259036SIlia Diachkov       ++i;
206ec259036SIlia Diachkov     }
207ec259036SIlia Diachkov   }
208ec259036SIlia Diachkov 
209ec259036SIlia Diachkov   // Generate a SPIR-V type for the function.
210eab7d363SIlia Diachkov   auto MRI = MIRBuilder.getMRI();
211ec259036SIlia Diachkov   Register FuncVReg = MRI->createGenericVirtualRegister(LLT::scalar(32));
212ec259036SIlia Diachkov   MRI->setRegClass(FuncVReg, &SPIRV::IDRegClass);
213fa2a7a25SAleksandr Bezzubikov   if (F.isDeclaration())
214fa2a7a25SAleksandr Bezzubikov     GR->add(&F, &MIRBuilder.getMF(), FuncVReg);
215*b8e1544bSIlia Diachkov   SPIRVType *RetTy = GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder);
216*b8e1544bSIlia Diachkov   SPIRVType *FuncTy = GR->getOrCreateOpTypeFunctionWithArgs(
217*b8e1544bSIlia Diachkov       FTy, RetTy, ArgTypeVRegs, MIRBuilder);
218eab7d363SIlia Diachkov 
219eab7d363SIlia Diachkov   // Build the OpTypeFunction declaring it.
220eab7d363SIlia Diachkov   uint32_t FuncControl = getFunctionControl(F);
221eab7d363SIlia Diachkov 
222ec259036SIlia Diachkov   MIRBuilder.buildInstr(SPIRV::OpFunction)
223ec259036SIlia Diachkov       .addDef(FuncVReg)
224*b8e1544bSIlia Diachkov       .addUse(GR->getSPIRVTypeID(RetTy))
225eab7d363SIlia Diachkov       .addImm(FuncControl)
226eab7d363SIlia Diachkov       .addUse(GR->getSPIRVTypeID(FuncTy));
227ec259036SIlia Diachkov 
228ec259036SIlia Diachkov   // Add OpFunctionParameters.
229*b8e1544bSIlia Diachkov   int i = 0;
230*b8e1544bSIlia Diachkov   for (const auto &Arg : F.args()) {
231ec259036SIlia Diachkov     assert(VRegs[i].size() == 1 && "Formal arg has multiple vregs");
232ec259036SIlia Diachkov     MRI->setRegClass(VRegs[i][0], &SPIRV::IDRegClass);
233ec259036SIlia Diachkov     MIRBuilder.buildInstr(SPIRV::OpFunctionParameter)
234ec259036SIlia Diachkov         .addDef(VRegs[i][0])
235*b8e1544bSIlia Diachkov         .addUse(GR->getSPIRVTypeID(ArgTypeVRegs[i]));
236fa2a7a25SAleksandr Bezzubikov     if (F.isDeclaration())
237*b8e1544bSIlia Diachkov       GR->add(&Arg, &MIRBuilder.getMF(), VRegs[i][0]);
238*b8e1544bSIlia Diachkov     i++;
239ec259036SIlia Diachkov   }
240eab7d363SIlia Diachkov   // Name the function.
241eab7d363SIlia Diachkov   if (F.hasName())
242eab7d363SIlia Diachkov     buildOpName(FuncVReg, F.getName(), MIRBuilder);
243eab7d363SIlia Diachkov 
244eab7d363SIlia Diachkov   // Handle entry points and function linkage.
245eab7d363SIlia Diachkov   if (F.getCallingConv() == CallingConv::SPIR_KERNEL) {
246eab7d363SIlia Diachkov     auto MIB = MIRBuilder.buildInstr(SPIRV::OpEntryPoint)
247eab7d363SIlia Diachkov                    .addImm(static_cast<uint32_t>(SPIRV::ExecutionModel::Kernel))
248eab7d363SIlia Diachkov                    .addUse(FuncVReg);
249eab7d363SIlia Diachkov     addStringImm(F.getName(), MIB);
250eab7d363SIlia Diachkov   } else if (F.getLinkage() == GlobalValue::LinkageTypes::ExternalLinkage ||
251eab7d363SIlia Diachkov              F.getLinkage() == GlobalValue::LinkOnceODRLinkage) {
252eab7d363SIlia Diachkov     auto LnkTy = F.isDeclaration() ? SPIRV::LinkageType::Import
253eab7d363SIlia Diachkov                                    : SPIRV::LinkageType::Export;
254eab7d363SIlia Diachkov     buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes,
255eab7d363SIlia Diachkov                     {static_cast<uint32_t>(LnkTy)}, F.getGlobalIdentifier());
256eab7d363SIlia Diachkov   }
257eab7d363SIlia Diachkov 
258ec259036SIlia Diachkov   return true;
259ec259036SIlia Diachkov }
260ec259036SIlia Diachkov 
lowerCall(MachineIRBuilder & MIRBuilder,CallLoweringInfo & Info) const261ec259036SIlia Diachkov bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
262ec259036SIlia Diachkov                                   CallLoweringInfo &Info) const {
263ec259036SIlia Diachkov   // Currently call returns should have single vregs.
264ec259036SIlia Diachkov   // TODO: handle the case of multiple registers.
265ec259036SIlia Diachkov   if (Info.OrigRet.Regs.size() > 1)
266ec259036SIlia Diachkov     return false;
267*b8e1544bSIlia Diachkov   MachineFunction &MF = MIRBuilder.getMF();
268*b8e1544bSIlia Diachkov   GR->setCurrentFunc(MF);
269*b8e1544bSIlia Diachkov   FunctionType *FTy = nullptr;
270*b8e1544bSIlia Diachkov   const Function *CF = nullptr;
271ec259036SIlia Diachkov 
272eab7d363SIlia Diachkov   // Emit a regular OpFunctionCall. If it's an externally declared function,
273*b8e1544bSIlia Diachkov   // be sure to emit its type and function declaration here. It will be hoisted
274*b8e1544bSIlia Diachkov   // globally later.
275eab7d363SIlia Diachkov   if (Info.Callee.isGlobal()) {
276*b8e1544bSIlia Diachkov     CF = dyn_cast_or_null<const Function>(Info.Callee.getGlobal());
277eab7d363SIlia Diachkov     // TODO: support constexpr casts and indirect calls.
278eab7d363SIlia Diachkov     if (CF == nullptr)
279eab7d363SIlia Diachkov       return false;
280*b8e1544bSIlia Diachkov     FTy = getOriginalFunctionType(*CF);
281*b8e1544bSIlia Diachkov   }
282*b8e1544bSIlia Diachkov 
283*b8e1544bSIlia Diachkov   Register ResVReg =
284*b8e1544bSIlia Diachkov       Info.OrigRet.Regs.empty() ? Register(0) : Info.OrigRet.Regs[0];
285*b8e1544bSIlia Diachkov   if (CF && CF->isDeclaration() &&
286*b8e1544bSIlia Diachkov       !GR->find(CF, &MIRBuilder.getMF()).isValid()) {
287eab7d363SIlia Diachkov     // Emit the type info and forward function declaration to the first MBB
288eab7d363SIlia Diachkov     // to ensure VReg definition dependencies are valid across all MBBs.
289*b8e1544bSIlia Diachkov     MachineIRBuilder FirstBlockBuilder;
290*b8e1544bSIlia Diachkov     FirstBlockBuilder.setMF(MF);
291*b8e1544bSIlia Diachkov     FirstBlockBuilder.setMBB(*MF.getBlockNumbered(0));
292eab7d363SIlia Diachkov 
293eab7d363SIlia Diachkov     SmallVector<ArrayRef<Register>, 8> VRegArgs;
294eab7d363SIlia Diachkov     SmallVector<SmallVector<Register, 1>, 8> ToInsert;
295eab7d363SIlia Diachkov     for (const Argument &Arg : CF->args()) {
296eab7d363SIlia Diachkov       if (MIRBuilder.getDataLayout().getTypeStoreSize(Arg.getType()).isZero())
297eab7d363SIlia Diachkov         continue; // Don't handle zero sized types.
298*b8e1544bSIlia Diachkov       ToInsert.push_back(
299*b8e1544bSIlia Diachkov           {MIRBuilder.getMRI()->createGenericVirtualRegister(LLT::scalar(32))});
300eab7d363SIlia Diachkov       VRegArgs.push_back(ToInsert.back());
301eab7d363SIlia Diachkov     }
302*b8e1544bSIlia Diachkov     // TODO: Reuse FunctionLoweringInfo
303eab7d363SIlia Diachkov     FunctionLoweringInfo FuncInfo;
304*b8e1544bSIlia Diachkov     lowerFormalArguments(FirstBlockBuilder, *CF, VRegArgs, FuncInfo);
305eab7d363SIlia Diachkov   }
306eab7d363SIlia Diachkov 
307ec259036SIlia Diachkov   // Make sure there's a valid return reg, even for functions returning void.
308*b8e1544bSIlia Diachkov   if (!ResVReg.isValid())
309ec259036SIlia Diachkov     ResVReg = MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::IDRegClass);
310eab7d363SIlia Diachkov   SPIRVType *RetType =
311*b8e1544bSIlia Diachkov       GR->assignTypeToVReg(FTy->getReturnType(), ResVReg, MIRBuilder);
312eab7d363SIlia Diachkov 
313ec259036SIlia Diachkov   // Emit the OpFunctionCall and its args.
314ec259036SIlia Diachkov   auto MIB = MIRBuilder.buildInstr(SPIRV::OpFunctionCall)
315ec259036SIlia Diachkov                  .addDef(ResVReg)
316eab7d363SIlia Diachkov                  .addUse(GR->getSPIRVTypeID(RetType))
317ec259036SIlia Diachkov                  .add(Info.Callee);
318ec259036SIlia Diachkov 
319ec259036SIlia Diachkov   for (const auto &Arg : Info.OrigArgs) {
320ec259036SIlia Diachkov     // Currently call args should have single vregs.
321ec259036SIlia Diachkov     if (Arg.Regs.size() > 1)
322ec259036SIlia Diachkov       return false;
323ec259036SIlia Diachkov     MIB.addUse(Arg.Regs[0]);
324ec259036SIlia Diachkov   }
325*b8e1544bSIlia Diachkov   const auto &STI = MF.getSubtarget();
326*b8e1544bSIlia Diachkov   return MIB.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
327*b8e1544bSIlia Diachkov                               *STI.getRegBankInfo());
328ec259036SIlia Diachkov }
329