xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
37*0fca6ea1SDimitry Andric   RVVArgDispatcher &RVVDispatcher;
38*0fca6ea1SDimitry Andric 
3906c3fb27SDimitry Andric public:
RISCVOutgoingValueAssigner__anonde0932290111::RISCVOutgoingValueAssigner4006c3fb27SDimitry Andric   RISCVOutgoingValueAssigner(
41*0fca6ea1SDimitry Andric       RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet,
42*0fca6ea1SDimitry Andric       RVVArgDispatcher &RVVDispatcher)
4306c3fb27SDimitry Andric       : CallLowering::OutgoingValueAssigner(nullptr),
44*0fca6ea1SDimitry Andric         RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet),
45*0fca6ea1SDimitry Andric         RVVDispatcher(RVVDispatcher) {}
4606c3fb27SDimitry Andric 
assignArg__anonde0932290111::RISCVOutgoingValueAssigner4706c3fb27SDimitry Andric   bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
4806c3fb27SDimitry Andric                  CCValAssign::LocInfo LocInfo,
4906c3fb27SDimitry Andric                  const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
5006c3fb27SDimitry Andric                  CCState &State) override {
5106c3fb27SDimitry Andric     MachineFunction &MF = State.getMachineFunction();
5206c3fb27SDimitry Andric     const DataLayout &DL = MF.getDataLayout();
5306c3fb27SDimitry Andric     const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
5406c3fb27SDimitry Andric 
555f757f3fSDimitry Andric     if (RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT,
565f757f3fSDimitry Andric                       LocInfo, Flags, State, Info.IsFixed, IsRet, Info.Ty,
57*0fca6ea1SDimitry Andric                       *Subtarget.getTargetLowering(), RVVDispatcher))
585f757f3fSDimitry Andric       return true;
595f757f3fSDimitry Andric 
605f757f3fSDimitry Andric     StackSize = State.getStackSize();
615f757f3fSDimitry Andric     return false;
6206c3fb27SDimitry Andric   }
6306c3fb27SDimitry Andric };
6406c3fb27SDimitry Andric 
6506c3fb27SDimitry Andric struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
RISCVOutgoingValueHandler__anonde0932290111::RISCVOutgoingValueHandler6606c3fb27SDimitry Andric   RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
6706c3fb27SDimitry Andric                             MachineInstrBuilder MIB)
685f757f3fSDimitry Andric       : OutgoingValueHandler(B, MRI), MIB(MIB),
695f757f3fSDimitry Andric         Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
getStackAddress__anonde0932290111::RISCVOutgoingValueHandler7006c3fb27SDimitry Andric   Register getStackAddress(uint64_t MemSize, int64_t Offset,
7106c3fb27SDimitry Andric                            MachinePointerInfo &MPO,
7206c3fb27SDimitry Andric                            ISD::ArgFlagsTy Flags) override {
735f757f3fSDimitry Andric     MachineFunction &MF = MIRBuilder.getMF();
745f757f3fSDimitry Andric     LLT p0 = LLT::pointer(0, Subtarget.getXLen());
755f757f3fSDimitry Andric     LLT sXLen = LLT::scalar(Subtarget.getXLen());
765f757f3fSDimitry Andric 
775f757f3fSDimitry Andric     if (!SPReg)
785f757f3fSDimitry Andric       SPReg = MIRBuilder.buildCopy(p0, Register(RISCV::X2)).getReg(0);
795f757f3fSDimitry Andric 
805f757f3fSDimitry Andric     auto OffsetReg = MIRBuilder.buildConstant(sXLen, Offset);
815f757f3fSDimitry Andric 
825f757f3fSDimitry Andric     auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg);
835f757f3fSDimitry Andric 
845f757f3fSDimitry Andric     MPO = MachinePointerInfo::getStack(MF, Offset);
855f757f3fSDimitry Andric     return AddrReg.getReg(0);
8606c3fb27SDimitry Andric   }
8706c3fb27SDimitry Andric 
assignValueToAddress__anonde0932290111::RISCVOutgoingValueHandler8806c3fb27SDimitry Andric   void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
895f757f3fSDimitry Andric                             const MachinePointerInfo &MPO,
905f757f3fSDimitry Andric                             const CCValAssign &VA) override {
915f757f3fSDimitry Andric     MachineFunction &MF = MIRBuilder.getMF();
925f757f3fSDimitry Andric     uint64_t LocMemOffset = VA.getLocMemOffset();
935f757f3fSDimitry Andric 
945f757f3fSDimitry Andric     // TODO: Move StackAlignment to subtarget and share with FrameLowering.
955f757f3fSDimitry Andric     auto MMO =
965f757f3fSDimitry Andric         MF.getMachineMemOperand(MPO, MachineMemOperand::MOStore, MemTy,
975f757f3fSDimitry Andric                                 commonAlignment(Align(16), LocMemOffset));
985f757f3fSDimitry Andric 
995f757f3fSDimitry Andric     Register ExtReg = extendRegister(ValVReg, VA);
1005f757f3fSDimitry Andric     MIRBuilder.buildStore(ExtReg, Addr, *MMO);
10106c3fb27SDimitry Andric   }
10206c3fb27SDimitry Andric 
assignValueToReg__anonde0932290111::RISCVOutgoingValueHandler10306c3fb27SDimitry Andric   void assignValueToReg(Register ValVReg, Register PhysReg,
1045f757f3fSDimitry Andric                         const CCValAssign &VA) override {
105*0fca6ea1SDimitry Andric     // If we're passing a smaller fp value into a larger integer register,
106*0fca6ea1SDimitry Andric     // anyextend before copying.
107*0fca6ea1SDimitry Andric     if ((VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) ||
108*0fca6ea1SDimitry Andric         ((VA.getLocVT() == MVT::i32 || VA.getLocVT() == MVT::i64) &&
109*0fca6ea1SDimitry Andric          VA.getValVT() == MVT::f16)) {
110*0fca6ea1SDimitry Andric       LLT DstTy = LLT::scalar(VA.getLocVT().getSizeInBits());
111*0fca6ea1SDimitry Andric       ValVReg = MIRBuilder.buildAnyExt(DstTy, ValVReg).getReg(0);
112*0fca6ea1SDimitry Andric     }
1135f757f3fSDimitry Andric 
11406c3fb27SDimitry Andric     Register ExtReg = extendRegister(ValVReg, VA);
11506c3fb27SDimitry Andric     MIRBuilder.buildCopy(PhysReg, ExtReg);
11606c3fb27SDimitry Andric     MIB.addUse(PhysReg, RegState::Implicit);
11706c3fb27SDimitry Andric   }
1185f757f3fSDimitry Andric 
assignCustomValue__anonde0932290111::RISCVOutgoingValueHandler1195f757f3fSDimitry Andric   unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
1205f757f3fSDimitry Andric                              ArrayRef<CCValAssign> VAs,
1215f757f3fSDimitry Andric                              std::function<void()> *Thunk) override {
1225f757f3fSDimitry Andric     assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
1235f757f3fSDimitry Andric     const CCValAssign &VALo = VAs[0];
1245f757f3fSDimitry Andric     const CCValAssign &VAHi = VAs[1];
1255f757f3fSDimitry Andric 
1265f757f3fSDimitry Andric     assert(VAHi.needsCustom() && "Value doesn't need custom handling");
1275f757f3fSDimitry Andric     assert(VALo.getValNo() == VAHi.getValNo() &&
1285f757f3fSDimitry Andric            "Values belong to different arguments");
1295f757f3fSDimitry Andric 
1305f757f3fSDimitry Andric     assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
1315f757f3fSDimitry Andric            VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
1325f757f3fSDimitry Andric            "unexpected custom value");
1335f757f3fSDimitry Andric 
1345f757f3fSDimitry Andric     Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
1355f757f3fSDimitry Andric                           MRI.createGenericVirtualRegister(LLT::scalar(32))};
1365f757f3fSDimitry Andric     MIRBuilder.buildUnmerge(NewRegs, Arg.Regs[0]);
1375f757f3fSDimitry Andric 
1385f757f3fSDimitry Andric     if (VAHi.isMemLoc()) {
1395f757f3fSDimitry Andric       LLT MemTy(VAHi.getLocVT());
1405f757f3fSDimitry Andric 
1415f757f3fSDimitry Andric       MachinePointerInfo MPO;
1425f757f3fSDimitry Andric       Register StackAddr = getStackAddress(
1435f757f3fSDimitry Andric           MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
1445f757f3fSDimitry Andric 
1455f757f3fSDimitry Andric       assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
1465f757f3fSDimitry Andric                            const_cast<CCValAssign &>(VAHi));
1475f757f3fSDimitry Andric     }
1485f757f3fSDimitry Andric 
1495f757f3fSDimitry Andric     auto assignFunc = [=]() {
1505f757f3fSDimitry Andric       assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
1515f757f3fSDimitry Andric       if (VAHi.isRegLoc())
1525f757f3fSDimitry Andric         assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
1535f757f3fSDimitry Andric     };
1545f757f3fSDimitry Andric 
1555f757f3fSDimitry Andric     if (Thunk) {
1565f757f3fSDimitry Andric       *Thunk = assignFunc;
1577a6dacacSDimitry Andric       return 2;
1585f757f3fSDimitry Andric     }
1595f757f3fSDimitry Andric 
1605f757f3fSDimitry Andric     assignFunc();
1617a6dacacSDimitry Andric     return 2;
1625f757f3fSDimitry Andric   }
1635f757f3fSDimitry Andric 
1645f757f3fSDimitry Andric private:
1655f757f3fSDimitry Andric   MachineInstrBuilder MIB;
1665f757f3fSDimitry Andric 
1675f757f3fSDimitry Andric   // Cache the SP register vreg if we need it more than once in this call site.
1685f757f3fSDimitry Andric   Register SPReg;
1695f757f3fSDimitry Andric 
1705f757f3fSDimitry Andric   const RISCVSubtarget &Subtarget;
17106c3fb27SDimitry Andric };
17206c3fb27SDimitry Andric 
17306c3fb27SDimitry Andric struct RISCVIncomingValueAssigner : public CallLowering::IncomingValueAssigner {
17406c3fb27SDimitry Andric private:
17506c3fb27SDimitry Andric   // The function used internally to assign args - we ignore the AssignFn stored
17606c3fb27SDimitry Andric   // by IncomingValueAssigner since RISC-V implements its CC using a custom
17706c3fb27SDimitry Andric   // function with a different signature.
17806c3fb27SDimitry Andric   RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn;
17906c3fb27SDimitry Andric 
18006c3fb27SDimitry Andric   // Whether this is assigning args from a return.
18106c3fb27SDimitry Andric   bool IsRet;
18206c3fb27SDimitry Andric 
183*0fca6ea1SDimitry Andric   RVVArgDispatcher &RVVDispatcher;
184*0fca6ea1SDimitry Andric 
18506c3fb27SDimitry Andric public:
RISCVIncomingValueAssigner__anonde0932290111::RISCVIncomingValueAssigner18606c3fb27SDimitry Andric   RISCVIncomingValueAssigner(
187*0fca6ea1SDimitry Andric       RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet,
188*0fca6ea1SDimitry Andric       RVVArgDispatcher &RVVDispatcher)
18906c3fb27SDimitry Andric       : CallLowering::IncomingValueAssigner(nullptr),
190*0fca6ea1SDimitry Andric         RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet),
191*0fca6ea1SDimitry Andric         RVVDispatcher(RVVDispatcher) {}
19206c3fb27SDimitry Andric 
assignArg__anonde0932290111::RISCVIncomingValueAssigner19306c3fb27SDimitry Andric   bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
19406c3fb27SDimitry Andric                  CCValAssign::LocInfo LocInfo,
19506c3fb27SDimitry Andric                  const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
19606c3fb27SDimitry Andric                  CCState &State) override {
19706c3fb27SDimitry Andric     MachineFunction &MF = State.getMachineFunction();
19806c3fb27SDimitry Andric     const DataLayout &DL = MF.getDataLayout();
19906c3fb27SDimitry Andric     const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
20006c3fb27SDimitry Andric 
2015f757f3fSDimitry Andric     if (LocVT.isScalableVector())
2025f757f3fSDimitry Andric       MF.getInfo<RISCVMachineFunctionInfo>()->setIsVectorCall();
2035f757f3fSDimitry Andric 
2045f757f3fSDimitry Andric     if (RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT,
2055f757f3fSDimitry Andric                       LocInfo, Flags, State, /*IsFixed=*/true, IsRet, Info.Ty,
206*0fca6ea1SDimitry Andric                       *Subtarget.getTargetLowering(), RVVDispatcher))
2075f757f3fSDimitry Andric       return true;
2085f757f3fSDimitry Andric 
2095f757f3fSDimitry Andric     StackSize = State.getStackSize();
2105f757f3fSDimitry Andric     return false;
21106c3fb27SDimitry Andric   }
21206c3fb27SDimitry Andric };
21306c3fb27SDimitry Andric 
21406c3fb27SDimitry Andric struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
RISCVIncomingValueHandler__anonde0932290111::RISCVIncomingValueHandler21506c3fb27SDimitry Andric   RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
2165f757f3fSDimitry Andric       : IncomingValueHandler(B, MRI),
2175f757f3fSDimitry Andric         Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
21806c3fb27SDimitry Andric 
getStackAddress__anonde0932290111::RISCVIncomingValueHandler21906c3fb27SDimitry Andric   Register getStackAddress(uint64_t MemSize, int64_t Offset,
22006c3fb27SDimitry Andric                            MachinePointerInfo &MPO,
22106c3fb27SDimitry Andric                            ISD::ArgFlagsTy Flags) override {
2225f757f3fSDimitry Andric     MachineFrameInfo &MFI = MIRBuilder.getMF().getFrameInfo();
2235f757f3fSDimitry Andric 
2245f757f3fSDimitry Andric     int FI = MFI.CreateFixedObject(MemSize, Offset, /*Immutable=*/true);
2255f757f3fSDimitry Andric     MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
2265f757f3fSDimitry Andric     return MIRBuilder.buildFrameIndex(LLT::pointer(0, Subtarget.getXLen()), FI)
2275f757f3fSDimitry Andric         .getReg(0);
22806c3fb27SDimitry Andric   }
22906c3fb27SDimitry Andric 
assignValueToAddress__anonde0932290111::RISCVIncomingValueHandler23006c3fb27SDimitry Andric   void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
2315f757f3fSDimitry Andric                             const MachinePointerInfo &MPO,
2325f757f3fSDimitry Andric                             const CCValAssign &VA) override {
2335f757f3fSDimitry Andric     MachineFunction &MF = MIRBuilder.getMF();
2345f757f3fSDimitry Andric     auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy,
2355f757f3fSDimitry Andric                                        inferAlignFromPtrInfo(MF, MPO));
2365f757f3fSDimitry Andric     MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
23706c3fb27SDimitry Andric   }
23806c3fb27SDimitry Andric 
assignValueToReg__anonde0932290111::RISCVIncomingValueHandler23906c3fb27SDimitry Andric   void assignValueToReg(Register ValVReg, Register PhysReg,
2405f757f3fSDimitry Andric                         const CCValAssign &VA) override {
2415f757f3fSDimitry Andric     markPhysRegUsed(PhysReg);
2425f757f3fSDimitry Andric     IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);
2435f757f3fSDimitry Andric   }
2445f757f3fSDimitry Andric 
assignCustomValue__anonde0932290111::RISCVIncomingValueHandler2455f757f3fSDimitry Andric   unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
2465f757f3fSDimitry Andric                              ArrayRef<CCValAssign> VAs,
2475f757f3fSDimitry Andric                              std::function<void()> *Thunk) override {
2485f757f3fSDimitry Andric     assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
2495f757f3fSDimitry Andric     const CCValAssign &VALo = VAs[0];
2505f757f3fSDimitry Andric     const CCValAssign &VAHi = VAs[1];
2515f757f3fSDimitry Andric 
2525f757f3fSDimitry Andric     assert(VAHi.needsCustom() && "Value doesn't need custom handling");
2535f757f3fSDimitry Andric     assert(VALo.getValNo() == VAHi.getValNo() &&
2545f757f3fSDimitry Andric            "Values belong to different arguments");
2555f757f3fSDimitry Andric 
2565f757f3fSDimitry Andric     assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
2575f757f3fSDimitry Andric            VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
2585f757f3fSDimitry Andric            "unexpected custom value");
2595f757f3fSDimitry Andric 
2605f757f3fSDimitry Andric     Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
2615f757f3fSDimitry Andric                           MRI.createGenericVirtualRegister(LLT::scalar(32))};
2625f757f3fSDimitry Andric 
2635f757f3fSDimitry Andric     if (VAHi.isMemLoc()) {
2645f757f3fSDimitry Andric       LLT MemTy(VAHi.getLocVT());
2655f757f3fSDimitry Andric 
2665f757f3fSDimitry Andric       MachinePointerInfo MPO;
2675f757f3fSDimitry Andric       Register StackAddr = getStackAddress(
2685f757f3fSDimitry Andric           MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
2695f757f3fSDimitry Andric 
2705f757f3fSDimitry Andric       assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
2715f757f3fSDimitry Andric                            const_cast<CCValAssign &>(VAHi));
2725f757f3fSDimitry Andric     }
2735f757f3fSDimitry Andric 
2745f757f3fSDimitry Andric     assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
2755f757f3fSDimitry Andric     if (VAHi.isRegLoc())
2765f757f3fSDimitry Andric       assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
2775f757f3fSDimitry Andric 
2785f757f3fSDimitry Andric     MIRBuilder.buildMergeLikeInstr(Arg.Regs[0], NewRegs);
2795f757f3fSDimitry Andric 
2807a6dacacSDimitry Andric     return 2;
2815f757f3fSDimitry Andric   }
2825f757f3fSDimitry Andric 
2835f757f3fSDimitry Andric   /// How the physical register gets marked varies between formal
2845f757f3fSDimitry Andric   /// parameters (it's a basic-block live-in), and a call instruction
2855f757f3fSDimitry Andric   /// (it's an implicit-def of the BL).
2865f757f3fSDimitry Andric   virtual void markPhysRegUsed(MCRegister PhysReg) = 0;
2875f757f3fSDimitry Andric 
2885f757f3fSDimitry Andric private:
2895f757f3fSDimitry Andric   const RISCVSubtarget &Subtarget;
2905f757f3fSDimitry Andric };
2915f757f3fSDimitry Andric 
2925f757f3fSDimitry Andric struct RISCVFormalArgHandler : public RISCVIncomingValueHandler {
RISCVFormalArgHandler__anonde0932290111::RISCVFormalArgHandler2935f757f3fSDimitry Andric   RISCVFormalArgHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
2945f757f3fSDimitry Andric       : RISCVIncomingValueHandler(B, MRI) {}
2955f757f3fSDimitry Andric 
markPhysRegUsed__anonde0932290111::RISCVFormalArgHandler2965f757f3fSDimitry Andric   void markPhysRegUsed(MCRegister PhysReg) override {
2975f757f3fSDimitry Andric     MIRBuilder.getMRI()->addLiveIn(PhysReg);
29806c3fb27SDimitry Andric     MIRBuilder.getMBB().addLiveIn(PhysReg);
29906c3fb27SDimitry Andric   }
30006c3fb27SDimitry Andric };
30106c3fb27SDimitry Andric 
30206c3fb27SDimitry Andric struct RISCVCallReturnHandler : public RISCVIncomingValueHandler {
RISCVCallReturnHandler__anonde0932290111::RISCVCallReturnHandler30306c3fb27SDimitry Andric   RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
30406c3fb27SDimitry Andric                          MachineInstrBuilder &MIB)
30506c3fb27SDimitry Andric       : RISCVIncomingValueHandler(B, MRI), MIB(MIB) {}
30606c3fb27SDimitry Andric 
markPhysRegUsed__anonde0932290111::RISCVCallReturnHandler3075f757f3fSDimitry Andric   void markPhysRegUsed(MCRegister PhysReg) override {
30806c3fb27SDimitry Andric     MIB.addDef(PhysReg, RegState::Implicit);
30906c3fb27SDimitry Andric   }
3105f757f3fSDimitry Andric 
3115f757f3fSDimitry Andric   MachineInstrBuilder MIB;
31206c3fb27SDimitry Andric };
31306c3fb27SDimitry Andric 
31406c3fb27SDimitry Andric } // namespace
31506c3fb27SDimitry Andric 
RISCVCallLowering(const RISCVTargetLowering & TLI)316bdd1243dSDimitry Andric RISCVCallLowering::RISCVCallLowering(const RISCVTargetLowering &TLI)
317bdd1243dSDimitry Andric     : CallLowering(&TLI) {}
318bdd1243dSDimitry Andric 
3195f757f3fSDimitry Andric /// Return true if scalable vector with ScalarTy is legal for lowering.
isLegalElementTypeForRVV(Type * EltTy,const RISCVSubtarget & Subtarget)3205f757f3fSDimitry Andric static bool isLegalElementTypeForRVV(Type *EltTy,
3215f757f3fSDimitry Andric                                      const RISCVSubtarget &Subtarget) {
3225f757f3fSDimitry Andric   if (EltTy->isPointerTy())
3235f757f3fSDimitry Andric     return Subtarget.is64Bit() ? Subtarget.hasVInstructionsI64() : true;
3245f757f3fSDimitry Andric   if (EltTy->isIntegerTy(1) || EltTy->isIntegerTy(8) ||
3255f757f3fSDimitry Andric       EltTy->isIntegerTy(16) || EltTy->isIntegerTy(32))
3265f757f3fSDimitry Andric     return true;
3275f757f3fSDimitry Andric   if (EltTy->isIntegerTy(64))
3285f757f3fSDimitry Andric     return Subtarget.hasVInstructionsI64();
3295f757f3fSDimitry Andric   if (EltTy->isHalfTy())
3305f757f3fSDimitry Andric     return Subtarget.hasVInstructionsF16();
3315f757f3fSDimitry Andric   if (EltTy->isBFloatTy())
3325f757f3fSDimitry Andric     return Subtarget.hasVInstructionsBF16();
3335f757f3fSDimitry Andric   if (EltTy->isFloatTy())
3345f757f3fSDimitry Andric     return Subtarget.hasVInstructionsF32();
3355f757f3fSDimitry Andric   if (EltTy->isDoubleTy())
3365f757f3fSDimitry Andric     return Subtarget.hasVInstructionsF64();
3375f757f3fSDimitry Andric   return false;
3385f757f3fSDimitry Andric }
3395f757f3fSDimitry Andric 
3405f757f3fSDimitry Andric // TODO: Support all argument types.
3415f757f3fSDimitry Andric // TODO: Remove IsLowerArgs argument by adding support for vectors in lowerCall.
isSupportedArgumentType(Type * T,const RISCVSubtarget & Subtarget,bool IsLowerArgs=false)3425f757f3fSDimitry Andric static bool isSupportedArgumentType(Type *T, const RISCVSubtarget &Subtarget,
3435f757f3fSDimitry Andric                                     bool IsLowerArgs = false) {
3445f757f3fSDimitry Andric   if (T->isIntegerTy())
345*0fca6ea1SDimitry Andric     return true;
346*0fca6ea1SDimitry Andric   if (T->isHalfTy() || T->isFloatTy() || T->isDoubleTy())
3475f757f3fSDimitry Andric     return true;
3485f757f3fSDimitry Andric   if (T->isPointerTy())
3495f757f3fSDimitry Andric     return true;
3505f757f3fSDimitry Andric   // TODO: Support fixed vector types.
3515f757f3fSDimitry Andric   if (IsLowerArgs && T->isVectorTy() && Subtarget.hasVInstructions() &&
3525f757f3fSDimitry Andric       T->isScalableTy() &&
3535f757f3fSDimitry Andric       isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
3545f757f3fSDimitry Andric     return true;
3555f757f3fSDimitry Andric   return false;
3565f757f3fSDimitry Andric }
3575f757f3fSDimitry Andric 
3585f757f3fSDimitry Andric // TODO: Only integer, pointer and aggregate types are supported now.
3595f757f3fSDimitry Andric // TODO: Remove IsLowerRetVal argument by adding support for vectors in
3605f757f3fSDimitry Andric // lowerCall.
isSupportedReturnType(Type * T,const RISCVSubtarget & Subtarget,bool IsLowerRetVal=false)3615f757f3fSDimitry Andric static bool isSupportedReturnType(Type *T, const RISCVSubtarget &Subtarget,
3625f757f3fSDimitry Andric                                   bool IsLowerRetVal = false) {
3635f757f3fSDimitry Andric   // TODO: Integers larger than 2*XLen are passed indirectly which is not
3645f757f3fSDimitry Andric   // supported yet.
3655f757f3fSDimitry Andric   if (T->isIntegerTy())
3665f757f3fSDimitry Andric     return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2;
367*0fca6ea1SDimitry Andric   if (T->isHalfTy() || T->isFloatTy() || T->isDoubleTy())
3685f757f3fSDimitry Andric     return true;
3695f757f3fSDimitry Andric   if (T->isPointerTy())
3705f757f3fSDimitry Andric     return true;
3715f757f3fSDimitry Andric 
3725f757f3fSDimitry Andric   if (T->isArrayTy())
3735f757f3fSDimitry Andric     return isSupportedReturnType(T->getArrayElementType(), Subtarget);
3745f757f3fSDimitry Andric 
3755f757f3fSDimitry Andric   if (T->isStructTy()) {
3765f757f3fSDimitry Andric     auto StructT = cast<StructType>(T);
3775f757f3fSDimitry Andric     for (unsigned i = 0, e = StructT->getNumElements(); i != e; ++i)
3785f757f3fSDimitry Andric       if (!isSupportedReturnType(StructT->getElementType(i), Subtarget))
3795f757f3fSDimitry Andric         return false;
3805f757f3fSDimitry Andric     return true;
3815f757f3fSDimitry Andric   }
3825f757f3fSDimitry Andric 
3835f757f3fSDimitry Andric   if (IsLowerRetVal && T->isVectorTy() && Subtarget.hasVInstructions() &&
3845f757f3fSDimitry Andric       T->isScalableTy() &&
3855f757f3fSDimitry Andric       isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
3865f757f3fSDimitry Andric     return true;
3875f757f3fSDimitry Andric 
3885f757f3fSDimitry Andric   return false;
3895f757f3fSDimitry Andric }
3905f757f3fSDimitry Andric 
lowerReturnVal(MachineIRBuilder & MIRBuilder,const Value * Val,ArrayRef<Register> VRegs,MachineInstrBuilder & Ret) const39106c3fb27SDimitry Andric bool RISCVCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
39206c3fb27SDimitry Andric                                        const Value *Val,
39306c3fb27SDimitry Andric                                        ArrayRef<Register> VRegs,
39406c3fb27SDimitry Andric                                        MachineInstrBuilder &Ret) const {
39506c3fb27SDimitry Andric   if (!Val)
39606c3fb27SDimitry Andric     return true;
39706c3fb27SDimitry Andric 
3985f757f3fSDimitry Andric   const RISCVSubtarget &Subtarget =
3995f757f3fSDimitry Andric       MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
4005f757f3fSDimitry Andric   if (!isSupportedReturnType(Val->getType(), Subtarget, /*IsLowerRetVal=*/true))
40106c3fb27SDimitry Andric     return false;
40206c3fb27SDimitry Andric 
40306c3fb27SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
40406c3fb27SDimitry Andric   const DataLayout &DL = MF.getDataLayout();
40506c3fb27SDimitry Andric   const Function &F = MF.getFunction();
40606c3fb27SDimitry Andric   CallingConv::ID CC = F.getCallingConv();
40706c3fb27SDimitry Andric 
40806c3fb27SDimitry Andric   ArgInfo OrigRetInfo(VRegs, Val->getType(), 0);
40906c3fb27SDimitry Andric   setArgFlags(OrigRetInfo, AttributeList::ReturnIndex, DL, F);
41006c3fb27SDimitry Andric 
41106c3fb27SDimitry Andric   SmallVector<ArgInfo, 4> SplitRetInfos;
41206c3fb27SDimitry Andric   splitToValueTypes(OrigRetInfo, SplitRetInfos, DL, CC);
41306c3fb27SDimitry Andric 
414*0fca6ea1SDimitry Andric   RVVArgDispatcher Dispatcher{&MF, getTLI<RISCVTargetLowering>(),
415*0fca6ea1SDimitry Andric                               ArrayRef(F.getReturnType())};
41606c3fb27SDimitry Andric   RISCVOutgoingValueAssigner Assigner(
41706c3fb27SDimitry Andric       CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
418*0fca6ea1SDimitry Andric       /*IsRet=*/true, Dispatcher);
41906c3fb27SDimitry Andric   RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret);
42006c3fb27SDimitry Andric   return determineAndHandleAssignments(Handler, Assigner, SplitRetInfos,
42106c3fb27SDimitry Andric                                        MIRBuilder, CC, F.isVarArg());
42206c3fb27SDimitry Andric }
42306c3fb27SDimitry Andric 
lowerReturn(MachineIRBuilder & MIRBuilder,const Value * Val,ArrayRef<Register> VRegs,FunctionLoweringInfo & FLI) const424bdd1243dSDimitry Andric bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
425bdd1243dSDimitry Andric                                     const Value *Val, ArrayRef<Register> VRegs,
426bdd1243dSDimitry Andric                                     FunctionLoweringInfo &FLI) const {
42706c3fb27SDimitry Andric   assert(!Val == VRegs.empty() && "Return value without a vreg");
428bdd1243dSDimitry Andric   MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET);
429bdd1243dSDimitry Andric 
43006c3fb27SDimitry Andric   if (!lowerReturnVal(MIRBuilder, Val, VRegs, Ret))
431bdd1243dSDimitry Andric     return false;
43206c3fb27SDimitry Andric 
433bdd1243dSDimitry Andric   MIRBuilder.insertInstr(Ret);
434bdd1243dSDimitry Andric   return true;
435bdd1243dSDimitry Andric }
436bdd1243dSDimitry Andric 
4375f757f3fSDimitry Andric /// If there are varargs that were passed in a0-a7, the data in those registers
4385f757f3fSDimitry Andric /// must be copied to the varargs save area on the stack.
saveVarArgRegisters(MachineIRBuilder & MIRBuilder,CallLowering::IncomingValueHandler & Handler,IncomingValueAssigner & Assigner,CCState & CCInfo) const4395f757f3fSDimitry Andric void RISCVCallLowering::saveVarArgRegisters(
4405f757f3fSDimitry Andric     MachineIRBuilder &MIRBuilder, CallLowering::IncomingValueHandler &Handler,
4415f757f3fSDimitry Andric     IncomingValueAssigner &Assigner, CCState &CCInfo) const {
4425f757f3fSDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
4435f757f3fSDimitry Andric   const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
4445f757f3fSDimitry Andric   unsigned XLenInBytes = Subtarget.getXLen() / 8;
4457a6dacacSDimitry Andric   ArrayRef<MCPhysReg> ArgRegs = RISCV::getArgGPRs(Subtarget.getTargetABI());
4465f757f3fSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
4475f757f3fSDimitry Andric   unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
4485f757f3fSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
4495f757f3fSDimitry Andric   RISCVMachineFunctionInfo *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
4505f757f3fSDimitry Andric 
4515f757f3fSDimitry Andric   // Size of the vararg save area. For now, the varargs save area is either
4525f757f3fSDimitry Andric   // zero or large enough to hold a0-a7.
4535f757f3fSDimitry Andric   int VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx);
4545f757f3fSDimitry Andric   int FI;
4555f757f3fSDimitry Andric 
4565f757f3fSDimitry Andric   // If all registers are allocated, then all varargs must be passed on the
4575f757f3fSDimitry Andric   // stack and we don't need to save any argregs.
4585f757f3fSDimitry Andric   if (VarArgsSaveSize == 0) {
4595f757f3fSDimitry Andric     int VaArgOffset = Assigner.StackSize;
4605f757f3fSDimitry Andric     FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
4615f757f3fSDimitry Andric   } else {
4625f757f3fSDimitry Andric     int VaArgOffset = -VarArgsSaveSize;
4635f757f3fSDimitry Andric     FI = MFI.CreateFixedObject(VarArgsSaveSize, VaArgOffset, true);
4645f757f3fSDimitry Andric 
4655f757f3fSDimitry Andric     // If saving an odd number of registers then create an extra stack slot to
4665f757f3fSDimitry Andric     // ensure that the frame pointer is 2*XLEN-aligned, which in turn ensures
4675f757f3fSDimitry Andric     // offsets to even-numbered registered remain 2*XLEN-aligned.
4685f757f3fSDimitry Andric     if (Idx % 2) {
4695f757f3fSDimitry Andric       MFI.CreateFixedObject(XLenInBytes,
4705f757f3fSDimitry Andric                             VaArgOffset - static_cast<int>(XLenInBytes), true);
4715f757f3fSDimitry Andric       VarArgsSaveSize += XLenInBytes;
4725f757f3fSDimitry Andric     }
4735f757f3fSDimitry Andric 
4745f757f3fSDimitry Andric     const LLT p0 = LLT::pointer(MF.getDataLayout().getAllocaAddrSpace(),
4755f757f3fSDimitry Andric                                 Subtarget.getXLen());
4765f757f3fSDimitry Andric     const LLT sXLen = LLT::scalar(Subtarget.getXLen());
4775f757f3fSDimitry Andric 
4785f757f3fSDimitry Andric     auto FIN = MIRBuilder.buildFrameIndex(p0, FI);
4795f757f3fSDimitry Andric     auto Offset = MIRBuilder.buildConstant(
4805f757f3fSDimitry Andric         MRI.createGenericVirtualRegister(sXLen), XLenInBytes);
4815f757f3fSDimitry Andric 
4825f757f3fSDimitry Andric     // Copy the integer registers that may have been used for passing varargs
4835f757f3fSDimitry Andric     // to the vararg save area.
4845f757f3fSDimitry Andric     const MVT XLenVT = Subtarget.getXLenVT();
4855f757f3fSDimitry Andric     for (unsigned I = Idx; I < ArgRegs.size(); ++I) {
4865f757f3fSDimitry Andric       const Register VReg = MRI.createGenericVirtualRegister(sXLen);
4875f757f3fSDimitry Andric       Handler.assignValueToReg(
4885f757f3fSDimitry Andric           VReg, ArgRegs[I],
4895f757f3fSDimitry Andric           CCValAssign::getReg(I + MF.getFunction().getNumOperands(), XLenVT,
4905f757f3fSDimitry Andric                               ArgRegs[I], XLenVT, CCValAssign::Full));
4915f757f3fSDimitry Andric       auto MPO =
4925f757f3fSDimitry Andric           MachinePointerInfo::getFixedStack(MF, FI, (I - Idx) * XLenInBytes);
4935f757f3fSDimitry Andric       MIRBuilder.buildStore(VReg, FIN, MPO, inferAlignFromPtrInfo(MF, MPO));
4945f757f3fSDimitry Andric       FIN = MIRBuilder.buildPtrAdd(MRI.createGenericVirtualRegister(p0),
4955f757f3fSDimitry Andric                                    FIN.getReg(0), Offset);
4965f757f3fSDimitry Andric     }
4975f757f3fSDimitry Andric   }
4985f757f3fSDimitry Andric 
4995f757f3fSDimitry Andric   // Record the frame index of the first variable argument which is a value
5005f757f3fSDimitry Andric   // necessary to G_VASTART.
5015f757f3fSDimitry Andric   RVFI->setVarArgsFrameIndex(FI);
5025f757f3fSDimitry Andric   RVFI->setVarArgsSaveSize(VarArgsSaveSize);
5035f757f3fSDimitry Andric }
5045f757f3fSDimitry Andric 
lowerFormalArguments(MachineIRBuilder & MIRBuilder,const Function & F,ArrayRef<ArrayRef<Register>> VRegs,FunctionLoweringInfo & FLI) const505bdd1243dSDimitry Andric bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
506bdd1243dSDimitry Andric                                              const Function &F,
507bdd1243dSDimitry Andric                                              ArrayRef<ArrayRef<Register>> VRegs,
508bdd1243dSDimitry Andric                                              FunctionLoweringInfo &FLI) const {
5095f757f3fSDimitry Andric   // Early exit if there are no arguments. varargs are not part of F.args() but
5105f757f3fSDimitry Andric   // must be lowered.
5115f757f3fSDimitry Andric   if (F.arg_empty() && !F.isVarArg())
512bdd1243dSDimitry Andric     return true;
513bdd1243dSDimitry Andric 
5145f757f3fSDimitry Andric   const RISCVSubtarget &Subtarget =
5155f757f3fSDimitry Andric       MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
51606c3fb27SDimitry Andric   for (auto &Arg : F.args()) {
5175f757f3fSDimitry Andric     if (!isSupportedArgumentType(Arg.getType(), Subtarget,
5185f757f3fSDimitry Andric                                  /*IsLowerArgs=*/true))
51906c3fb27SDimitry Andric       return false;
52006c3fb27SDimitry Andric   }
52106c3fb27SDimitry Andric 
52206c3fb27SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
52306c3fb27SDimitry Andric   const DataLayout &DL = MF.getDataLayout();
52406c3fb27SDimitry Andric   CallingConv::ID CC = F.getCallingConv();
52506c3fb27SDimitry Andric 
52606c3fb27SDimitry Andric   SmallVector<ArgInfo, 32> SplitArgInfos;
527*0fca6ea1SDimitry Andric   SmallVector<Type *, 4> TypeList;
52806c3fb27SDimitry Andric   unsigned Index = 0;
52906c3fb27SDimitry Andric   for (auto &Arg : F.args()) {
53006c3fb27SDimitry Andric     // Construct the ArgInfo object from destination register and argument type.
53106c3fb27SDimitry Andric     ArgInfo AInfo(VRegs[Index], Arg.getType(), Index);
53206c3fb27SDimitry Andric     setArgFlags(AInfo, Index + AttributeList::FirstArgIndex, DL, F);
53306c3fb27SDimitry Andric 
53406c3fb27SDimitry Andric     // Handle any required merging from split value types from physical
53506c3fb27SDimitry Andric     // registers into the desired VReg. ArgInfo objects are constructed
53606c3fb27SDimitry Andric     // correspondingly and appended to SplitArgInfos.
53706c3fb27SDimitry Andric     splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
53806c3fb27SDimitry Andric 
539*0fca6ea1SDimitry Andric     TypeList.push_back(Arg.getType());
540*0fca6ea1SDimitry Andric 
54106c3fb27SDimitry Andric     ++Index;
54206c3fb27SDimitry Andric   }
54306c3fb27SDimitry Andric 
544*0fca6ea1SDimitry Andric   RVVArgDispatcher Dispatcher{&MF, getTLI<RISCVTargetLowering>(),
545*0fca6ea1SDimitry Andric                               ArrayRef(TypeList)};
54606c3fb27SDimitry Andric   RISCVIncomingValueAssigner Assigner(
54706c3fb27SDimitry Andric       CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
548*0fca6ea1SDimitry Andric       /*IsRet=*/false, Dispatcher);
5495f757f3fSDimitry Andric   RISCVFormalArgHandler Handler(MIRBuilder, MF.getRegInfo());
55006c3fb27SDimitry Andric 
5515f757f3fSDimitry Andric   SmallVector<CCValAssign, 16> ArgLocs;
5525f757f3fSDimitry Andric   CCState CCInfo(CC, F.isVarArg(), MIRBuilder.getMF(), ArgLocs, F.getContext());
5535f757f3fSDimitry Andric   if (!determineAssignments(Assigner, SplitArgInfos, CCInfo) ||
5545f757f3fSDimitry Andric       !handleAssignments(Handler, SplitArgInfos, CCInfo, ArgLocs, MIRBuilder))
5555f757f3fSDimitry Andric     return false;
5565f757f3fSDimitry Andric 
5575f757f3fSDimitry Andric   if (F.isVarArg())
5585f757f3fSDimitry Andric     saveVarArgRegisters(MIRBuilder, Handler, Assigner, CCInfo);
5595f757f3fSDimitry Andric 
5605f757f3fSDimitry Andric   return true;
561bdd1243dSDimitry Andric }
562bdd1243dSDimitry Andric 
lowerCall(MachineIRBuilder & MIRBuilder,CallLoweringInfo & Info) const563bdd1243dSDimitry Andric bool RISCVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
564bdd1243dSDimitry Andric                                   CallLoweringInfo &Info) const {
56506c3fb27SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
56606c3fb27SDimitry Andric   const DataLayout &DL = MF.getDataLayout();
56706c3fb27SDimitry Andric   const Function &F = MF.getFunction();
56806c3fb27SDimitry Andric   CallingConv::ID CC = F.getCallingConv();
56906c3fb27SDimitry Andric 
5705f757f3fSDimitry Andric   const RISCVSubtarget &Subtarget =
5715f757f3fSDimitry Andric       MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
57206c3fb27SDimitry Andric   for (auto &AInfo : Info.OrigArgs) {
5735f757f3fSDimitry Andric     if (!isSupportedArgumentType(AInfo.Ty, Subtarget))
57406c3fb27SDimitry Andric       return false;
57506c3fb27SDimitry Andric   }
57606c3fb27SDimitry Andric 
5775f757f3fSDimitry Andric   if (!Info.OrigRet.Ty->isVoidTy() &&
5785f757f3fSDimitry Andric       !isSupportedReturnType(Info.OrigRet.Ty, Subtarget))
5795f757f3fSDimitry Andric     return false;
5805f757f3fSDimitry Andric 
5815f757f3fSDimitry Andric   MachineInstrBuilder CallSeqStart =
5825f757f3fSDimitry Andric       MIRBuilder.buildInstr(RISCV::ADJCALLSTACKDOWN);
5835f757f3fSDimitry Andric 
58406c3fb27SDimitry Andric   SmallVector<ArgInfo, 32> SplitArgInfos;
58506c3fb27SDimitry Andric   SmallVector<ISD::OutputArg, 8> Outs;
586*0fca6ea1SDimitry Andric   SmallVector<Type *, 4> TypeList;
58706c3fb27SDimitry Andric   for (auto &AInfo : Info.OrigArgs) {
58806c3fb27SDimitry Andric     // Handle any required unmerging of split value types from a given VReg into
58906c3fb27SDimitry Andric     // physical registers. ArgInfo objects are constructed correspondingly and
59006c3fb27SDimitry Andric     // appended to SplitArgInfos.
59106c3fb27SDimitry Andric     splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
592*0fca6ea1SDimitry Andric     TypeList.push_back(AInfo.Ty);
59306c3fb27SDimitry Andric   }
59406c3fb27SDimitry Andric 
59506c3fb27SDimitry Andric   // TODO: Support tail calls.
59606c3fb27SDimitry Andric   Info.IsTailCall = false;
59706c3fb27SDimitry Andric 
5985f757f3fSDimitry Andric   // Select the recommended relocation type R_RISCV_CALL_PLT.
59906c3fb27SDimitry Andric   if (!Info.Callee.isReg())
6001db9f3b2SDimitry Andric     Info.Callee.setTargetFlags(RISCVII::MO_CALL);
60106c3fb27SDimitry Andric 
60206c3fb27SDimitry Andric   MachineInstrBuilder Call =
60306c3fb27SDimitry Andric       MIRBuilder
60406c3fb27SDimitry Andric           .buildInstrNoInsert(Info.Callee.isReg() ? RISCV::PseudoCALLIndirect
60506c3fb27SDimitry Andric                                                   : RISCV::PseudoCALL)
60606c3fb27SDimitry Andric           .add(Info.Callee);
6075f757f3fSDimitry Andric   const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
6085f757f3fSDimitry Andric   Call.addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));
60906c3fb27SDimitry Andric 
610*0fca6ea1SDimitry Andric   RVVArgDispatcher ArgDispatcher{&MF, getTLI<RISCVTargetLowering>(),
611*0fca6ea1SDimitry Andric                                  ArrayRef(TypeList)};
61206c3fb27SDimitry Andric   RISCVOutgoingValueAssigner ArgAssigner(
61306c3fb27SDimitry Andric       CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
614*0fca6ea1SDimitry Andric       /*IsRet=*/false, ArgDispatcher);
61506c3fb27SDimitry Andric   RISCVOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), Call);
61606c3fb27SDimitry Andric   if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgInfos,
61706c3fb27SDimitry Andric                                      MIRBuilder, CC, Info.IsVarArg))
61806c3fb27SDimitry Andric     return false;
61906c3fb27SDimitry Andric 
62006c3fb27SDimitry Andric   MIRBuilder.insertInstr(Call);
62106c3fb27SDimitry Andric 
6225f757f3fSDimitry Andric   CallSeqStart.addImm(ArgAssigner.StackSize).addImm(0);
6235f757f3fSDimitry Andric   MIRBuilder.buildInstr(RISCV::ADJCALLSTACKUP)
6245f757f3fSDimitry Andric       .addImm(ArgAssigner.StackSize)
6255f757f3fSDimitry Andric       .addImm(0);
6265f757f3fSDimitry Andric 
6275f757f3fSDimitry Andric   // If Callee is a reg, since it is used by a target specific
6285f757f3fSDimitry Andric   // instruction, it must have a register class matching the
6295f757f3fSDimitry Andric   // constraint of that instruction.
6305f757f3fSDimitry Andric   if (Call->getOperand(0).isReg())
6315f757f3fSDimitry Andric     constrainOperandRegClass(MF, *TRI, MF.getRegInfo(),
6325f757f3fSDimitry Andric                              *Subtarget.getInstrInfo(),
6335f757f3fSDimitry Andric                              *Subtarget.getRegBankInfo(), *Call,
6345f757f3fSDimitry Andric                              Call->getDesc(), Call->getOperand(0), 0);
6355f757f3fSDimitry Andric 
63606c3fb27SDimitry Andric   if (Info.OrigRet.Ty->isVoidTy())
63706c3fb27SDimitry Andric     return true;
63806c3fb27SDimitry Andric 
63906c3fb27SDimitry Andric   SmallVector<ArgInfo, 4> SplitRetInfos;
64006c3fb27SDimitry Andric   splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC);
64106c3fb27SDimitry Andric 
642*0fca6ea1SDimitry Andric   RVVArgDispatcher RetDispatcher{&MF, getTLI<RISCVTargetLowering>(),
643*0fca6ea1SDimitry Andric                                  ArrayRef(F.getReturnType())};
64406c3fb27SDimitry Andric   RISCVIncomingValueAssigner RetAssigner(
64506c3fb27SDimitry Andric       CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
646*0fca6ea1SDimitry Andric       /*IsRet=*/true, RetDispatcher);
64706c3fb27SDimitry Andric   RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call);
64806c3fb27SDimitry Andric   if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos,
64906c3fb27SDimitry Andric                                      MIRBuilder, CC, Info.IsVarArg))
65006c3fb27SDimitry Andric     return false;
65106c3fb27SDimitry Andric 
65206c3fb27SDimitry Andric   return true;
653bdd1243dSDimitry Andric }
654