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" 17*5f757f3fSDimitry Andric #include "RISCVMachineFunctionInfo.h" 1806c3fb27SDimitry Andric #include "RISCVSubtarget.h" 1906c3fb27SDimitry Andric #include "llvm/CodeGen/Analysis.h" 20bdd1243dSDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 21*5f757f3fSDimitry 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: 3806c3fb27SDimitry Andric RISCVOutgoingValueAssigner( 3906c3fb27SDimitry Andric RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet) 4006c3fb27SDimitry Andric : CallLowering::OutgoingValueAssigner(nullptr), 4106c3fb27SDimitry Andric RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {} 4206c3fb27SDimitry Andric 4306c3fb27SDimitry 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 51*5f757f3fSDimitry Andric if (RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT, 52*5f757f3fSDimitry Andric LocInfo, Flags, State, Info.IsFixed, IsRet, Info.Ty, 53*5f757f3fSDimitry Andric *Subtarget.getTargetLowering(), 54*5f757f3fSDimitry Andric /*FirstMaskArgument=*/std::nullopt)) 55*5f757f3fSDimitry Andric return true; 56*5f757f3fSDimitry Andric 57*5f757f3fSDimitry Andric StackSize = State.getStackSize(); 58*5f757f3fSDimitry Andric return false; 5906c3fb27SDimitry Andric } 6006c3fb27SDimitry Andric }; 6106c3fb27SDimitry Andric 6206c3fb27SDimitry Andric struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler { 6306c3fb27SDimitry Andric RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI, 6406c3fb27SDimitry Andric MachineInstrBuilder MIB) 65*5f757f3fSDimitry Andric : OutgoingValueHandler(B, MRI), MIB(MIB), 66*5f757f3fSDimitry Andric Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {} 6706c3fb27SDimitry Andric Register getStackAddress(uint64_t MemSize, int64_t Offset, 6806c3fb27SDimitry Andric MachinePointerInfo &MPO, 6906c3fb27SDimitry Andric ISD::ArgFlagsTy Flags) override { 70*5f757f3fSDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 71*5f757f3fSDimitry Andric LLT p0 = LLT::pointer(0, Subtarget.getXLen()); 72*5f757f3fSDimitry Andric LLT sXLen = LLT::scalar(Subtarget.getXLen()); 73*5f757f3fSDimitry Andric 74*5f757f3fSDimitry Andric if (!SPReg) 75*5f757f3fSDimitry Andric SPReg = MIRBuilder.buildCopy(p0, Register(RISCV::X2)).getReg(0); 76*5f757f3fSDimitry Andric 77*5f757f3fSDimitry Andric auto OffsetReg = MIRBuilder.buildConstant(sXLen, Offset); 78*5f757f3fSDimitry Andric 79*5f757f3fSDimitry Andric auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg); 80*5f757f3fSDimitry Andric 81*5f757f3fSDimitry Andric MPO = MachinePointerInfo::getStack(MF, Offset); 82*5f757f3fSDimitry Andric return AddrReg.getReg(0); 8306c3fb27SDimitry Andric } 8406c3fb27SDimitry Andric 8506c3fb27SDimitry Andric void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, 86*5f757f3fSDimitry Andric const MachinePointerInfo &MPO, 87*5f757f3fSDimitry Andric const CCValAssign &VA) override { 88*5f757f3fSDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 89*5f757f3fSDimitry Andric uint64_t LocMemOffset = VA.getLocMemOffset(); 90*5f757f3fSDimitry Andric 91*5f757f3fSDimitry Andric // TODO: Move StackAlignment to subtarget and share with FrameLowering. 92*5f757f3fSDimitry Andric auto MMO = 93*5f757f3fSDimitry Andric MF.getMachineMemOperand(MPO, MachineMemOperand::MOStore, MemTy, 94*5f757f3fSDimitry Andric commonAlignment(Align(16), LocMemOffset)); 95*5f757f3fSDimitry Andric 96*5f757f3fSDimitry Andric Register ExtReg = extendRegister(ValVReg, VA); 97*5f757f3fSDimitry Andric MIRBuilder.buildStore(ExtReg, Addr, *MMO); 9806c3fb27SDimitry Andric } 9906c3fb27SDimitry Andric 10006c3fb27SDimitry Andric void assignValueToReg(Register ValVReg, Register PhysReg, 101*5f757f3fSDimitry Andric const CCValAssign &VA) override { 102*5f757f3fSDimitry Andric // If we're passing an f32 value into an i64, anyextend before copying. 103*5f757f3fSDimitry Andric if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) 104*5f757f3fSDimitry Andric ValVReg = MIRBuilder.buildAnyExt(LLT::scalar(64), ValVReg).getReg(0); 105*5f757f3fSDimitry Andric 10606c3fb27SDimitry Andric Register ExtReg = extendRegister(ValVReg, VA); 10706c3fb27SDimitry Andric MIRBuilder.buildCopy(PhysReg, ExtReg); 10806c3fb27SDimitry Andric MIB.addUse(PhysReg, RegState::Implicit); 10906c3fb27SDimitry Andric } 110*5f757f3fSDimitry Andric 111*5f757f3fSDimitry Andric unsigned assignCustomValue(CallLowering::ArgInfo &Arg, 112*5f757f3fSDimitry Andric ArrayRef<CCValAssign> VAs, 113*5f757f3fSDimitry Andric std::function<void()> *Thunk) override { 114*5f757f3fSDimitry Andric assert(VAs.size() >= 2 && "Expected at least 2 VAs."); 115*5f757f3fSDimitry Andric const CCValAssign &VALo = VAs[0]; 116*5f757f3fSDimitry Andric const CCValAssign &VAHi = VAs[1]; 117*5f757f3fSDimitry Andric 118*5f757f3fSDimitry Andric assert(VAHi.needsCustom() && "Value doesn't need custom handling"); 119*5f757f3fSDimitry Andric assert(VALo.getValNo() == VAHi.getValNo() && 120*5f757f3fSDimitry Andric "Values belong to different arguments"); 121*5f757f3fSDimitry Andric 122*5f757f3fSDimitry Andric assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 && 123*5f757f3fSDimitry Andric VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 && 124*5f757f3fSDimitry Andric "unexpected custom value"); 125*5f757f3fSDimitry Andric 126*5f757f3fSDimitry Andric Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)), 127*5f757f3fSDimitry Andric MRI.createGenericVirtualRegister(LLT::scalar(32))}; 128*5f757f3fSDimitry Andric MIRBuilder.buildUnmerge(NewRegs, Arg.Regs[0]); 129*5f757f3fSDimitry Andric 130*5f757f3fSDimitry Andric if (VAHi.isMemLoc()) { 131*5f757f3fSDimitry Andric LLT MemTy(VAHi.getLocVT()); 132*5f757f3fSDimitry Andric 133*5f757f3fSDimitry Andric MachinePointerInfo MPO; 134*5f757f3fSDimitry Andric Register StackAddr = getStackAddress( 135*5f757f3fSDimitry Andric MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]); 136*5f757f3fSDimitry Andric 137*5f757f3fSDimitry Andric assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO, 138*5f757f3fSDimitry Andric const_cast<CCValAssign &>(VAHi)); 139*5f757f3fSDimitry Andric } 140*5f757f3fSDimitry Andric 141*5f757f3fSDimitry Andric auto assignFunc = [=]() { 142*5f757f3fSDimitry Andric assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo); 143*5f757f3fSDimitry Andric if (VAHi.isRegLoc()) 144*5f757f3fSDimitry Andric assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi); 145*5f757f3fSDimitry Andric }; 146*5f757f3fSDimitry Andric 147*5f757f3fSDimitry Andric if (Thunk) { 148*5f757f3fSDimitry Andric *Thunk = assignFunc; 149*5f757f3fSDimitry Andric return 1; 150*5f757f3fSDimitry Andric } 151*5f757f3fSDimitry Andric 152*5f757f3fSDimitry Andric assignFunc(); 153*5f757f3fSDimitry Andric return 1; 154*5f757f3fSDimitry Andric } 155*5f757f3fSDimitry Andric 156*5f757f3fSDimitry Andric private: 157*5f757f3fSDimitry Andric MachineInstrBuilder MIB; 158*5f757f3fSDimitry Andric 159*5f757f3fSDimitry Andric // Cache the SP register vreg if we need it more than once in this call site. 160*5f757f3fSDimitry Andric Register SPReg; 161*5f757f3fSDimitry Andric 162*5f757f3fSDimitry 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: 17606c3fb27SDimitry Andric RISCVIncomingValueAssigner( 17706c3fb27SDimitry Andric RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet) 17806c3fb27SDimitry Andric : CallLowering::IncomingValueAssigner(nullptr), 17906c3fb27SDimitry Andric RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {} 18006c3fb27SDimitry Andric 18106c3fb27SDimitry 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 189*5f757f3fSDimitry Andric if (LocVT.isScalableVector()) 190*5f757f3fSDimitry Andric MF.getInfo<RISCVMachineFunctionInfo>()->setIsVectorCall(); 191*5f757f3fSDimitry Andric 192*5f757f3fSDimitry Andric if (RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT, 193*5f757f3fSDimitry Andric LocInfo, Flags, State, /*IsFixed=*/true, IsRet, Info.Ty, 194*5f757f3fSDimitry Andric *Subtarget.getTargetLowering(), 195*5f757f3fSDimitry Andric /*FirstMaskArgument=*/std::nullopt)) 196*5f757f3fSDimitry Andric return true; 197*5f757f3fSDimitry Andric 198*5f757f3fSDimitry Andric StackSize = State.getStackSize(); 199*5f757f3fSDimitry Andric return false; 20006c3fb27SDimitry Andric } 20106c3fb27SDimitry Andric }; 20206c3fb27SDimitry Andric 20306c3fb27SDimitry Andric struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler { 20406c3fb27SDimitry Andric RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI) 205*5f757f3fSDimitry Andric : IncomingValueHandler(B, MRI), 206*5f757f3fSDimitry Andric Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {} 20706c3fb27SDimitry Andric 20806c3fb27SDimitry Andric Register getStackAddress(uint64_t MemSize, int64_t Offset, 20906c3fb27SDimitry Andric MachinePointerInfo &MPO, 21006c3fb27SDimitry Andric ISD::ArgFlagsTy Flags) override { 211*5f757f3fSDimitry Andric MachineFrameInfo &MFI = MIRBuilder.getMF().getFrameInfo(); 212*5f757f3fSDimitry Andric 213*5f757f3fSDimitry Andric int FI = MFI.CreateFixedObject(MemSize, Offset, /*Immutable=*/true); 214*5f757f3fSDimitry Andric MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI); 215*5f757f3fSDimitry Andric return MIRBuilder.buildFrameIndex(LLT::pointer(0, Subtarget.getXLen()), FI) 216*5f757f3fSDimitry Andric .getReg(0); 21706c3fb27SDimitry Andric } 21806c3fb27SDimitry Andric 21906c3fb27SDimitry Andric void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, 220*5f757f3fSDimitry Andric const MachinePointerInfo &MPO, 221*5f757f3fSDimitry Andric const CCValAssign &VA) override { 222*5f757f3fSDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 223*5f757f3fSDimitry Andric auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy, 224*5f757f3fSDimitry Andric inferAlignFromPtrInfo(MF, MPO)); 225*5f757f3fSDimitry Andric MIRBuilder.buildLoad(ValVReg, Addr, *MMO); 22606c3fb27SDimitry Andric } 22706c3fb27SDimitry Andric 22806c3fb27SDimitry Andric void assignValueToReg(Register ValVReg, Register PhysReg, 229*5f757f3fSDimitry Andric const CCValAssign &VA) override { 230*5f757f3fSDimitry Andric markPhysRegUsed(PhysReg); 231*5f757f3fSDimitry Andric IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA); 232*5f757f3fSDimitry Andric } 233*5f757f3fSDimitry Andric 234*5f757f3fSDimitry Andric unsigned assignCustomValue(CallLowering::ArgInfo &Arg, 235*5f757f3fSDimitry Andric ArrayRef<CCValAssign> VAs, 236*5f757f3fSDimitry Andric std::function<void()> *Thunk) override { 237*5f757f3fSDimitry Andric assert(VAs.size() >= 2 && "Expected at least 2 VAs."); 238*5f757f3fSDimitry Andric const CCValAssign &VALo = VAs[0]; 239*5f757f3fSDimitry Andric const CCValAssign &VAHi = VAs[1]; 240*5f757f3fSDimitry Andric 241*5f757f3fSDimitry Andric assert(VAHi.needsCustom() && "Value doesn't need custom handling"); 242*5f757f3fSDimitry Andric assert(VALo.getValNo() == VAHi.getValNo() && 243*5f757f3fSDimitry Andric "Values belong to different arguments"); 244*5f757f3fSDimitry Andric 245*5f757f3fSDimitry Andric assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 && 246*5f757f3fSDimitry Andric VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 && 247*5f757f3fSDimitry Andric "unexpected custom value"); 248*5f757f3fSDimitry Andric 249*5f757f3fSDimitry Andric Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)), 250*5f757f3fSDimitry Andric MRI.createGenericVirtualRegister(LLT::scalar(32))}; 251*5f757f3fSDimitry Andric 252*5f757f3fSDimitry Andric if (VAHi.isMemLoc()) { 253*5f757f3fSDimitry Andric LLT MemTy(VAHi.getLocVT()); 254*5f757f3fSDimitry Andric 255*5f757f3fSDimitry Andric MachinePointerInfo MPO; 256*5f757f3fSDimitry Andric Register StackAddr = getStackAddress( 257*5f757f3fSDimitry Andric MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]); 258*5f757f3fSDimitry Andric 259*5f757f3fSDimitry Andric assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO, 260*5f757f3fSDimitry Andric const_cast<CCValAssign &>(VAHi)); 261*5f757f3fSDimitry Andric } 262*5f757f3fSDimitry Andric 263*5f757f3fSDimitry Andric assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo); 264*5f757f3fSDimitry Andric if (VAHi.isRegLoc()) 265*5f757f3fSDimitry Andric assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi); 266*5f757f3fSDimitry Andric 267*5f757f3fSDimitry Andric MIRBuilder.buildMergeLikeInstr(Arg.Regs[0], NewRegs); 268*5f757f3fSDimitry Andric 269*5f757f3fSDimitry Andric return 1; 270*5f757f3fSDimitry Andric } 271*5f757f3fSDimitry Andric 272*5f757f3fSDimitry Andric /// How the physical register gets marked varies between formal 273*5f757f3fSDimitry Andric /// parameters (it's a basic-block live-in), and a call instruction 274*5f757f3fSDimitry Andric /// (it's an implicit-def of the BL). 275*5f757f3fSDimitry Andric virtual void markPhysRegUsed(MCRegister PhysReg) = 0; 276*5f757f3fSDimitry Andric 277*5f757f3fSDimitry Andric private: 278*5f757f3fSDimitry Andric const RISCVSubtarget &Subtarget; 279*5f757f3fSDimitry Andric }; 280*5f757f3fSDimitry Andric 281*5f757f3fSDimitry Andric struct RISCVFormalArgHandler : public RISCVIncomingValueHandler { 282*5f757f3fSDimitry Andric RISCVFormalArgHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI) 283*5f757f3fSDimitry Andric : RISCVIncomingValueHandler(B, MRI) {} 284*5f757f3fSDimitry Andric 285*5f757f3fSDimitry Andric void markPhysRegUsed(MCRegister PhysReg) override { 286*5f757f3fSDimitry Andric MIRBuilder.getMRI()->addLiveIn(PhysReg); 28706c3fb27SDimitry Andric MIRBuilder.getMBB().addLiveIn(PhysReg); 28806c3fb27SDimitry Andric } 28906c3fb27SDimitry Andric }; 29006c3fb27SDimitry Andric 29106c3fb27SDimitry Andric struct RISCVCallReturnHandler : public RISCVIncomingValueHandler { 29206c3fb27SDimitry Andric RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI, 29306c3fb27SDimitry Andric MachineInstrBuilder &MIB) 29406c3fb27SDimitry Andric : RISCVIncomingValueHandler(B, MRI), MIB(MIB) {} 29506c3fb27SDimitry Andric 296*5f757f3fSDimitry Andric void markPhysRegUsed(MCRegister PhysReg) override { 29706c3fb27SDimitry Andric MIB.addDef(PhysReg, RegState::Implicit); 29806c3fb27SDimitry Andric } 299*5f757f3fSDimitry Andric 300*5f757f3fSDimitry Andric MachineInstrBuilder MIB; 30106c3fb27SDimitry Andric }; 30206c3fb27SDimitry Andric 30306c3fb27SDimitry Andric } // namespace 30406c3fb27SDimitry Andric 305bdd1243dSDimitry Andric RISCVCallLowering::RISCVCallLowering(const RISCVTargetLowering &TLI) 306bdd1243dSDimitry Andric : CallLowering(&TLI) {} 307bdd1243dSDimitry Andric 308*5f757f3fSDimitry Andric /// Return true if scalable vector with ScalarTy is legal for lowering. 309*5f757f3fSDimitry Andric static bool isLegalElementTypeForRVV(Type *EltTy, 310*5f757f3fSDimitry Andric const RISCVSubtarget &Subtarget) { 311*5f757f3fSDimitry Andric if (EltTy->isPointerTy()) 312*5f757f3fSDimitry Andric return Subtarget.is64Bit() ? Subtarget.hasVInstructionsI64() : true; 313*5f757f3fSDimitry Andric if (EltTy->isIntegerTy(1) || EltTy->isIntegerTy(8) || 314*5f757f3fSDimitry Andric EltTy->isIntegerTy(16) || EltTy->isIntegerTy(32)) 315*5f757f3fSDimitry Andric return true; 316*5f757f3fSDimitry Andric if (EltTy->isIntegerTy(64)) 317*5f757f3fSDimitry Andric return Subtarget.hasVInstructionsI64(); 318*5f757f3fSDimitry Andric if (EltTy->isHalfTy()) 319*5f757f3fSDimitry Andric return Subtarget.hasVInstructionsF16(); 320*5f757f3fSDimitry Andric if (EltTy->isBFloatTy()) 321*5f757f3fSDimitry Andric return Subtarget.hasVInstructionsBF16(); 322*5f757f3fSDimitry Andric if (EltTy->isFloatTy()) 323*5f757f3fSDimitry Andric return Subtarget.hasVInstructionsF32(); 324*5f757f3fSDimitry Andric if (EltTy->isDoubleTy()) 325*5f757f3fSDimitry Andric return Subtarget.hasVInstructionsF64(); 326*5f757f3fSDimitry Andric return false; 327*5f757f3fSDimitry Andric } 328*5f757f3fSDimitry Andric 329*5f757f3fSDimitry Andric // TODO: Support all argument types. 330*5f757f3fSDimitry Andric // TODO: Remove IsLowerArgs argument by adding support for vectors in lowerCall. 331*5f757f3fSDimitry Andric static bool isSupportedArgumentType(Type *T, const RISCVSubtarget &Subtarget, 332*5f757f3fSDimitry Andric bool IsLowerArgs = false) { 333*5f757f3fSDimitry Andric // TODO: Integers larger than 2*XLen are passed indirectly which is not 334*5f757f3fSDimitry Andric // supported yet. 335*5f757f3fSDimitry Andric if (T->isIntegerTy()) 336*5f757f3fSDimitry Andric return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2; 337*5f757f3fSDimitry Andric if (T->isFloatTy() || T->isDoubleTy()) 338*5f757f3fSDimitry Andric return true; 339*5f757f3fSDimitry Andric if (T->isPointerTy()) 340*5f757f3fSDimitry Andric return true; 341*5f757f3fSDimitry Andric // TODO: Support fixed vector types. 342*5f757f3fSDimitry Andric if (IsLowerArgs && T->isVectorTy() && Subtarget.hasVInstructions() && 343*5f757f3fSDimitry Andric T->isScalableTy() && 344*5f757f3fSDimitry Andric isLegalElementTypeForRVV(T->getScalarType(), Subtarget)) 345*5f757f3fSDimitry Andric return true; 346*5f757f3fSDimitry Andric return false; 347*5f757f3fSDimitry Andric } 348*5f757f3fSDimitry Andric 349*5f757f3fSDimitry Andric // TODO: Only integer, pointer and aggregate types are supported now. 350*5f757f3fSDimitry Andric // TODO: Remove IsLowerRetVal argument by adding support for vectors in 351*5f757f3fSDimitry Andric // lowerCall. 352*5f757f3fSDimitry Andric static bool isSupportedReturnType(Type *T, const RISCVSubtarget &Subtarget, 353*5f757f3fSDimitry Andric bool IsLowerRetVal = false) { 354*5f757f3fSDimitry Andric // TODO: Integers larger than 2*XLen are passed indirectly which is not 355*5f757f3fSDimitry Andric // supported yet. 356*5f757f3fSDimitry Andric if (T->isIntegerTy()) 357*5f757f3fSDimitry Andric return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2; 358*5f757f3fSDimitry Andric if (T->isFloatTy() || T->isDoubleTy()) 359*5f757f3fSDimitry Andric return true; 360*5f757f3fSDimitry Andric if (T->isPointerTy()) 361*5f757f3fSDimitry Andric return true; 362*5f757f3fSDimitry Andric 363*5f757f3fSDimitry Andric if (T->isArrayTy()) 364*5f757f3fSDimitry Andric return isSupportedReturnType(T->getArrayElementType(), Subtarget); 365*5f757f3fSDimitry Andric 366*5f757f3fSDimitry Andric if (T->isStructTy()) { 367*5f757f3fSDimitry Andric auto StructT = cast<StructType>(T); 368*5f757f3fSDimitry Andric for (unsigned i = 0, e = StructT->getNumElements(); i != e; ++i) 369*5f757f3fSDimitry Andric if (!isSupportedReturnType(StructT->getElementType(i), Subtarget)) 370*5f757f3fSDimitry Andric return false; 371*5f757f3fSDimitry Andric return true; 372*5f757f3fSDimitry Andric } 373*5f757f3fSDimitry Andric 374*5f757f3fSDimitry Andric if (IsLowerRetVal && T->isVectorTy() && Subtarget.hasVInstructions() && 375*5f757f3fSDimitry Andric T->isScalableTy() && 376*5f757f3fSDimitry Andric isLegalElementTypeForRVV(T->getScalarType(), Subtarget)) 377*5f757f3fSDimitry Andric return true; 378*5f757f3fSDimitry Andric 379*5f757f3fSDimitry Andric return false; 380*5f757f3fSDimitry Andric } 381*5f757f3fSDimitry Andric 38206c3fb27SDimitry 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 389*5f757f3fSDimitry Andric const RISCVSubtarget &Subtarget = 390*5f757f3fSDimitry Andric MIRBuilder.getMF().getSubtarget<RISCVSubtarget>(); 391*5f757f3fSDimitry 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 413bdd1243dSDimitry 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 426*5f757f3fSDimitry Andric /// If there are varargs that were passed in a0-a7, the data in those registers 427*5f757f3fSDimitry Andric /// must be copied to the varargs save area on the stack. 428*5f757f3fSDimitry Andric void RISCVCallLowering::saveVarArgRegisters( 429*5f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder, CallLowering::IncomingValueHandler &Handler, 430*5f757f3fSDimitry Andric IncomingValueAssigner &Assigner, CCState &CCInfo) const { 431*5f757f3fSDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 432*5f757f3fSDimitry Andric const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>(); 433*5f757f3fSDimitry Andric unsigned XLenInBytes = Subtarget.getXLen() / 8; 434*5f757f3fSDimitry Andric ArrayRef<MCPhysReg> ArgRegs = RISCV::getArgGPRs(); 435*5f757f3fSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 436*5f757f3fSDimitry Andric unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs); 437*5f757f3fSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 438*5f757f3fSDimitry Andric RISCVMachineFunctionInfo *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); 439*5f757f3fSDimitry Andric 440*5f757f3fSDimitry Andric // Size of the vararg save area. For now, the varargs save area is either 441*5f757f3fSDimitry Andric // zero or large enough to hold a0-a7. 442*5f757f3fSDimitry Andric int VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx); 443*5f757f3fSDimitry Andric int FI; 444*5f757f3fSDimitry Andric 445*5f757f3fSDimitry Andric // If all registers are allocated, then all varargs must be passed on the 446*5f757f3fSDimitry Andric // stack and we don't need to save any argregs. 447*5f757f3fSDimitry Andric if (VarArgsSaveSize == 0) { 448*5f757f3fSDimitry Andric int VaArgOffset = Assigner.StackSize; 449*5f757f3fSDimitry Andric FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true); 450*5f757f3fSDimitry Andric } else { 451*5f757f3fSDimitry Andric int VaArgOffset = -VarArgsSaveSize; 452*5f757f3fSDimitry Andric FI = MFI.CreateFixedObject(VarArgsSaveSize, VaArgOffset, true); 453*5f757f3fSDimitry Andric 454*5f757f3fSDimitry Andric // If saving an odd number of registers then create an extra stack slot to 455*5f757f3fSDimitry Andric // ensure that the frame pointer is 2*XLEN-aligned, which in turn ensures 456*5f757f3fSDimitry Andric // offsets to even-numbered registered remain 2*XLEN-aligned. 457*5f757f3fSDimitry Andric if (Idx % 2) { 458*5f757f3fSDimitry Andric MFI.CreateFixedObject(XLenInBytes, 459*5f757f3fSDimitry Andric VaArgOffset - static_cast<int>(XLenInBytes), true); 460*5f757f3fSDimitry Andric VarArgsSaveSize += XLenInBytes; 461*5f757f3fSDimitry Andric } 462*5f757f3fSDimitry Andric 463*5f757f3fSDimitry Andric const LLT p0 = LLT::pointer(MF.getDataLayout().getAllocaAddrSpace(), 464*5f757f3fSDimitry Andric Subtarget.getXLen()); 465*5f757f3fSDimitry Andric const LLT sXLen = LLT::scalar(Subtarget.getXLen()); 466*5f757f3fSDimitry Andric 467*5f757f3fSDimitry Andric auto FIN = MIRBuilder.buildFrameIndex(p0, FI); 468*5f757f3fSDimitry Andric auto Offset = MIRBuilder.buildConstant( 469*5f757f3fSDimitry Andric MRI.createGenericVirtualRegister(sXLen), XLenInBytes); 470*5f757f3fSDimitry Andric 471*5f757f3fSDimitry Andric // Copy the integer registers that may have been used for passing varargs 472*5f757f3fSDimitry Andric // to the vararg save area. 473*5f757f3fSDimitry Andric const MVT XLenVT = Subtarget.getXLenVT(); 474*5f757f3fSDimitry Andric for (unsigned I = Idx; I < ArgRegs.size(); ++I) { 475*5f757f3fSDimitry Andric const Register VReg = MRI.createGenericVirtualRegister(sXLen); 476*5f757f3fSDimitry Andric Handler.assignValueToReg( 477*5f757f3fSDimitry Andric VReg, ArgRegs[I], 478*5f757f3fSDimitry Andric CCValAssign::getReg(I + MF.getFunction().getNumOperands(), XLenVT, 479*5f757f3fSDimitry Andric ArgRegs[I], XLenVT, CCValAssign::Full)); 480*5f757f3fSDimitry Andric auto MPO = 481*5f757f3fSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI, (I - Idx) * XLenInBytes); 482*5f757f3fSDimitry Andric MIRBuilder.buildStore(VReg, FIN, MPO, inferAlignFromPtrInfo(MF, MPO)); 483*5f757f3fSDimitry Andric FIN = MIRBuilder.buildPtrAdd(MRI.createGenericVirtualRegister(p0), 484*5f757f3fSDimitry Andric FIN.getReg(0), Offset); 485*5f757f3fSDimitry Andric } 486*5f757f3fSDimitry Andric } 487*5f757f3fSDimitry Andric 488*5f757f3fSDimitry Andric // Record the frame index of the first variable argument which is a value 489*5f757f3fSDimitry Andric // necessary to G_VASTART. 490*5f757f3fSDimitry Andric RVFI->setVarArgsFrameIndex(FI); 491*5f757f3fSDimitry Andric RVFI->setVarArgsSaveSize(VarArgsSaveSize); 492*5f757f3fSDimitry Andric } 493*5f757f3fSDimitry Andric 494bdd1243dSDimitry Andric bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, 495bdd1243dSDimitry Andric const Function &F, 496bdd1243dSDimitry Andric ArrayRef<ArrayRef<Register>> VRegs, 497bdd1243dSDimitry Andric FunctionLoweringInfo &FLI) const { 498*5f757f3fSDimitry Andric // Early exit if there are no arguments. varargs are not part of F.args() but 499*5f757f3fSDimitry Andric // must be lowered. 500*5f757f3fSDimitry Andric if (F.arg_empty() && !F.isVarArg()) 501bdd1243dSDimitry Andric return true; 502bdd1243dSDimitry Andric 503*5f757f3fSDimitry Andric const RISCVSubtarget &Subtarget = 504*5f757f3fSDimitry Andric MIRBuilder.getMF().getSubtarget<RISCVSubtarget>(); 50506c3fb27SDimitry Andric for (auto &Arg : F.args()) { 506*5f757f3fSDimitry Andric if (!isSupportedArgumentType(Arg.getType(), Subtarget, 507*5f757f3fSDimitry 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); 533*5f757f3fSDimitry Andric RISCVFormalArgHandler Handler(MIRBuilder, MF.getRegInfo()); 53406c3fb27SDimitry Andric 535*5f757f3fSDimitry Andric SmallVector<CCValAssign, 16> ArgLocs; 536*5f757f3fSDimitry Andric CCState CCInfo(CC, F.isVarArg(), MIRBuilder.getMF(), ArgLocs, F.getContext()); 537*5f757f3fSDimitry Andric if (!determineAssignments(Assigner, SplitArgInfos, CCInfo) || 538*5f757f3fSDimitry Andric !handleAssignments(Handler, SplitArgInfos, CCInfo, ArgLocs, MIRBuilder)) 539*5f757f3fSDimitry Andric return false; 540*5f757f3fSDimitry Andric 541*5f757f3fSDimitry Andric if (F.isVarArg()) 542*5f757f3fSDimitry Andric saveVarArgRegisters(MIRBuilder, Handler, Assigner, CCInfo); 543*5f757f3fSDimitry Andric 544*5f757f3fSDimitry Andric return true; 545bdd1243dSDimitry Andric } 546bdd1243dSDimitry Andric 547bdd1243dSDimitry 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 554*5f757f3fSDimitry Andric const RISCVSubtarget &Subtarget = 555*5f757f3fSDimitry Andric MIRBuilder.getMF().getSubtarget<RISCVSubtarget>(); 55606c3fb27SDimitry Andric for (auto &AInfo : Info.OrigArgs) { 557*5f757f3fSDimitry Andric if (!isSupportedArgumentType(AInfo.Ty, Subtarget)) 55806c3fb27SDimitry Andric return false; 55906c3fb27SDimitry Andric } 56006c3fb27SDimitry Andric 561*5f757f3fSDimitry Andric if (!Info.OrigRet.Ty->isVoidTy() && 562*5f757f3fSDimitry Andric !isSupportedReturnType(Info.OrigRet.Ty, Subtarget)) 563*5f757f3fSDimitry Andric return false; 564*5f757f3fSDimitry Andric 565*5f757f3fSDimitry Andric MachineInstrBuilder CallSeqStart = 566*5f757f3fSDimitry Andric MIRBuilder.buildInstr(RISCV::ADJCALLSTACKDOWN); 567*5f757f3fSDimitry 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 580*5f757f3fSDimitry Andric // Select the recommended relocation type R_RISCV_CALL_PLT. 58106c3fb27SDimitry Andric if (!Info.Callee.isReg()) 582*5f757f3fSDimitry Andric Info.Callee.setTargetFlags(RISCVII::MO_PLT); 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); 589*5f757f3fSDimitry Andric const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); 590*5f757f3fSDimitry 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 602*5f757f3fSDimitry Andric CallSeqStart.addImm(ArgAssigner.StackSize).addImm(0); 603*5f757f3fSDimitry Andric MIRBuilder.buildInstr(RISCV::ADJCALLSTACKUP) 604*5f757f3fSDimitry Andric .addImm(ArgAssigner.StackSize) 605*5f757f3fSDimitry Andric .addImm(0); 606*5f757f3fSDimitry Andric 607*5f757f3fSDimitry Andric // If Callee is a reg, since it is used by a target specific 608*5f757f3fSDimitry Andric // instruction, it must have a register class matching the 609*5f757f3fSDimitry Andric // constraint of that instruction. 610*5f757f3fSDimitry Andric if (Call->getOperand(0).isReg()) 611*5f757f3fSDimitry Andric constrainOperandRegClass(MF, *TRI, MF.getRegInfo(), 612*5f757f3fSDimitry Andric *Subtarget.getInstrInfo(), 613*5f757f3fSDimitry Andric *Subtarget.getRegBankInfo(), *Call, 614*5f757f3fSDimitry Andric Call->getDesc(), Call->getOperand(0), 0); 615*5f757f3fSDimitry 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