1//===-- RISCVCallLowering.cpp - Call lowering -------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// This file implements the lowering of LLVM calls to machine code calls for
11/// GlobalISel.
12//
13//===----------------------------------------------------------------------===//
14
15#include "RISCVCallLowering.h"
16#include "RISCVCallingConv.h"
17#include "RISCVISelLowering.h"
18#include "RISCVMachineFunctionInfo.h"
19#include "RISCVSubtarget.h"
20#include "llvm/CodeGen/Analysis.h"
21#include "llvm/CodeGen/FunctionLoweringInfo.h"
22#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
23#include "llvm/CodeGen/MachineFrameInfo.h"
24
25using namespace llvm;
26
27namespace {
28
29struct RISCVOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner {
30private:
31 // The function used internally to assign args - we ignore the AssignFn stored
32 // by OutgoingValueAssigner since RISC-V implements its CC using a custom
33 // function with a different signature.
34 RISCVCCAssignFn *RISCVAssignFn;
35
36 // Whether this is assigning args for a return.
37 bool IsRet;
38
39public:
40 RISCVOutgoingValueAssigner(RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
41 : CallLowering::OutgoingValueAssigner(nullptr),
42 RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
43
44 bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
45 CCValAssign::LocInfo LocInfo,
46 const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
47 CCState &State) override {
48 if (RISCVAssignFn(ValNo, ValVT, LocVT, LocInfo, Flags, State, IsRet,
49 Info.Ty))
50 return true;
51
52 StackSize = State.getStackSize();
53 return false;
54 }
55};
56
57struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
58 RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
59 MachineInstrBuilder MIB)
60 : OutgoingValueHandler(B, MRI), MIB(MIB),
61 Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
62 Register getStackAddress(uint64_t MemSize, int64_t Offset,
63 MachinePointerInfo &MPO,
64 ISD::ArgFlagsTy Flags) override {
65 MachineFunction &MF = MIRBuilder.getMF();
66 LLT p0 = LLT::pointer(AddressSpace: 0, SizeInBits: Subtarget.getXLen());
67 LLT sXLen = LLT::scalar(SizeInBits: Subtarget.getXLen());
68
69 if (!SPReg)
70 SPReg = MIRBuilder.buildCopy(Res: p0, Op: Register(RISCV::X2)).getReg(Idx: 0);
71
72 auto OffsetReg = MIRBuilder.buildConstant(Res: sXLen, Val: Offset);
73
74 auto AddrReg = MIRBuilder.buildPtrAdd(Res: p0, Op0: SPReg, Op1: OffsetReg);
75
76 MPO = MachinePointerInfo::getStack(MF, Offset);
77 return AddrReg.getReg(Idx: 0);
78 }
79
80 void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
81 const MachinePointerInfo &MPO,
82 const CCValAssign &VA) override {
83 MachineFunction &MF = MIRBuilder.getMF();
84 uint64_t LocMemOffset = VA.getLocMemOffset();
85
86 // TODO: Move StackAlignment to subtarget and share with FrameLowering.
87 auto MMO =
88 MF.getMachineMemOperand(PtrInfo: MPO, f: MachineMemOperand::MOStore, MemTy,
89 base_alignment: commonAlignment(A: Align(16), Offset: LocMemOffset));
90
91 Register ExtReg = extendRegister(ValReg: ValVReg, VA);
92 MIRBuilder.buildStore(Val: ExtReg, Addr, MMO&: *MMO);
93 }
94
95 void assignValueToReg(Register ValVReg, Register PhysReg,
96 const CCValAssign &VA,
97 ISD::ArgFlagsTy Flags = {}) override {
98 Register ExtReg = extendRegister(ValReg: ValVReg, VA);
99 MIRBuilder.buildCopy(Res: PhysReg, Op: ExtReg);
100 MIB.addUse(RegNo: PhysReg, Flags: RegState::Implicit);
101 }
102
103 unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
104 ArrayRef<CCValAssign> VAs,
105 std::function<void()> *Thunk) override {
106 const CCValAssign &VA = VAs[0];
107 if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
108 (VA.getLocVT().isInteger() && VA.getValVT() == MVT::f16)) {
109 Register PhysReg = VA.getLocReg();
110
111 auto assignFunc = [=]() {
112 auto Trunc = MIRBuilder.buildAnyExt(Res: LLT(VA.getLocVT()), Op: Arg.Regs[0]);
113 MIRBuilder.buildCopy(Res: PhysReg, Op: Trunc);
114 MIB.addUse(RegNo: PhysReg, Flags: RegState::Implicit);
115 };
116
117 if (Thunk) {
118 *Thunk = std::move(assignFunc);
119 return 1;
120 }
121
122 assignFunc();
123 return 1;
124 }
125
126 assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
127 const CCValAssign &VAHi = VAs[1];
128
129 assert(VAHi.needsCustom() && "Value doesn't need custom handling");
130 assert(VA.getValNo() == VAHi.getValNo() &&
131 "Values belong to different arguments");
132
133 assert(VA.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
134 VA.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
135 "unexpected custom value");
136
137 Register NewRegs[] = {MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32)),
138 MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32))};
139 MIRBuilder.buildUnmerge(Res: NewRegs, Op: Arg.Regs[0]);
140
141 if (VAHi.isMemLoc()) {
142 LLT MemTy(VAHi.getLocVT());
143
144 MachinePointerInfo MPO;
145 Register StackAddr = getStackAddress(
146 MemSize: MemTy.getSizeInBytes(), Offset: VAHi.getLocMemOffset(), MPO, Flags: Arg.Flags[0]);
147
148 assignValueToAddress(ValVReg: NewRegs[1], Addr: StackAddr, MemTy, MPO,
149 VA: const_cast<CCValAssign &>(VAHi));
150 }
151
152 auto assignFunc = [=]() {
153 assignValueToReg(ValVReg: NewRegs[0], PhysReg: VA.getLocReg(), VA);
154 if (VAHi.isRegLoc())
155 assignValueToReg(ValVReg: NewRegs[1], PhysReg: VAHi.getLocReg(), VA: VAHi);
156 };
157
158 if (Thunk) {
159 *Thunk = std::move(assignFunc);
160 return 2;
161 }
162
163 assignFunc();
164 return 2;
165 }
166
167private:
168 MachineInstrBuilder MIB;
169
170 // Cache the SP register vreg if we need it more than once in this call site.
171 Register SPReg;
172
173 const RISCVSubtarget &Subtarget;
174};
175
176struct RISCVIncomingValueAssigner : public CallLowering::IncomingValueAssigner {
177private:
178 // The function used internally to assign args - we ignore the AssignFn stored
179 // by IncomingValueAssigner since RISC-V implements its CC using a custom
180 // function with a different signature.
181 RISCVCCAssignFn *RISCVAssignFn;
182
183 // Whether this is assigning args from a return.
184 bool IsRet;
185
186public:
187 RISCVIncomingValueAssigner(RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
188 : CallLowering::IncomingValueAssigner(nullptr),
189 RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
190
191 bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
192 CCValAssign::LocInfo LocInfo,
193 const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
194 CCState &State) override {
195 MachineFunction &MF = State.getMachineFunction();
196
197 if (LocVT.isScalableVector())
198 MF.getInfo<RISCVMachineFunctionInfo>()->setIsVectorCall();
199
200 if (RISCVAssignFn(ValNo, ValVT, LocVT, LocInfo, Flags, State, IsRet,
201 Info.Ty))
202 return true;
203
204 StackSize = State.getStackSize();
205 return false;
206 }
207};
208
209struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
210 RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
211 : IncomingValueHandler(B, MRI),
212 Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
213
214 Register getStackAddress(uint64_t MemSize, int64_t Offset,
215 MachinePointerInfo &MPO,
216 ISD::ArgFlagsTy Flags) override {
217 MachineFrameInfo &MFI = MIRBuilder.getMF().getFrameInfo();
218
219 int FI = MFI.CreateFixedObject(Size: MemSize, SPOffset: Offset, /*Immutable=*/IsImmutable: true);
220 MPO = MachinePointerInfo::getFixedStack(MF&: MIRBuilder.getMF(), FI);
221 return MIRBuilder.buildFrameIndex(Res: LLT::pointer(AddressSpace: 0, SizeInBits: Subtarget.getXLen()), Idx: FI)
222 .getReg(Idx: 0);
223 }
224
225 void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
226 const MachinePointerInfo &MPO,
227 const CCValAssign &VA) override {
228 MachineFunction &MF = MIRBuilder.getMF();
229 auto MMO = MF.getMachineMemOperand(PtrInfo: MPO, f: MachineMemOperand::MOLoad, MemTy,
230 base_alignment: inferAlignFromPtrInfo(MF, MPO));
231 MIRBuilder.buildLoad(Res: ValVReg, Addr, MMO&: *MMO);
232 }
233
234 void assignValueToReg(Register ValVReg, Register PhysReg,
235 const CCValAssign &VA,
236 ISD::ArgFlagsTy Flags = {}) override {
237 markPhysRegUsed(PhysReg);
238 IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);
239 }
240
241 unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
242 ArrayRef<CCValAssign> VAs,
243 std::function<void()> *Thunk) override {
244 const CCValAssign &VA = VAs[0];
245 if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
246 (VA.getLocVT().isInteger() && VA.getValVT() == MVT::f16)) {
247 Register PhysReg = VA.getLocReg();
248
249 markPhysRegUsed(PhysReg);
250
251 LLT LocTy(VA.getLocVT());
252 auto Copy = MIRBuilder.buildCopy(Res: LocTy, Op: PhysReg);
253
254 MIRBuilder.buildTrunc(Res: Arg.Regs[0], Op: Copy.getReg(Idx: 0));
255 return 1;
256 }
257
258 assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
259 const CCValAssign &VAHi = VAs[1];
260
261 assert(VAHi.needsCustom() && "Value doesn't need custom handling");
262 assert(VA.getValNo() == VAHi.getValNo() &&
263 "Values belong to different arguments");
264
265 assert(VA.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
266 VA.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
267 "unexpected custom value");
268
269 Register NewRegs[] = {MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32)),
270 MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32))};
271
272 if (VAHi.isMemLoc()) {
273 LLT MemTy(VAHi.getLocVT());
274
275 MachinePointerInfo MPO;
276 Register StackAddr = getStackAddress(
277 MemSize: MemTy.getSizeInBytes(), Offset: VAHi.getLocMemOffset(), MPO, Flags: Arg.Flags[0]);
278
279 assignValueToAddress(ValVReg: NewRegs[1], Addr: StackAddr, MemTy, MPO,
280 VA: const_cast<CCValAssign &>(VAHi));
281 }
282
283 assignValueToReg(ValVReg: NewRegs[0], PhysReg: VA.getLocReg(), VA);
284 if (VAHi.isRegLoc())
285 assignValueToReg(ValVReg: NewRegs[1], PhysReg: VAHi.getLocReg(), VA: VAHi);
286
287 MIRBuilder.buildMergeLikeInstr(Res: Arg.Regs[0], Ops: NewRegs);
288
289 return 2;
290 }
291
292 /// How the physical register gets marked varies between formal
293 /// parameters (it's a basic-block live-in), and a call instruction
294 /// (it's an implicit-def of the BL).
295 virtual void markPhysRegUsed(MCRegister PhysReg) = 0;
296
297private:
298 const RISCVSubtarget &Subtarget;
299};
300
301struct RISCVFormalArgHandler : public RISCVIncomingValueHandler {
302 RISCVFormalArgHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
303 : RISCVIncomingValueHandler(B, MRI) {}
304
305 void markPhysRegUsed(MCRegister PhysReg) override {
306 MIRBuilder.getMRI()->addLiveIn(Reg: PhysReg);
307 MIRBuilder.getMBB().addLiveIn(PhysReg);
308 }
309};
310
311struct RISCVCallReturnHandler : public RISCVIncomingValueHandler {
312 RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
313 MachineInstrBuilder &MIB)
314 : RISCVIncomingValueHandler(B, MRI), MIB(MIB) {}
315
316 void markPhysRegUsed(MCRegister PhysReg) override {
317 MIB.addDef(RegNo: PhysReg, Flags: RegState::Implicit);
318 }
319
320 MachineInstrBuilder MIB;
321};
322
323} // namespace
324
325RISCVCallLowering::RISCVCallLowering(const RISCVTargetLowering &TLI)
326 : CallLowering(&TLI) {}
327
328/// Return true if scalable vector with ScalarTy is legal for lowering.
329static bool isLegalElementTypeForRVV(Type *EltTy,
330 const RISCVSubtarget &Subtarget) {
331 if (EltTy->isPointerTy())
332 return Subtarget.is64Bit() ? Subtarget.hasVInstructionsI64() : true;
333 if (EltTy->isIntegerTy(Bitwidth: 1) || EltTy->isIntegerTy(Bitwidth: 8) ||
334 EltTy->isIntegerTy(Bitwidth: 16) || EltTy->isIntegerTy(Bitwidth: 32))
335 return true;
336 if (EltTy->isIntegerTy(Bitwidth: 64))
337 return Subtarget.hasVInstructionsI64();
338 if (EltTy->isHalfTy())
339 return Subtarget.hasVInstructionsF16Minimal();
340 if (EltTy->isBFloatTy())
341 return Subtarget.hasVInstructionsBF16Minimal();
342 if (EltTy->isFloatTy())
343 return Subtarget.hasVInstructionsF32();
344 if (EltTy->isDoubleTy())
345 return Subtarget.hasVInstructionsF64();
346 return false;
347}
348
349// TODO: Support all argument types.
350// TODO: Remove IsLowerArgs argument by adding support for vectors in lowerCall.
351static bool isSupportedArgumentType(Type *T, const RISCVSubtarget &Subtarget,
352 bool IsLowerArgs = false) {
353 if (T->isIntegerTy())
354 return true;
355 if (T->isHalfTy() || T->isFloatTy() || T->isDoubleTy() || T->isFP128Ty())
356 return true;
357 if (T->isPointerTy())
358 return true;
359 if (T->isArrayTy())
360 return isSupportedArgumentType(T: T->getArrayElementType(), Subtarget,
361 IsLowerArgs);
362 // TODO: Support fixed vector types.
363 if (IsLowerArgs && T->isVectorTy() && Subtarget.hasVInstructions() &&
364 T->isScalableTy() &&
365 isLegalElementTypeForRVV(EltTy: T->getScalarType(), Subtarget))
366 return true;
367 return false;
368}
369
370// TODO: Only integer, pointer and aggregate types are supported now.
371// TODO: Remove IsLowerRetVal argument by adding support for vectors in
372// lowerCall.
373static bool isSupportedReturnType(Type *T, const RISCVSubtarget &Subtarget,
374 bool IsLowerRetVal = false) {
375 if (T->isIntegerTy() || T->isFloatingPointTy() || T->isPointerTy())
376 return true;
377
378 if (T->isArrayTy())
379 return isSupportedReturnType(T: T->getArrayElementType(), Subtarget);
380
381 if (T->isStructTy()) {
382 auto StructT = cast<StructType>(Val: T);
383 for (unsigned i = 0, e = StructT->getNumElements(); i != e; ++i)
384 if (!isSupportedReturnType(T: StructT->getElementType(N: i), Subtarget))
385 return false;
386 return true;
387 }
388
389 if (IsLowerRetVal && T->isVectorTy() && Subtarget.hasVInstructions() &&
390 T->isScalableTy() &&
391 isLegalElementTypeForRVV(EltTy: T->getScalarType(), Subtarget))
392 return true;
393
394 return false;
395}
396
397bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
398 const Value *Val, ArrayRef<Register> VRegs,
399 FunctionLoweringInfo &FLI) const {
400 assert(!Val == VRegs.empty() && "Return value without a vreg");
401 MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(Opcode: RISCV::PseudoRET);
402
403 if (!FLI.CanLowerReturn) {
404 insertSRetStores(MIRBuilder, RetTy: Val->getType(), VRegs, DemoteReg: FLI.DemoteRegister);
405 } else if (!VRegs.empty()) {
406 const RISCVSubtarget &Subtarget =
407 MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
408 if (!isSupportedReturnType(T: Val->getType(), Subtarget,
409 /*IsLowerRetVal=*/true))
410 return false;
411
412 MachineFunction &MF = MIRBuilder.getMF();
413 const DataLayout &DL = MF.getDataLayout();
414 const Function &F = MF.getFunction();
415 CallingConv::ID CC = F.getCallingConv();
416
417 ArgInfo OrigRetInfo(VRegs, Val->getType(), 0);
418 setArgFlags(Arg&: OrigRetInfo, OpIdx: AttributeList::ReturnIndex, DL, FuncInfo: F);
419
420 SmallVector<ArgInfo, 4> SplitRetInfos;
421 splitToValueTypes(OrigArgInfo: OrigRetInfo, SplitArgs&: SplitRetInfos, DL, CallConv: CC);
422
423 RISCVOutgoingValueAssigner Assigner(
424 CC == CallingConv::Fast ? CC_RISCV_FastCC : CC_RISCV,
425 /*IsRet=*/true);
426 RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret);
427 if (!determineAndHandleAssignments(Handler, Assigner, Args&: SplitRetInfos,
428 MIRBuilder, CallConv: CC, IsVarArg: F.isVarArg()))
429 return false;
430 }
431
432 MIRBuilder.insertInstr(MIB: Ret);
433 return true;
434}
435
436bool RISCVCallLowering::canLowerReturn(MachineFunction &MF,
437 CallingConv::ID CallConv,
438 SmallVectorImpl<BaseArgInfo> &Outs,
439 bool IsVarArg) const {
440 SmallVector<CCValAssign, 16> ArgLocs;
441 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs,
442 MF.getFunction().getContext());
443
444 for (unsigned I = 0, E = Outs.size(); I < E; ++I) {
445 MVT VT = MVT::getVT(Ty: Outs[I].Ty);
446 if (CC_RISCV(ValNo: I, ValVT: VT, LocVT: VT, LocInfo: CCValAssign::Full, ArgFlags: Outs[I].Flags[0], State&: CCInfo,
447 /*isRet=*/IsRet: true, OrigTy: nullptr))
448 return false;
449 }
450 return true;
451}
452
453/// If there are varargs that were passed in a0-a7, the data in those registers
454/// must be copied to the varargs save area on the stack.
455void RISCVCallLowering::saveVarArgRegisters(
456 MachineIRBuilder &MIRBuilder, CallLowering::IncomingValueHandler &Handler,
457 IncomingValueAssigner &Assigner, CCState &CCInfo) const {
458 MachineFunction &MF = MIRBuilder.getMF();
459 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
460 unsigned XLenInBytes = Subtarget.getXLen() / 8;
461 ArrayRef<MCPhysReg> ArgRegs = RISCV::getArgGPRs(ABI: Subtarget.getTargetABI());
462 MachineRegisterInfo &MRI = MF.getRegInfo();
463 unsigned Idx = CCInfo.getFirstUnallocated(Regs: ArgRegs);
464 MachineFrameInfo &MFI = MF.getFrameInfo();
465 RISCVMachineFunctionInfo *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
466
467 // Size of the vararg save area. For now, the varargs save area is either
468 // zero or large enough to hold a0-a7.
469 int VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx);
470 int FI;
471
472 // If all registers are allocated, then all varargs must be passed on the
473 // stack and we don't need to save any argregs.
474 if (VarArgsSaveSize == 0) {
475 int VaArgOffset = Assigner.StackSize;
476 FI = MFI.CreateFixedObject(Size: XLenInBytes, SPOffset: VaArgOffset, IsImmutable: true);
477 } else {
478 int VaArgOffset = -VarArgsSaveSize;
479 FI = MFI.CreateFixedObject(Size: VarArgsSaveSize, SPOffset: VaArgOffset, IsImmutable: true);
480
481 // If saving an odd number of registers then create an extra stack slot to
482 // ensure that the frame pointer is 2*XLEN-aligned, which in turn ensures
483 // offsets to even-numbered registered remain 2*XLEN-aligned.
484 if (Idx % 2) {
485 MFI.CreateFixedObject(Size: XLenInBytes,
486 SPOffset: VaArgOffset - static_cast<int>(XLenInBytes), IsImmutable: true);
487 VarArgsSaveSize += XLenInBytes;
488 }
489
490 const LLT p0 = LLT::pointer(AddressSpace: MF.getDataLayout().getAllocaAddrSpace(),
491 SizeInBits: Subtarget.getXLen());
492 const LLT sXLen = LLT::scalar(SizeInBits: Subtarget.getXLen());
493
494 auto FIN = MIRBuilder.buildFrameIndex(Res: p0, Idx: FI);
495 auto Offset = MIRBuilder.buildConstant(
496 Res: MRI.createGenericVirtualRegister(Ty: sXLen), Val: XLenInBytes);
497
498 // Copy the integer registers that may have been used for passing varargs
499 // to the vararg save area.
500 const MVT XLenVT = Subtarget.getXLenVT();
501 for (unsigned I = Idx; I < ArgRegs.size(); ++I) {
502 const Register VReg = MRI.createGenericVirtualRegister(Ty: sXLen);
503 Handler.assignValueToReg(
504 ValVReg: VReg, PhysReg: ArgRegs[I],
505 VA: CCValAssign::getReg(ValNo: I + MF.getFunction().getNumOperands(), ValVT: XLenVT,
506 Reg: ArgRegs[I], LocVT: XLenVT, HTP: CCValAssign::Full));
507 auto MPO =
508 MachinePointerInfo::getFixedStack(MF, FI, Offset: (I - Idx) * XLenInBytes);
509 MIRBuilder.buildStore(Val: VReg, Addr: FIN, PtrInfo: MPO, Alignment: inferAlignFromPtrInfo(MF, MPO));
510 FIN = MIRBuilder.buildPtrAdd(Res: MRI.createGenericVirtualRegister(Ty: p0),
511 Op0: FIN.getReg(Idx: 0), Op1: Offset);
512 }
513 }
514
515 // Record the frame index of the first variable argument which is a value
516 // necessary to G_VASTART.
517 RVFI->setVarArgsFrameIndex(FI);
518 RVFI->setVarArgsSaveSize(VarArgsSaveSize);
519}
520
521bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
522 const Function &F,
523 ArrayRef<ArrayRef<Register>> VRegs,
524 FunctionLoweringInfo &FLI) const {
525 MachineFunction &MF = MIRBuilder.getMF();
526
527 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
528 for (auto &Arg : F.args()) {
529 if (!isSupportedArgumentType(T: Arg.getType(), Subtarget,
530 /*IsLowerArgs=*/true))
531 return false;
532 }
533
534 MachineRegisterInfo &MRI = MF.getRegInfo();
535 const DataLayout &DL = MF.getDataLayout();
536 CallingConv::ID CC = F.getCallingConv();
537
538 SmallVector<ArgInfo, 32> SplitArgInfos;
539
540 // Insert the hidden sret parameter if the return value won't fit in the
541 // return registers.
542 if (!FLI.CanLowerReturn)
543 insertSRetIncomingArgument(F, SplitArgs&: SplitArgInfos, DemoteReg&: FLI.DemoteRegister, MRI, DL);
544
545 unsigned Index = 0;
546 for (auto &Arg : F.args()) {
547 // Construct the ArgInfo object from destination register and argument type.
548 ArgInfo AInfo(VRegs[Index], Arg.getType(), Index);
549 setArgFlags(Arg&: AInfo, OpIdx: Index + AttributeList::FirstArgIndex, DL, FuncInfo: F);
550
551 // Handle any required merging from split value types from physical
552 // registers into the desired VReg. ArgInfo objects are constructed
553 // correspondingly and appended to SplitArgInfos.
554 splitToValueTypes(OrigArgInfo: AInfo, SplitArgs&: SplitArgInfos, DL, CallConv: CC);
555
556 ++Index;
557 }
558
559 RISCVIncomingValueAssigner Assigner(CC == CallingConv::Fast ? CC_RISCV_FastCC
560 : CC_RISCV,
561 /*IsRet=*/false);
562 RISCVFormalArgHandler Handler(MIRBuilder, MF.getRegInfo());
563
564 SmallVector<CCValAssign, 16> ArgLocs;
565 CCState CCInfo(CC, F.isVarArg(), MIRBuilder.getMF(), ArgLocs, F.getContext());
566 if (!determineAssignments(Assigner, Args&: SplitArgInfos, CCInfo) ||
567 !handleAssignments(Handler, Args&: SplitArgInfos, CCState&: CCInfo, ArgLocs, MIRBuilder))
568 return false;
569
570 if (F.isVarArg())
571 saveVarArgRegisters(MIRBuilder, Handler, Assigner, CCInfo);
572
573 return true;
574}
575
576bool RISCVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
577 CallLoweringInfo &Info) const {
578 MachineFunction &MF = MIRBuilder.getMF();
579 const DataLayout &DL = MF.getDataLayout();
580 CallingConv::ID CC = Info.CallConv;
581
582 const RISCVSubtarget &Subtarget =
583 MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
584 for (auto &AInfo : Info.OrigArgs) {
585 if (!isSupportedArgumentType(T: AInfo.Ty, Subtarget))
586 return false;
587 if (AInfo.Flags[0].isByVal())
588 return false;
589 }
590
591 if (!Info.OrigRet.Ty->isVoidTy() &&
592 !isSupportedReturnType(T: Info.OrigRet.Ty, Subtarget))
593 return false;
594
595 MachineInstrBuilder CallSeqStart =
596 MIRBuilder.buildInstr(Opcode: RISCV::ADJCALLSTACKDOWN);
597
598 SmallVector<ArgInfo, 32> SplitArgInfos;
599 for (auto &AInfo : Info.OrigArgs) {
600 // Handle any required unmerging of split value types from a given VReg into
601 // physical registers. ArgInfo objects are constructed correspondingly and
602 // appended to SplitArgInfos.
603 splitToValueTypes(OrigArgInfo: AInfo, SplitArgs&: SplitArgInfos, DL, CallConv: CC);
604 }
605
606 // TODO: Support tail calls.
607 Info.IsTailCall = false;
608
609 // Select the recommended relocation type R_RISCV_CALL_PLT.
610 if (!Info.Callee.isReg())
611 Info.Callee.setTargetFlags(RISCVII::MO_CALL);
612
613 MachineInstrBuilder Call =
614 MIRBuilder
615 .buildInstrNoInsert(Opcode: Info.Callee.isReg() ? RISCV::PseudoCALLIndirect
616 : RISCV::PseudoCALL)
617 .add(MO: Info.Callee);
618 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
619 Call.addRegMask(Mask: TRI->getCallPreservedMask(MF, Info.CallConv));
620
621 RISCVOutgoingValueAssigner ArgAssigner(
622 CC == CallingConv::Fast ? CC_RISCV_FastCC : CC_RISCV,
623 /*IsRet=*/false);
624 RISCVOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), Call);
625 if (!determineAndHandleAssignments(Handler&: ArgHandler, Assigner&: ArgAssigner, Args&: SplitArgInfos,
626 MIRBuilder, CallConv: CC, IsVarArg: Info.IsVarArg))
627 return false;
628
629 MIRBuilder.insertInstr(MIB: Call);
630
631 CallSeqStart.addImm(Val: ArgAssigner.StackSize).addImm(Val: 0);
632 MIRBuilder.buildInstr(Opcode: RISCV::ADJCALLSTACKUP)
633 .addImm(Val: ArgAssigner.StackSize)
634 .addImm(Val: 0);
635
636 // If Callee is a reg, since it is used by a target specific
637 // instruction, it must have a register class matching the
638 // constraint of that instruction.
639 if (Call->getOperand(i: 0).isReg())
640 constrainOperandRegClass(MF, TRI: *TRI, MRI&: MF.getRegInfo(),
641 TII: *Subtarget.getInstrInfo(),
642 RBI: *Subtarget.getRegBankInfo(), InsertPt&: *Call,
643 II: Call->getDesc(), RegMO&: Call->getOperand(i: 0), OpIdx: 0);
644
645 if (Info.CanLowerReturn && !Info.OrigRet.Ty->isVoidTy()) {
646 SmallVector<ArgInfo, 4> SplitRetInfos;
647 splitToValueTypes(OrigArgInfo: Info.OrigRet, SplitArgs&: SplitRetInfos, DL, CallConv: CC);
648
649 RISCVIncomingValueAssigner RetAssigner(
650 CC == CallingConv::Fast ? CC_RISCV_FastCC : CC_RISCV,
651 /*IsRet=*/true);
652 RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call);
653 if (!determineAndHandleAssignments(Handler&: RetHandler, Assigner&: RetAssigner, Args&: SplitRetInfos,
654 MIRBuilder, CallConv: CC, IsVarArg: Info.IsVarArg))
655 return false;
656 }
657
658 if (!Info.CanLowerReturn)
659 insertSRetLoads(MIRBuilder, RetTy: Info.OrigRet.Ty, VRegs: Info.OrigRet.Regs,
660 DemoteReg: Info.DemoteRegister, FI: Info.DemoteStackIndex);
661
662 return true;
663}
664