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