1bdd1243dSDimitry Andric //===-- RISCVCallLowering.cpp - Call lowering -------------------*- C++ -*-===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric //
9bdd1243dSDimitry Andric /// \file
10bdd1243dSDimitry Andric /// This file implements the lowering of LLVM calls to machine code calls for
11bdd1243dSDimitry Andric /// GlobalISel.
12bdd1243dSDimitry Andric //
13bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
14bdd1243dSDimitry Andric
15bdd1243dSDimitry Andric #include "RISCVCallLowering.h"
16bdd1243dSDimitry Andric #include "RISCVISelLowering.h"
175f757f3fSDimitry Andric #include "RISCVMachineFunctionInfo.h"
1806c3fb27SDimitry Andric #include "RISCVSubtarget.h"
1906c3fb27SDimitry Andric #include "llvm/CodeGen/Analysis.h"
20bdd1243dSDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
215f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
22bdd1243dSDimitry Andric
23bdd1243dSDimitry Andric using namespace llvm;
24bdd1243dSDimitry Andric
2506c3fb27SDimitry Andric namespace {
2606c3fb27SDimitry Andric
2706c3fb27SDimitry Andric struct RISCVOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner {
2806c3fb27SDimitry Andric private:
2906c3fb27SDimitry Andric // The function used internally to assign args - we ignore the AssignFn stored
3006c3fb27SDimitry Andric // by OutgoingValueAssigner since RISC-V implements its CC using a custom
3106c3fb27SDimitry Andric // function with a different signature.
3206c3fb27SDimitry Andric RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn;
3306c3fb27SDimitry Andric
3406c3fb27SDimitry Andric // Whether this is assigning args for a return.
3506c3fb27SDimitry Andric bool IsRet;
3606c3fb27SDimitry Andric
3706c3fb27SDimitry Andric public:
RISCVOutgoingValueAssigner__anon7474aaf10111::RISCVOutgoingValueAssigner3806c3fb27SDimitry Andric RISCVOutgoingValueAssigner(
3906c3fb27SDimitry Andric RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
4006c3fb27SDimitry Andric : CallLowering::OutgoingValueAssigner(nullptr),
4106c3fb27SDimitry Andric RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
4206c3fb27SDimitry Andric
assignArg__anon7474aaf10111::RISCVOutgoingValueAssigner4306c3fb27SDimitry Andric bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
4406c3fb27SDimitry Andric CCValAssign::LocInfo LocInfo,
4506c3fb27SDimitry Andric const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
4606c3fb27SDimitry Andric CCState &State) override {
4706c3fb27SDimitry Andric MachineFunction &MF = State.getMachineFunction();
4806c3fb27SDimitry Andric const DataLayout &DL = MF.getDataLayout();
4906c3fb27SDimitry Andric const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
5006c3fb27SDimitry Andric
515f757f3fSDimitry Andric if (RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT,
525f757f3fSDimitry Andric LocInfo, Flags, State, Info.IsFixed, IsRet, Info.Ty,
535f757f3fSDimitry Andric *Subtarget.getTargetLowering(),
545f757f3fSDimitry Andric /*FirstMaskArgument=*/std::nullopt))
555f757f3fSDimitry Andric return true;
565f757f3fSDimitry Andric
575f757f3fSDimitry Andric StackSize = State.getStackSize();
585f757f3fSDimitry Andric return false;
5906c3fb27SDimitry Andric }
6006c3fb27SDimitry Andric };
6106c3fb27SDimitry Andric
6206c3fb27SDimitry Andric struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
RISCVOutgoingValueHandler__anon7474aaf10111::RISCVOutgoingValueHandler6306c3fb27SDimitry Andric RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
6406c3fb27SDimitry Andric MachineInstrBuilder MIB)
655f757f3fSDimitry Andric : OutgoingValueHandler(B, MRI), MIB(MIB),
665f757f3fSDimitry Andric Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
getStackAddress__anon7474aaf10111::RISCVOutgoingValueHandler6706c3fb27SDimitry Andric Register getStackAddress(uint64_t MemSize, int64_t Offset,
6806c3fb27SDimitry Andric MachinePointerInfo &MPO,
6906c3fb27SDimitry Andric ISD::ArgFlagsTy Flags) override {
705f757f3fSDimitry Andric MachineFunction &MF = MIRBuilder.getMF();
715f757f3fSDimitry Andric LLT p0 = LLT::pointer(0, Subtarget.getXLen());
725f757f3fSDimitry Andric LLT sXLen = LLT::scalar(Subtarget.getXLen());
735f757f3fSDimitry Andric
745f757f3fSDimitry Andric if (!SPReg)
755f757f3fSDimitry Andric SPReg = MIRBuilder.buildCopy(p0, Register(RISCV::X2)).getReg(0);
765f757f3fSDimitry Andric
775f757f3fSDimitry Andric auto OffsetReg = MIRBuilder.buildConstant(sXLen, Offset);
785f757f3fSDimitry Andric
795f757f3fSDimitry Andric auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg);
805f757f3fSDimitry Andric
815f757f3fSDimitry Andric MPO = MachinePointerInfo::getStack(MF, Offset);
825f757f3fSDimitry Andric return AddrReg.getReg(0);
8306c3fb27SDimitry Andric }
8406c3fb27SDimitry Andric
assignValueToAddress__anon7474aaf10111::RISCVOutgoingValueHandler8506c3fb27SDimitry Andric void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
865f757f3fSDimitry Andric const MachinePointerInfo &MPO,
875f757f3fSDimitry Andric const CCValAssign &VA) override {
885f757f3fSDimitry Andric MachineFunction &MF = MIRBuilder.getMF();
895f757f3fSDimitry Andric uint64_t LocMemOffset = VA.getLocMemOffset();
905f757f3fSDimitry Andric
915f757f3fSDimitry Andric // TODO: Move StackAlignment to subtarget and share with FrameLowering.
925f757f3fSDimitry Andric auto MMO =
935f757f3fSDimitry Andric MF.getMachineMemOperand(MPO, MachineMemOperand::MOStore, MemTy,
945f757f3fSDimitry Andric commonAlignment(Align(16), LocMemOffset));
955f757f3fSDimitry Andric
965f757f3fSDimitry Andric Register ExtReg = extendRegister(ValVReg, VA);
975f757f3fSDimitry Andric MIRBuilder.buildStore(ExtReg, Addr, *MMO);
9806c3fb27SDimitry Andric }
9906c3fb27SDimitry Andric
assignValueToReg__anon7474aaf10111::RISCVOutgoingValueHandler10006c3fb27SDimitry Andric void assignValueToReg(Register ValVReg, Register PhysReg,
1015f757f3fSDimitry Andric const CCValAssign &VA) override {
1025f757f3fSDimitry Andric // If we're passing an f32 value into an i64, anyextend before copying.
1035f757f3fSDimitry Andric if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
1045f757f3fSDimitry Andric ValVReg = MIRBuilder.buildAnyExt(LLT::scalar(64), ValVReg).getReg(0);
1055f757f3fSDimitry Andric
10606c3fb27SDimitry Andric Register ExtReg = extendRegister(ValVReg, VA);
10706c3fb27SDimitry Andric MIRBuilder.buildCopy(PhysReg, ExtReg);
10806c3fb27SDimitry Andric MIB.addUse(PhysReg, RegState::Implicit);
10906c3fb27SDimitry Andric }
1105f757f3fSDimitry Andric
assignCustomValue__anon7474aaf10111::RISCVOutgoingValueHandler1115f757f3fSDimitry Andric unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
1125f757f3fSDimitry Andric ArrayRef<CCValAssign> VAs,
1135f757f3fSDimitry Andric std::function<void()> *Thunk) override {
1145f757f3fSDimitry Andric assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
1155f757f3fSDimitry Andric const CCValAssign &VALo = VAs[0];
1165f757f3fSDimitry Andric const CCValAssign &VAHi = VAs[1];
1175f757f3fSDimitry Andric
1185f757f3fSDimitry Andric assert(VAHi.needsCustom() && "Value doesn't need custom handling");
1195f757f3fSDimitry Andric assert(VALo.getValNo() == VAHi.getValNo() &&
1205f757f3fSDimitry Andric "Values belong to different arguments");
1215f757f3fSDimitry Andric
1225f757f3fSDimitry Andric assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
1235f757f3fSDimitry Andric VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
1245f757f3fSDimitry Andric "unexpected custom value");
1255f757f3fSDimitry Andric
1265f757f3fSDimitry Andric Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
1275f757f3fSDimitry Andric MRI.createGenericVirtualRegister(LLT::scalar(32))};
1285f757f3fSDimitry Andric MIRBuilder.buildUnmerge(NewRegs, Arg.Regs[0]);
1295f757f3fSDimitry Andric
1305f757f3fSDimitry Andric if (VAHi.isMemLoc()) {
1315f757f3fSDimitry Andric LLT MemTy(VAHi.getLocVT());
1325f757f3fSDimitry Andric
1335f757f3fSDimitry Andric MachinePointerInfo MPO;
1345f757f3fSDimitry Andric Register StackAddr = getStackAddress(
1355f757f3fSDimitry Andric MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
1365f757f3fSDimitry Andric
1375f757f3fSDimitry Andric assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
1385f757f3fSDimitry Andric const_cast<CCValAssign &>(VAHi));
1395f757f3fSDimitry Andric }
1405f757f3fSDimitry Andric
1415f757f3fSDimitry Andric auto assignFunc = [=]() {
1425f757f3fSDimitry Andric assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
1435f757f3fSDimitry Andric if (VAHi.isRegLoc())
1445f757f3fSDimitry Andric assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
1455f757f3fSDimitry Andric };
1465f757f3fSDimitry Andric
1475f757f3fSDimitry Andric if (Thunk) {
1485f757f3fSDimitry Andric *Thunk = assignFunc;
149*7a6dacacSDimitry Andric return 2;
1505f757f3fSDimitry Andric }
1515f757f3fSDimitry Andric
1525f757f3fSDimitry Andric assignFunc();
153*7a6dacacSDimitry Andric return 2;
1545f757f3fSDimitry Andric }
1555f757f3fSDimitry Andric
1565f757f3fSDimitry Andric private:
1575f757f3fSDimitry Andric MachineInstrBuilder MIB;
1585f757f3fSDimitry Andric
1595f757f3fSDimitry Andric // Cache the SP register vreg if we need it more than once in this call site.
1605f757f3fSDimitry Andric Register SPReg;
1615f757f3fSDimitry Andric
1625f757f3fSDimitry Andric const RISCVSubtarget &Subtarget;
16306c3fb27SDimitry Andric };
16406c3fb27SDimitry Andric
16506c3fb27SDimitry Andric struct RISCVIncomingValueAssigner : public CallLowering::IncomingValueAssigner {
16606c3fb27SDimitry Andric private:
16706c3fb27SDimitry Andric // The function used internally to assign args - we ignore the AssignFn stored
16806c3fb27SDimitry Andric // by IncomingValueAssigner since RISC-V implements its CC using a custom
16906c3fb27SDimitry Andric // function with a different signature.
17006c3fb27SDimitry Andric RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn;
17106c3fb27SDimitry Andric
17206c3fb27SDimitry Andric // Whether this is assigning args from a return.
17306c3fb27SDimitry Andric bool IsRet;
17406c3fb27SDimitry Andric
17506c3fb27SDimitry Andric public:
RISCVIncomingValueAssigner__anon7474aaf10111::RISCVIncomingValueAssigner17606c3fb27SDimitry Andric RISCVIncomingValueAssigner(
17706c3fb27SDimitry Andric RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
17806c3fb27SDimitry Andric : CallLowering::IncomingValueAssigner(nullptr),
17906c3fb27SDimitry Andric RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
18006c3fb27SDimitry Andric
assignArg__anon7474aaf10111::RISCVIncomingValueAssigner18106c3fb27SDimitry Andric bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
18206c3fb27SDimitry Andric CCValAssign::LocInfo LocInfo,
18306c3fb27SDimitry Andric const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
18406c3fb27SDimitry Andric CCState &State) override {
18506c3fb27SDimitry Andric MachineFunction &MF = State.getMachineFunction();
18606c3fb27SDimitry Andric const DataLayout &DL = MF.getDataLayout();
18706c3fb27SDimitry Andric const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
18806c3fb27SDimitry Andric
1895f757f3fSDimitry Andric if (LocVT.isScalableVector())
1905f757f3fSDimitry Andric MF.getInfo<RISCVMachineFunctionInfo>()->setIsVectorCall();
1915f757f3fSDimitry Andric
1925f757f3fSDimitry Andric if (RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT,
1935f757f3fSDimitry Andric LocInfo, Flags, State, /*IsFixed=*/true, IsRet, Info.Ty,
1945f757f3fSDimitry Andric *Subtarget.getTargetLowering(),
1955f757f3fSDimitry Andric /*FirstMaskArgument=*/std::nullopt))
1965f757f3fSDimitry Andric return true;
1975f757f3fSDimitry Andric
1985f757f3fSDimitry Andric StackSize = State.getStackSize();
1995f757f3fSDimitry Andric return false;
20006c3fb27SDimitry Andric }
20106c3fb27SDimitry Andric };
20206c3fb27SDimitry Andric
20306c3fb27SDimitry Andric struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
RISCVIncomingValueHandler__anon7474aaf10111::RISCVIncomingValueHandler20406c3fb27SDimitry Andric RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
2055f757f3fSDimitry Andric : IncomingValueHandler(B, MRI),
2065f757f3fSDimitry Andric Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
20706c3fb27SDimitry Andric
getStackAddress__anon7474aaf10111::RISCVIncomingValueHandler20806c3fb27SDimitry Andric Register getStackAddress(uint64_t MemSize, int64_t Offset,
20906c3fb27SDimitry Andric MachinePointerInfo &MPO,
21006c3fb27SDimitry Andric ISD::ArgFlagsTy Flags) override {
2115f757f3fSDimitry Andric MachineFrameInfo &MFI = MIRBuilder.getMF().getFrameInfo();
2125f757f3fSDimitry Andric
2135f757f3fSDimitry Andric int FI = MFI.CreateFixedObject(MemSize, Offset, /*Immutable=*/true);
2145f757f3fSDimitry Andric MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
2155f757f3fSDimitry Andric return MIRBuilder.buildFrameIndex(LLT::pointer(0, Subtarget.getXLen()), FI)
2165f757f3fSDimitry Andric .getReg(0);
21706c3fb27SDimitry Andric }
21806c3fb27SDimitry Andric
assignValueToAddress__anon7474aaf10111::RISCVIncomingValueHandler21906c3fb27SDimitry Andric void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
2205f757f3fSDimitry Andric const MachinePointerInfo &MPO,
2215f757f3fSDimitry Andric const CCValAssign &VA) override {
2225f757f3fSDimitry Andric MachineFunction &MF = MIRBuilder.getMF();
2235f757f3fSDimitry Andric auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy,
2245f757f3fSDimitry Andric inferAlignFromPtrInfo(MF, MPO));
2255f757f3fSDimitry Andric MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
22606c3fb27SDimitry Andric }
22706c3fb27SDimitry Andric
assignValueToReg__anon7474aaf10111::RISCVIncomingValueHandler22806c3fb27SDimitry Andric void assignValueToReg(Register ValVReg, Register PhysReg,
2295f757f3fSDimitry Andric const CCValAssign &VA) override {
2305f757f3fSDimitry Andric markPhysRegUsed(PhysReg);
2315f757f3fSDimitry Andric IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);
2325f757f3fSDimitry Andric }
2335f757f3fSDimitry Andric
assignCustomValue__anon7474aaf10111::RISCVIncomingValueHandler2345f757f3fSDimitry Andric unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
2355f757f3fSDimitry Andric ArrayRef<CCValAssign> VAs,
2365f757f3fSDimitry Andric std::function<void()> *Thunk) override {
2375f757f3fSDimitry Andric assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
2385f757f3fSDimitry Andric const CCValAssign &VALo = VAs[0];
2395f757f3fSDimitry Andric const CCValAssign &VAHi = VAs[1];
2405f757f3fSDimitry Andric
2415f757f3fSDimitry Andric assert(VAHi.needsCustom() && "Value doesn't need custom handling");
2425f757f3fSDimitry Andric assert(VALo.getValNo() == VAHi.getValNo() &&
2435f757f3fSDimitry Andric "Values belong to different arguments");
2445f757f3fSDimitry Andric
2455f757f3fSDimitry Andric assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
2465f757f3fSDimitry Andric VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
2475f757f3fSDimitry Andric "unexpected custom value");
2485f757f3fSDimitry Andric
2495f757f3fSDimitry Andric Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
2505f757f3fSDimitry Andric MRI.createGenericVirtualRegister(LLT::scalar(32))};
2515f757f3fSDimitry Andric
2525f757f3fSDimitry Andric if (VAHi.isMemLoc()) {
2535f757f3fSDimitry Andric LLT MemTy(VAHi.getLocVT());
2545f757f3fSDimitry Andric
2555f757f3fSDimitry Andric MachinePointerInfo MPO;
2565f757f3fSDimitry Andric Register StackAddr = getStackAddress(
2575f757f3fSDimitry Andric MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
2585f757f3fSDimitry Andric
2595f757f3fSDimitry Andric assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
2605f757f3fSDimitry Andric const_cast<CCValAssign &>(VAHi));
2615f757f3fSDimitry Andric }
2625f757f3fSDimitry Andric
2635f757f3fSDimitry Andric assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
2645f757f3fSDimitry Andric if (VAHi.isRegLoc())
2655f757f3fSDimitry Andric assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
2665f757f3fSDimitry Andric
2675f757f3fSDimitry Andric MIRBuilder.buildMergeLikeInstr(Arg.Regs[0], NewRegs);
2685f757f3fSDimitry Andric
269*7a6dacacSDimitry Andric return 2;
2705f757f3fSDimitry Andric }
2715f757f3fSDimitry Andric
2725f757f3fSDimitry Andric /// How the physical register gets marked varies between formal
2735f757f3fSDimitry Andric /// parameters (it's a basic-block live-in), and a call instruction
2745f757f3fSDimitry Andric /// (it's an implicit-def of the BL).
2755f757f3fSDimitry Andric virtual void markPhysRegUsed(MCRegister PhysReg) = 0;
2765f757f3fSDimitry Andric
2775f757f3fSDimitry Andric private:
2785f757f3fSDimitry Andric const RISCVSubtarget &Subtarget;
2795f757f3fSDimitry Andric };
2805f757f3fSDimitry Andric
2815f757f3fSDimitry Andric struct RISCVFormalArgHandler : public RISCVIncomingValueHandler {
RISCVFormalArgHandler__anon7474aaf10111::RISCVFormalArgHandler2825f757f3fSDimitry Andric RISCVFormalArgHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
2835f757f3fSDimitry Andric : RISCVIncomingValueHandler(B, MRI) {}
2845f757f3fSDimitry Andric
markPhysRegUsed__anon7474aaf10111::RISCVFormalArgHandler2855f757f3fSDimitry Andric void markPhysRegUsed(MCRegister PhysReg) override {
2865f757f3fSDimitry Andric MIRBuilder.getMRI()->addLiveIn(PhysReg);
28706c3fb27SDimitry Andric MIRBuilder.getMBB().addLiveIn(PhysReg);
28806c3fb27SDimitry Andric }
28906c3fb27SDimitry Andric };
29006c3fb27SDimitry Andric
29106c3fb27SDimitry Andric struct RISCVCallReturnHandler : public RISCVIncomingValueHandler {
RISCVCallReturnHandler__anon7474aaf10111::RISCVCallReturnHandler29206c3fb27SDimitry Andric RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
29306c3fb27SDimitry Andric MachineInstrBuilder &MIB)
29406c3fb27SDimitry Andric : RISCVIncomingValueHandler(B, MRI), MIB(MIB) {}
29506c3fb27SDimitry Andric
markPhysRegUsed__anon7474aaf10111::RISCVCallReturnHandler2965f757f3fSDimitry Andric void markPhysRegUsed(MCRegister PhysReg) override {
29706c3fb27SDimitry Andric MIB.addDef(PhysReg, RegState::Implicit);
29806c3fb27SDimitry Andric }
2995f757f3fSDimitry Andric
3005f757f3fSDimitry Andric MachineInstrBuilder MIB;
30106c3fb27SDimitry Andric };
30206c3fb27SDimitry Andric
30306c3fb27SDimitry Andric } // namespace
30406c3fb27SDimitry Andric
RISCVCallLowering(const RISCVTargetLowering & TLI)305bdd1243dSDimitry Andric RISCVCallLowering::RISCVCallLowering(const RISCVTargetLowering &TLI)
306bdd1243dSDimitry Andric : CallLowering(&TLI) {}
307bdd1243dSDimitry Andric
3085f757f3fSDimitry Andric /// Return true if scalable vector with ScalarTy is legal for lowering.
isLegalElementTypeForRVV(Type * EltTy,const RISCVSubtarget & Subtarget)3095f757f3fSDimitry Andric static bool isLegalElementTypeForRVV(Type *EltTy,
3105f757f3fSDimitry Andric const RISCVSubtarget &Subtarget) {
3115f757f3fSDimitry Andric if (EltTy->isPointerTy())
3125f757f3fSDimitry Andric return Subtarget.is64Bit() ? Subtarget.hasVInstructionsI64() : true;
3135f757f3fSDimitry Andric if (EltTy->isIntegerTy(1) || EltTy->isIntegerTy(8) ||
3145f757f3fSDimitry Andric EltTy->isIntegerTy(16) || EltTy->isIntegerTy(32))
3155f757f3fSDimitry Andric return true;
3165f757f3fSDimitry Andric if (EltTy->isIntegerTy(64))
3175f757f3fSDimitry Andric return Subtarget.hasVInstructionsI64();
3185f757f3fSDimitry Andric if (EltTy->isHalfTy())
3195f757f3fSDimitry Andric return Subtarget.hasVInstructionsF16();
3205f757f3fSDimitry Andric if (EltTy->isBFloatTy())
3215f757f3fSDimitry Andric return Subtarget.hasVInstructionsBF16();
3225f757f3fSDimitry Andric if (EltTy->isFloatTy())
3235f757f3fSDimitry Andric return Subtarget.hasVInstructionsF32();
3245f757f3fSDimitry Andric if (EltTy->isDoubleTy())
3255f757f3fSDimitry Andric return Subtarget.hasVInstructionsF64();
3265f757f3fSDimitry Andric return false;
3275f757f3fSDimitry Andric }
3285f757f3fSDimitry Andric
3295f757f3fSDimitry Andric // TODO: Support all argument types.
3305f757f3fSDimitry Andric // TODO: Remove IsLowerArgs argument by adding support for vectors in lowerCall.
isSupportedArgumentType(Type * T,const RISCVSubtarget & Subtarget,bool IsLowerArgs=false)3315f757f3fSDimitry Andric static bool isSupportedArgumentType(Type *T, const RISCVSubtarget &Subtarget,
3325f757f3fSDimitry Andric bool IsLowerArgs = false) {
3335f757f3fSDimitry Andric // TODO: Integers larger than 2*XLen are passed indirectly which is not
3345f757f3fSDimitry Andric // supported yet.
3355f757f3fSDimitry Andric if (T->isIntegerTy())
3365f757f3fSDimitry Andric return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2;
3375f757f3fSDimitry Andric if (T->isFloatTy() || T->isDoubleTy())
3385f757f3fSDimitry Andric return true;
3395f757f3fSDimitry Andric if (T->isPointerTy())
3405f757f3fSDimitry Andric return true;
3415f757f3fSDimitry Andric // TODO: Support fixed vector types.
3425f757f3fSDimitry Andric if (IsLowerArgs && T->isVectorTy() && Subtarget.hasVInstructions() &&
3435f757f3fSDimitry Andric T->isScalableTy() &&
3445f757f3fSDimitry Andric isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
3455f757f3fSDimitry Andric return true;
3465f757f3fSDimitry Andric return false;
3475f757f3fSDimitry Andric }
3485f757f3fSDimitry Andric
3495f757f3fSDimitry Andric // TODO: Only integer, pointer and aggregate types are supported now.
3505f757f3fSDimitry Andric // TODO: Remove IsLowerRetVal argument by adding support for vectors in
3515f757f3fSDimitry Andric // lowerCall.
isSupportedReturnType(Type * T,const RISCVSubtarget & Subtarget,bool IsLowerRetVal=false)3525f757f3fSDimitry Andric static bool isSupportedReturnType(Type *T, const RISCVSubtarget &Subtarget,
3535f757f3fSDimitry Andric bool IsLowerRetVal = false) {
3545f757f3fSDimitry Andric // TODO: Integers larger than 2*XLen are passed indirectly which is not
3555f757f3fSDimitry Andric // supported yet.
3565f757f3fSDimitry Andric if (T->isIntegerTy())
3575f757f3fSDimitry Andric return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2;
3585f757f3fSDimitry Andric if (T->isFloatTy() || T->isDoubleTy())
3595f757f3fSDimitry Andric return true;
3605f757f3fSDimitry Andric if (T->isPointerTy())
3615f757f3fSDimitry Andric return true;
3625f757f3fSDimitry Andric
3635f757f3fSDimitry Andric if (T->isArrayTy())
3645f757f3fSDimitry Andric return isSupportedReturnType(T->getArrayElementType(), Subtarget);
3655f757f3fSDimitry Andric
3665f757f3fSDimitry Andric if (T->isStructTy()) {
3675f757f3fSDimitry Andric auto StructT = cast<StructType>(T);
3685f757f3fSDimitry Andric for (unsigned i = 0, e = StructT->getNumElements(); i != e; ++i)
3695f757f3fSDimitry Andric if (!isSupportedReturnType(StructT->getElementType(i), Subtarget))
3705f757f3fSDimitry Andric return false;
3715f757f3fSDimitry Andric return true;
3725f757f3fSDimitry Andric }
3735f757f3fSDimitry Andric
3745f757f3fSDimitry Andric if (IsLowerRetVal && T->isVectorTy() && Subtarget.hasVInstructions() &&
3755f757f3fSDimitry Andric T->isScalableTy() &&
3765f757f3fSDimitry Andric isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
3775f757f3fSDimitry Andric return true;
3785f757f3fSDimitry Andric
3795f757f3fSDimitry Andric return false;
3805f757f3fSDimitry Andric }
3815f757f3fSDimitry Andric
lowerReturnVal(MachineIRBuilder & MIRBuilder,const Value * Val,ArrayRef<Register> VRegs,MachineInstrBuilder & Ret) const38206c3fb27SDimitry Andric bool RISCVCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
38306c3fb27SDimitry Andric const Value *Val,
38406c3fb27SDimitry Andric ArrayRef<Register> VRegs,
38506c3fb27SDimitry Andric MachineInstrBuilder &Ret) const {
38606c3fb27SDimitry Andric if (!Val)
38706c3fb27SDimitry Andric return true;
38806c3fb27SDimitry Andric
3895f757f3fSDimitry Andric const RISCVSubtarget &Subtarget =
3905f757f3fSDimitry Andric MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
3915f757f3fSDimitry Andric if (!isSupportedReturnType(Val->getType(), Subtarget, /*IsLowerRetVal=*/true))
39206c3fb27SDimitry Andric return false;
39306c3fb27SDimitry Andric
39406c3fb27SDimitry Andric MachineFunction &MF = MIRBuilder.getMF();
39506c3fb27SDimitry Andric const DataLayout &DL = MF.getDataLayout();
39606c3fb27SDimitry Andric const Function &F = MF.getFunction();
39706c3fb27SDimitry Andric CallingConv::ID CC = F.getCallingConv();
39806c3fb27SDimitry Andric
39906c3fb27SDimitry Andric ArgInfo OrigRetInfo(VRegs, Val->getType(), 0);
40006c3fb27SDimitry Andric setArgFlags(OrigRetInfo, AttributeList::ReturnIndex, DL, F);
40106c3fb27SDimitry Andric
40206c3fb27SDimitry Andric SmallVector<ArgInfo, 4> SplitRetInfos;
40306c3fb27SDimitry Andric splitToValueTypes(OrigRetInfo, SplitRetInfos, DL, CC);
40406c3fb27SDimitry Andric
40506c3fb27SDimitry Andric RISCVOutgoingValueAssigner Assigner(
40606c3fb27SDimitry Andric CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
40706c3fb27SDimitry Andric /*IsRet=*/true);
40806c3fb27SDimitry Andric RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret);
40906c3fb27SDimitry Andric return determineAndHandleAssignments(Handler, Assigner, SplitRetInfos,
41006c3fb27SDimitry Andric MIRBuilder, CC, F.isVarArg());
41106c3fb27SDimitry Andric }
41206c3fb27SDimitry Andric
lowerReturn(MachineIRBuilder & MIRBuilder,const Value * Val,ArrayRef<Register> VRegs,FunctionLoweringInfo & FLI) const413bdd1243dSDimitry Andric bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
414bdd1243dSDimitry Andric const Value *Val, ArrayRef<Register> VRegs,
415bdd1243dSDimitry Andric FunctionLoweringInfo &FLI) const {
41606c3fb27SDimitry Andric assert(!Val == VRegs.empty() && "Return value without a vreg");
417bdd1243dSDimitry Andric MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET);
418bdd1243dSDimitry Andric
41906c3fb27SDimitry Andric if (!lowerReturnVal(MIRBuilder, Val, VRegs, Ret))
420bdd1243dSDimitry Andric return false;
42106c3fb27SDimitry Andric
422bdd1243dSDimitry Andric MIRBuilder.insertInstr(Ret);
423bdd1243dSDimitry Andric return true;
424bdd1243dSDimitry Andric }
425bdd1243dSDimitry Andric
4265f757f3fSDimitry Andric /// If there are varargs that were passed in a0-a7, the data in those registers
4275f757f3fSDimitry Andric /// must be copied to the varargs save area on the stack.
saveVarArgRegisters(MachineIRBuilder & MIRBuilder,CallLowering::IncomingValueHandler & Handler,IncomingValueAssigner & Assigner,CCState & CCInfo) const4285f757f3fSDimitry Andric void RISCVCallLowering::saveVarArgRegisters(
4295f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder, CallLowering::IncomingValueHandler &Handler,
4305f757f3fSDimitry Andric IncomingValueAssigner &Assigner, CCState &CCInfo) const {
4315f757f3fSDimitry Andric MachineFunction &MF = MIRBuilder.getMF();
4325f757f3fSDimitry Andric const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
4335f757f3fSDimitry Andric unsigned XLenInBytes = Subtarget.getXLen() / 8;
434*7a6dacacSDimitry Andric ArrayRef<MCPhysReg> ArgRegs = RISCV::getArgGPRs(Subtarget.getTargetABI());
4355f757f3fSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo();
4365f757f3fSDimitry Andric unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
4375f757f3fSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo();
4385f757f3fSDimitry Andric RISCVMachineFunctionInfo *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
4395f757f3fSDimitry Andric
4405f757f3fSDimitry Andric // Size of the vararg save area. For now, the varargs save area is either
4415f757f3fSDimitry Andric // zero or large enough to hold a0-a7.
4425f757f3fSDimitry Andric int VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx);
4435f757f3fSDimitry Andric int FI;
4445f757f3fSDimitry Andric
4455f757f3fSDimitry Andric // If all registers are allocated, then all varargs must be passed on the
4465f757f3fSDimitry Andric // stack and we don't need to save any argregs.
4475f757f3fSDimitry Andric if (VarArgsSaveSize == 0) {
4485f757f3fSDimitry Andric int VaArgOffset = Assigner.StackSize;
4495f757f3fSDimitry Andric FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
4505f757f3fSDimitry Andric } else {
4515f757f3fSDimitry Andric int VaArgOffset = -VarArgsSaveSize;
4525f757f3fSDimitry Andric FI = MFI.CreateFixedObject(VarArgsSaveSize, VaArgOffset, true);
4535f757f3fSDimitry Andric
4545f757f3fSDimitry Andric // If saving an odd number of registers then create an extra stack slot to
4555f757f3fSDimitry Andric // ensure that the frame pointer is 2*XLEN-aligned, which in turn ensures
4565f757f3fSDimitry Andric // offsets to even-numbered registered remain 2*XLEN-aligned.
4575f757f3fSDimitry Andric if (Idx % 2) {
4585f757f3fSDimitry Andric MFI.CreateFixedObject(XLenInBytes,
4595f757f3fSDimitry Andric VaArgOffset - static_cast<int>(XLenInBytes), true);
4605f757f3fSDimitry Andric VarArgsSaveSize += XLenInBytes;
4615f757f3fSDimitry Andric }
4625f757f3fSDimitry Andric
4635f757f3fSDimitry Andric const LLT p0 = LLT::pointer(MF.getDataLayout().getAllocaAddrSpace(),
4645f757f3fSDimitry Andric Subtarget.getXLen());
4655f757f3fSDimitry Andric const LLT sXLen = LLT::scalar(Subtarget.getXLen());
4665f757f3fSDimitry Andric
4675f757f3fSDimitry Andric auto FIN = MIRBuilder.buildFrameIndex(p0, FI);
4685f757f3fSDimitry Andric auto Offset = MIRBuilder.buildConstant(
4695f757f3fSDimitry Andric MRI.createGenericVirtualRegister(sXLen), XLenInBytes);
4705f757f3fSDimitry Andric
4715f757f3fSDimitry Andric // Copy the integer registers that may have been used for passing varargs
4725f757f3fSDimitry Andric // to the vararg save area.
4735f757f3fSDimitry Andric const MVT XLenVT = Subtarget.getXLenVT();
4745f757f3fSDimitry Andric for (unsigned I = Idx; I < ArgRegs.size(); ++I) {
4755f757f3fSDimitry Andric const Register VReg = MRI.createGenericVirtualRegister(sXLen);
4765f757f3fSDimitry Andric Handler.assignValueToReg(
4775f757f3fSDimitry Andric VReg, ArgRegs[I],
4785f757f3fSDimitry Andric CCValAssign::getReg(I + MF.getFunction().getNumOperands(), XLenVT,
4795f757f3fSDimitry Andric ArgRegs[I], XLenVT, CCValAssign::Full));
4805f757f3fSDimitry Andric auto MPO =
4815f757f3fSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI, (I - Idx) * XLenInBytes);
4825f757f3fSDimitry Andric MIRBuilder.buildStore(VReg, FIN, MPO, inferAlignFromPtrInfo(MF, MPO));
4835f757f3fSDimitry Andric FIN = MIRBuilder.buildPtrAdd(MRI.createGenericVirtualRegister(p0),
4845f757f3fSDimitry Andric FIN.getReg(0), Offset);
4855f757f3fSDimitry Andric }
4865f757f3fSDimitry Andric }
4875f757f3fSDimitry Andric
4885f757f3fSDimitry Andric // Record the frame index of the first variable argument which is a value
4895f757f3fSDimitry Andric // necessary to G_VASTART.
4905f757f3fSDimitry Andric RVFI->setVarArgsFrameIndex(FI);
4915f757f3fSDimitry Andric RVFI->setVarArgsSaveSize(VarArgsSaveSize);
4925f757f3fSDimitry Andric }
4935f757f3fSDimitry Andric
lowerFormalArguments(MachineIRBuilder & MIRBuilder,const Function & F,ArrayRef<ArrayRef<Register>> VRegs,FunctionLoweringInfo & FLI) const494bdd1243dSDimitry Andric bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
495bdd1243dSDimitry Andric const Function &F,
496bdd1243dSDimitry Andric ArrayRef<ArrayRef<Register>> VRegs,
497bdd1243dSDimitry Andric FunctionLoweringInfo &FLI) const {
4985f757f3fSDimitry Andric // Early exit if there are no arguments. varargs are not part of F.args() but
4995f757f3fSDimitry Andric // must be lowered.
5005f757f3fSDimitry Andric if (F.arg_empty() && !F.isVarArg())
501bdd1243dSDimitry Andric return true;
502bdd1243dSDimitry Andric
5035f757f3fSDimitry Andric const RISCVSubtarget &Subtarget =
5045f757f3fSDimitry Andric MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
50506c3fb27SDimitry Andric for (auto &Arg : F.args()) {
5065f757f3fSDimitry Andric if (!isSupportedArgumentType(Arg.getType(), Subtarget,
5075f757f3fSDimitry Andric /*IsLowerArgs=*/true))
50806c3fb27SDimitry Andric return false;
50906c3fb27SDimitry Andric }
51006c3fb27SDimitry Andric
51106c3fb27SDimitry Andric MachineFunction &MF = MIRBuilder.getMF();
51206c3fb27SDimitry Andric const DataLayout &DL = MF.getDataLayout();
51306c3fb27SDimitry Andric CallingConv::ID CC = F.getCallingConv();
51406c3fb27SDimitry Andric
51506c3fb27SDimitry Andric SmallVector<ArgInfo, 32> SplitArgInfos;
51606c3fb27SDimitry Andric unsigned Index = 0;
51706c3fb27SDimitry Andric for (auto &Arg : F.args()) {
51806c3fb27SDimitry Andric // Construct the ArgInfo object from destination register and argument type.
51906c3fb27SDimitry Andric ArgInfo AInfo(VRegs[Index], Arg.getType(), Index);
52006c3fb27SDimitry Andric setArgFlags(AInfo, Index + AttributeList::FirstArgIndex, DL, F);
52106c3fb27SDimitry Andric
52206c3fb27SDimitry Andric // Handle any required merging from split value types from physical
52306c3fb27SDimitry Andric // registers into the desired VReg. ArgInfo objects are constructed
52406c3fb27SDimitry Andric // correspondingly and appended to SplitArgInfos.
52506c3fb27SDimitry Andric splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
52606c3fb27SDimitry Andric
52706c3fb27SDimitry Andric ++Index;
52806c3fb27SDimitry Andric }
52906c3fb27SDimitry Andric
53006c3fb27SDimitry Andric RISCVIncomingValueAssigner Assigner(
53106c3fb27SDimitry Andric CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
53206c3fb27SDimitry Andric /*IsRet=*/false);
5335f757f3fSDimitry Andric RISCVFormalArgHandler Handler(MIRBuilder, MF.getRegInfo());
53406c3fb27SDimitry Andric
5355f757f3fSDimitry Andric SmallVector<CCValAssign, 16> ArgLocs;
5365f757f3fSDimitry Andric CCState CCInfo(CC, F.isVarArg(), MIRBuilder.getMF(), ArgLocs, F.getContext());
5375f757f3fSDimitry Andric if (!determineAssignments(Assigner, SplitArgInfos, CCInfo) ||
5385f757f3fSDimitry Andric !handleAssignments(Handler, SplitArgInfos, CCInfo, ArgLocs, MIRBuilder))
5395f757f3fSDimitry Andric return false;
5405f757f3fSDimitry Andric
5415f757f3fSDimitry Andric if (F.isVarArg())
5425f757f3fSDimitry Andric saveVarArgRegisters(MIRBuilder, Handler, Assigner, CCInfo);
5435f757f3fSDimitry Andric
5445f757f3fSDimitry Andric return true;
545bdd1243dSDimitry Andric }
546bdd1243dSDimitry Andric
lowerCall(MachineIRBuilder & MIRBuilder,CallLoweringInfo & Info) const547bdd1243dSDimitry Andric bool RISCVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
548bdd1243dSDimitry Andric CallLoweringInfo &Info) const {
54906c3fb27SDimitry Andric MachineFunction &MF = MIRBuilder.getMF();
55006c3fb27SDimitry Andric const DataLayout &DL = MF.getDataLayout();
55106c3fb27SDimitry Andric const Function &F = MF.getFunction();
55206c3fb27SDimitry Andric CallingConv::ID CC = F.getCallingConv();
55306c3fb27SDimitry Andric
5545f757f3fSDimitry Andric const RISCVSubtarget &Subtarget =
5555f757f3fSDimitry Andric MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
55606c3fb27SDimitry Andric for (auto &AInfo : Info.OrigArgs) {
5575f757f3fSDimitry Andric if (!isSupportedArgumentType(AInfo.Ty, Subtarget))
55806c3fb27SDimitry Andric return false;
55906c3fb27SDimitry Andric }
56006c3fb27SDimitry Andric
5615f757f3fSDimitry Andric if (!Info.OrigRet.Ty->isVoidTy() &&
5625f757f3fSDimitry Andric !isSupportedReturnType(Info.OrigRet.Ty, Subtarget))
5635f757f3fSDimitry Andric return false;
5645f757f3fSDimitry Andric
5655f757f3fSDimitry Andric MachineInstrBuilder CallSeqStart =
5665f757f3fSDimitry Andric MIRBuilder.buildInstr(RISCV::ADJCALLSTACKDOWN);
5675f757f3fSDimitry Andric
56806c3fb27SDimitry Andric SmallVector<ArgInfo, 32> SplitArgInfos;
56906c3fb27SDimitry Andric SmallVector<ISD::OutputArg, 8> Outs;
57006c3fb27SDimitry Andric for (auto &AInfo : Info.OrigArgs) {
57106c3fb27SDimitry Andric // Handle any required unmerging of split value types from a given VReg into
57206c3fb27SDimitry Andric // physical registers. ArgInfo objects are constructed correspondingly and
57306c3fb27SDimitry Andric // appended to SplitArgInfos.
57406c3fb27SDimitry Andric splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
57506c3fb27SDimitry Andric }
57606c3fb27SDimitry Andric
57706c3fb27SDimitry Andric // TODO: Support tail calls.
57806c3fb27SDimitry Andric Info.IsTailCall = false;
57906c3fb27SDimitry Andric
5805f757f3fSDimitry Andric // Select the recommended relocation type R_RISCV_CALL_PLT.
58106c3fb27SDimitry Andric if (!Info.Callee.isReg())
5821db9f3b2SDimitry Andric Info.Callee.setTargetFlags(RISCVII::MO_CALL);
58306c3fb27SDimitry Andric
58406c3fb27SDimitry Andric MachineInstrBuilder Call =
58506c3fb27SDimitry Andric MIRBuilder
58606c3fb27SDimitry Andric .buildInstrNoInsert(Info.Callee.isReg() ? RISCV::PseudoCALLIndirect
58706c3fb27SDimitry Andric : RISCV::PseudoCALL)
58806c3fb27SDimitry Andric .add(Info.Callee);
5895f757f3fSDimitry Andric const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
5905f757f3fSDimitry Andric Call.addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));
59106c3fb27SDimitry Andric
59206c3fb27SDimitry Andric RISCVOutgoingValueAssigner ArgAssigner(
59306c3fb27SDimitry Andric CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
59406c3fb27SDimitry Andric /*IsRet=*/false);
59506c3fb27SDimitry Andric RISCVOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), Call);
59606c3fb27SDimitry Andric if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgInfos,
59706c3fb27SDimitry Andric MIRBuilder, CC, Info.IsVarArg))
59806c3fb27SDimitry Andric return false;
59906c3fb27SDimitry Andric
60006c3fb27SDimitry Andric MIRBuilder.insertInstr(Call);
60106c3fb27SDimitry Andric
6025f757f3fSDimitry Andric CallSeqStart.addImm(ArgAssigner.StackSize).addImm(0);
6035f757f3fSDimitry Andric MIRBuilder.buildInstr(RISCV::ADJCALLSTACKUP)
6045f757f3fSDimitry Andric .addImm(ArgAssigner.StackSize)
6055f757f3fSDimitry Andric .addImm(0);
6065f757f3fSDimitry Andric
6075f757f3fSDimitry Andric // If Callee is a reg, since it is used by a target specific
6085f757f3fSDimitry Andric // instruction, it must have a register class matching the
6095f757f3fSDimitry Andric // constraint of that instruction.
6105f757f3fSDimitry Andric if (Call->getOperand(0).isReg())
6115f757f3fSDimitry Andric constrainOperandRegClass(MF, *TRI, MF.getRegInfo(),
6125f757f3fSDimitry Andric *Subtarget.getInstrInfo(),
6135f757f3fSDimitry Andric *Subtarget.getRegBankInfo(), *Call,
6145f757f3fSDimitry Andric Call->getDesc(), Call->getOperand(0), 0);
6155f757f3fSDimitry Andric
61606c3fb27SDimitry Andric if (Info.OrigRet.Ty->isVoidTy())
61706c3fb27SDimitry Andric return true;
61806c3fb27SDimitry Andric
61906c3fb27SDimitry Andric SmallVector<ArgInfo, 4> SplitRetInfos;
62006c3fb27SDimitry Andric splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC);
62106c3fb27SDimitry Andric
62206c3fb27SDimitry Andric RISCVIncomingValueAssigner RetAssigner(
62306c3fb27SDimitry Andric CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
62406c3fb27SDimitry Andric /*IsRet=*/true);
62506c3fb27SDimitry Andric RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call);
62606c3fb27SDimitry Andric if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos,
62706c3fb27SDimitry Andric MIRBuilder, CC, Info.IsVarArg))
62806c3fb27SDimitry Andric return false;
62906c3fb27SDimitry Andric
63006c3fb27SDimitry Andric return true;
631bdd1243dSDimitry Andric }
632