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: 4006c3fb27SDimitry 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 4706c3fb27SDimitry 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 { 6606c3fb27SDimitry Andric RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI, 6706c3fb27SDimitry Andric MachineInstrBuilder MIB) 685f757f3fSDimitry Andric : OutgoingValueHandler(B, MRI), MIB(MIB), 695f757f3fSDimitry Andric Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {} 7006c3fb27SDimitry 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 8806c3fb27SDimitry 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 10306c3fb27SDimitry 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 1195f757f3fSDimitry 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: 18606c3fb27SDimitry 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 19306c3fb27SDimitry 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 { 21506c3fb27SDimitry Andric RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI) 2165f757f3fSDimitry Andric : IncomingValueHandler(B, MRI), 2175f757f3fSDimitry Andric Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {} 21806c3fb27SDimitry Andric 21906c3fb27SDimitry 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 23006c3fb27SDimitry 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 23906c3fb27SDimitry 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 2455f757f3fSDimitry 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 { 2935f757f3fSDimitry Andric RISCVFormalArgHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI) 2945f757f3fSDimitry Andric : RISCVIncomingValueHandler(B, MRI) {} 2955f757f3fSDimitry Andric 2965f757f3fSDimitry 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 { 30306c3fb27SDimitry Andric RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI, 30406c3fb27SDimitry Andric MachineInstrBuilder &MIB) 30506c3fb27SDimitry Andric : RISCVIncomingValueHandler(B, MRI), MIB(MIB) {} 30606c3fb27SDimitry Andric 3075f757f3fSDimitry 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 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. 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. 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. 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 39106c3fb27SDimitry 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 424bdd1243dSDimitry 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. 4395f757f3fSDimitry 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 505bdd1243dSDimitry 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 563bdd1243dSDimitry 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