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*06c3fb27SDimitry Andric #include "RISCVSubtarget.h" 18*06c3fb27SDimitry Andric #include "llvm/CodeGen/Analysis.h" 19bdd1243dSDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 20bdd1243dSDimitry Andric 21bdd1243dSDimitry Andric using namespace llvm; 22bdd1243dSDimitry Andric 23*06c3fb27SDimitry Andric namespace { 24*06c3fb27SDimitry Andric 25*06c3fb27SDimitry Andric struct RISCVOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner { 26*06c3fb27SDimitry Andric private: 27*06c3fb27SDimitry Andric // The function used internally to assign args - we ignore the AssignFn stored 28*06c3fb27SDimitry Andric // by OutgoingValueAssigner since RISC-V implements its CC using a custom 29*06c3fb27SDimitry Andric // function with a different signature. 30*06c3fb27SDimitry Andric RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn; 31*06c3fb27SDimitry Andric 32*06c3fb27SDimitry Andric // Whether this is assigning args for a return. 33*06c3fb27SDimitry Andric bool IsRet; 34*06c3fb27SDimitry Andric 35*06c3fb27SDimitry Andric public: 36*06c3fb27SDimitry Andric RISCVOutgoingValueAssigner( 37*06c3fb27SDimitry Andric RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet) 38*06c3fb27SDimitry Andric : CallLowering::OutgoingValueAssigner(nullptr), 39*06c3fb27SDimitry Andric RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {} 40*06c3fb27SDimitry Andric 41*06c3fb27SDimitry Andric bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT, 42*06c3fb27SDimitry Andric CCValAssign::LocInfo LocInfo, 43*06c3fb27SDimitry Andric const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags, 44*06c3fb27SDimitry Andric CCState &State) override { 45*06c3fb27SDimitry Andric MachineFunction &MF = State.getMachineFunction(); 46*06c3fb27SDimitry Andric const DataLayout &DL = MF.getDataLayout(); 47*06c3fb27SDimitry Andric const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>(); 48*06c3fb27SDimitry Andric 49*06c3fb27SDimitry Andric return RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT, 50*06c3fb27SDimitry Andric LocInfo, Flags, State, /*IsFixed=*/true, IsRet, 51*06c3fb27SDimitry Andric Info.Ty, *Subtarget.getTargetLowering(), 52*06c3fb27SDimitry Andric /*FirstMaskArgument=*/std::nullopt); 53*06c3fb27SDimitry Andric } 54*06c3fb27SDimitry Andric }; 55*06c3fb27SDimitry Andric 56*06c3fb27SDimitry Andric struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler { 57*06c3fb27SDimitry Andric RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI, 58*06c3fb27SDimitry Andric MachineInstrBuilder MIB) 59*06c3fb27SDimitry Andric : OutgoingValueHandler(B, MRI), MIB(MIB) {} 60*06c3fb27SDimitry Andric 61*06c3fb27SDimitry Andric MachineInstrBuilder MIB; 62*06c3fb27SDimitry Andric 63*06c3fb27SDimitry Andric Register getStackAddress(uint64_t MemSize, int64_t Offset, 64*06c3fb27SDimitry Andric MachinePointerInfo &MPO, 65*06c3fb27SDimitry Andric ISD::ArgFlagsTy Flags) override { 66*06c3fb27SDimitry Andric llvm_unreachable("not implemented"); 67*06c3fb27SDimitry Andric } 68*06c3fb27SDimitry Andric 69*06c3fb27SDimitry Andric void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, 70*06c3fb27SDimitry Andric MachinePointerInfo &MPO, CCValAssign &VA) override { 71*06c3fb27SDimitry Andric llvm_unreachable("not implemented"); 72*06c3fb27SDimitry Andric } 73*06c3fb27SDimitry Andric 74*06c3fb27SDimitry Andric void assignValueToReg(Register ValVReg, Register PhysReg, 75*06c3fb27SDimitry Andric CCValAssign VA) override { 76*06c3fb27SDimitry Andric Register ExtReg = extendRegister(ValVReg, VA); 77*06c3fb27SDimitry Andric MIRBuilder.buildCopy(PhysReg, ExtReg); 78*06c3fb27SDimitry Andric MIB.addUse(PhysReg, RegState::Implicit); 79*06c3fb27SDimitry Andric } 80*06c3fb27SDimitry Andric }; 81*06c3fb27SDimitry Andric 82*06c3fb27SDimitry Andric struct RISCVIncomingValueAssigner : public CallLowering::IncomingValueAssigner { 83*06c3fb27SDimitry Andric private: 84*06c3fb27SDimitry Andric // The function used internally to assign args - we ignore the AssignFn stored 85*06c3fb27SDimitry Andric // by IncomingValueAssigner since RISC-V implements its CC using a custom 86*06c3fb27SDimitry Andric // function with a different signature. 87*06c3fb27SDimitry Andric RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn; 88*06c3fb27SDimitry Andric 89*06c3fb27SDimitry Andric // Whether this is assigning args from a return. 90*06c3fb27SDimitry Andric bool IsRet; 91*06c3fb27SDimitry Andric 92*06c3fb27SDimitry Andric public: 93*06c3fb27SDimitry Andric RISCVIncomingValueAssigner( 94*06c3fb27SDimitry Andric RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet) 95*06c3fb27SDimitry Andric : CallLowering::IncomingValueAssigner(nullptr), 96*06c3fb27SDimitry Andric RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {} 97*06c3fb27SDimitry Andric 98*06c3fb27SDimitry Andric bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT, 99*06c3fb27SDimitry Andric CCValAssign::LocInfo LocInfo, 100*06c3fb27SDimitry Andric const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags, 101*06c3fb27SDimitry Andric CCState &State) override { 102*06c3fb27SDimitry Andric MachineFunction &MF = State.getMachineFunction(); 103*06c3fb27SDimitry Andric const DataLayout &DL = MF.getDataLayout(); 104*06c3fb27SDimitry Andric const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>(); 105*06c3fb27SDimitry Andric 106*06c3fb27SDimitry Andric return RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT, 107*06c3fb27SDimitry Andric LocInfo, Flags, State, /*IsFixed=*/true, IsRet, 108*06c3fb27SDimitry Andric Info.Ty, *Subtarget.getTargetLowering(), 109*06c3fb27SDimitry Andric /*FirstMaskArgument=*/std::nullopt); 110*06c3fb27SDimitry Andric } 111*06c3fb27SDimitry Andric }; 112*06c3fb27SDimitry Andric 113*06c3fb27SDimitry Andric struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler { 114*06c3fb27SDimitry Andric RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI) 115*06c3fb27SDimitry Andric : IncomingValueHandler(B, MRI) {} 116*06c3fb27SDimitry Andric 117*06c3fb27SDimitry Andric Register getStackAddress(uint64_t MemSize, int64_t Offset, 118*06c3fb27SDimitry Andric MachinePointerInfo &MPO, 119*06c3fb27SDimitry Andric ISD::ArgFlagsTy Flags) override { 120*06c3fb27SDimitry Andric llvm_unreachable("not implemented"); 121*06c3fb27SDimitry Andric } 122*06c3fb27SDimitry Andric 123*06c3fb27SDimitry Andric void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, 124*06c3fb27SDimitry Andric MachinePointerInfo &MPO, CCValAssign &VA) override { 125*06c3fb27SDimitry Andric llvm_unreachable("not implemented"); 126*06c3fb27SDimitry Andric } 127*06c3fb27SDimitry Andric 128*06c3fb27SDimitry Andric void assignValueToReg(Register ValVReg, Register PhysReg, 129*06c3fb27SDimitry Andric CCValAssign VA) override { 130*06c3fb27SDimitry Andric // Copy argument received in physical register to desired VReg. 131*06c3fb27SDimitry Andric MIRBuilder.getMBB().addLiveIn(PhysReg); 132*06c3fb27SDimitry Andric MIRBuilder.buildCopy(ValVReg, PhysReg); 133*06c3fb27SDimitry Andric } 134*06c3fb27SDimitry Andric }; 135*06c3fb27SDimitry Andric 136*06c3fb27SDimitry Andric struct RISCVCallReturnHandler : public RISCVIncomingValueHandler { 137*06c3fb27SDimitry Andric RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI, 138*06c3fb27SDimitry Andric MachineInstrBuilder &MIB) 139*06c3fb27SDimitry Andric : RISCVIncomingValueHandler(B, MRI), MIB(MIB) {} 140*06c3fb27SDimitry Andric 141*06c3fb27SDimitry Andric MachineInstrBuilder MIB; 142*06c3fb27SDimitry Andric 143*06c3fb27SDimitry Andric void assignValueToReg(Register ValVReg, Register PhysReg, 144*06c3fb27SDimitry Andric CCValAssign VA) override { 145*06c3fb27SDimitry Andric // Copy argument received in physical register to desired VReg. 146*06c3fb27SDimitry Andric MIB.addDef(PhysReg, RegState::Implicit); 147*06c3fb27SDimitry Andric MIRBuilder.buildCopy(ValVReg, PhysReg); 148*06c3fb27SDimitry Andric } 149*06c3fb27SDimitry Andric }; 150*06c3fb27SDimitry Andric 151*06c3fb27SDimitry Andric } // namespace 152*06c3fb27SDimitry Andric 153bdd1243dSDimitry Andric RISCVCallLowering::RISCVCallLowering(const RISCVTargetLowering &TLI) 154bdd1243dSDimitry Andric : CallLowering(&TLI) {} 155bdd1243dSDimitry Andric 156*06c3fb27SDimitry Andric bool RISCVCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder, 157*06c3fb27SDimitry Andric const Value *Val, 158*06c3fb27SDimitry Andric ArrayRef<Register> VRegs, 159*06c3fb27SDimitry Andric MachineInstrBuilder &Ret) const { 160*06c3fb27SDimitry Andric if (!Val) 161*06c3fb27SDimitry Andric return true; 162*06c3fb27SDimitry Andric 163*06c3fb27SDimitry Andric // TODO: Only integer, pointer and aggregate types are supported now. 164*06c3fb27SDimitry Andric if (!Val->getType()->isIntOrPtrTy() && !Val->getType()->isAggregateType()) 165*06c3fb27SDimitry Andric return false; 166*06c3fb27SDimitry Andric 167*06c3fb27SDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 168*06c3fb27SDimitry Andric const DataLayout &DL = MF.getDataLayout(); 169*06c3fb27SDimitry Andric const Function &F = MF.getFunction(); 170*06c3fb27SDimitry Andric CallingConv::ID CC = F.getCallingConv(); 171*06c3fb27SDimitry Andric 172*06c3fb27SDimitry Andric ArgInfo OrigRetInfo(VRegs, Val->getType(), 0); 173*06c3fb27SDimitry Andric setArgFlags(OrigRetInfo, AttributeList::ReturnIndex, DL, F); 174*06c3fb27SDimitry Andric 175*06c3fb27SDimitry Andric SmallVector<ArgInfo, 4> SplitRetInfos; 176*06c3fb27SDimitry Andric splitToValueTypes(OrigRetInfo, SplitRetInfos, DL, CC); 177*06c3fb27SDimitry Andric 178*06c3fb27SDimitry Andric RISCVOutgoingValueAssigner Assigner( 179*06c3fb27SDimitry Andric CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV, 180*06c3fb27SDimitry Andric /*IsRet=*/true); 181*06c3fb27SDimitry Andric RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret); 182*06c3fb27SDimitry Andric return determineAndHandleAssignments(Handler, Assigner, SplitRetInfos, 183*06c3fb27SDimitry Andric MIRBuilder, CC, F.isVarArg()); 184*06c3fb27SDimitry Andric } 185*06c3fb27SDimitry Andric 186bdd1243dSDimitry Andric bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, 187bdd1243dSDimitry Andric const Value *Val, ArrayRef<Register> VRegs, 188bdd1243dSDimitry Andric FunctionLoweringInfo &FLI) const { 189*06c3fb27SDimitry Andric assert(!Val == VRegs.empty() && "Return value without a vreg"); 190bdd1243dSDimitry Andric MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET); 191bdd1243dSDimitry Andric 192*06c3fb27SDimitry Andric if (!lowerReturnVal(MIRBuilder, Val, VRegs, Ret)) 193bdd1243dSDimitry Andric return false; 194*06c3fb27SDimitry Andric 195bdd1243dSDimitry Andric MIRBuilder.insertInstr(Ret); 196bdd1243dSDimitry Andric return true; 197bdd1243dSDimitry Andric } 198bdd1243dSDimitry Andric 199bdd1243dSDimitry Andric bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, 200bdd1243dSDimitry Andric const Function &F, 201bdd1243dSDimitry Andric ArrayRef<ArrayRef<Register>> VRegs, 202bdd1243dSDimitry Andric FunctionLoweringInfo &FLI) const { 203*06c3fb27SDimitry Andric // Early exit if there are no arguments. 204bdd1243dSDimitry Andric if (F.arg_empty()) 205bdd1243dSDimitry Andric return true; 206bdd1243dSDimitry Andric 207*06c3fb27SDimitry Andric // TODO: Support vararg functions. 208*06c3fb27SDimitry Andric if (F.isVarArg()) 209bdd1243dSDimitry Andric return false; 210*06c3fb27SDimitry Andric 211*06c3fb27SDimitry Andric // TODO: Support all argument types. 212*06c3fb27SDimitry Andric for (auto &Arg : F.args()) { 213*06c3fb27SDimitry Andric if (Arg.getType()->isIntegerTy()) 214*06c3fb27SDimitry Andric continue; 215*06c3fb27SDimitry Andric if (Arg.getType()->isPointerTy()) 216*06c3fb27SDimitry Andric continue; 217*06c3fb27SDimitry Andric return false; 218*06c3fb27SDimitry Andric } 219*06c3fb27SDimitry Andric 220*06c3fb27SDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 221*06c3fb27SDimitry Andric const DataLayout &DL = MF.getDataLayout(); 222*06c3fb27SDimitry Andric CallingConv::ID CC = F.getCallingConv(); 223*06c3fb27SDimitry Andric 224*06c3fb27SDimitry Andric SmallVector<ArgInfo, 32> SplitArgInfos; 225*06c3fb27SDimitry Andric unsigned Index = 0; 226*06c3fb27SDimitry Andric for (auto &Arg : F.args()) { 227*06c3fb27SDimitry Andric // Construct the ArgInfo object from destination register and argument type. 228*06c3fb27SDimitry Andric ArgInfo AInfo(VRegs[Index], Arg.getType(), Index); 229*06c3fb27SDimitry Andric setArgFlags(AInfo, Index + AttributeList::FirstArgIndex, DL, F); 230*06c3fb27SDimitry Andric 231*06c3fb27SDimitry Andric // Handle any required merging from split value types from physical 232*06c3fb27SDimitry Andric // registers into the desired VReg. ArgInfo objects are constructed 233*06c3fb27SDimitry Andric // correspondingly and appended to SplitArgInfos. 234*06c3fb27SDimitry Andric splitToValueTypes(AInfo, SplitArgInfos, DL, CC); 235*06c3fb27SDimitry Andric 236*06c3fb27SDimitry Andric ++Index; 237*06c3fb27SDimitry Andric } 238*06c3fb27SDimitry Andric 239*06c3fb27SDimitry Andric RISCVIncomingValueAssigner Assigner( 240*06c3fb27SDimitry Andric CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV, 241*06c3fb27SDimitry Andric /*IsRet=*/false); 242*06c3fb27SDimitry Andric RISCVIncomingValueHandler Handler(MIRBuilder, MF.getRegInfo()); 243*06c3fb27SDimitry Andric 244*06c3fb27SDimitry Andric return determineAndHandleAssignments(Handler, Assigner, SplitArgInfos, 245*06c3fb27SDimitry Andric MIRBuilder, CC, F.isVarArg()); 246bdd1243dSDimitry Andric } 247bdd1243dSDimitry Andric 248bdd1243dSDimitry Andric bool RISCVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, 249bdd1243dSDimitry Andric CallLoweringInfo &Info) const { 250*06c3fb27SDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 251*06c3fb27SDimitry Andric const DataLayout &DL = MF.getDataLayout(); 252*06c3fb27SDimitry Andric const Function &F = MF.getFunction(); 253*06c3fb27SDimitry Andric CallingConv::ID CC = F.getCallingConv(); 254*06c3fb27SDimitry Andric 255*06c3fb27SDimitry Andric // TODO: Support vararg functions. 256*06c3fb27SDimitry Andric if (Info.IsVarArg) 257bdd1243dSDimitry Andric return false; 258*06c3fb27SDimitry Andric 259*06c3fb27SDimitry Andric // TODO: Support all argument types. 260*06c3fb27SDimitry Andric for (auto &AInfo : Info.OrigArgs) { 261*06c3fb27SDimitry Andric if (AInfo.Ty->isIntegerTy()) 262*06c3fb27SDimitry Andric continue; 263*06c3fb27SDimitry Andric if (AInfo.Ty->isPointerTy()) 264*06c3fb27SDimitry Andric continue; 265*06c3fb27SDimitry Andric if (AInfo.Ty->isFloatingPointTy()) 266*06c3fb27SDimitry Andric continue; 267*06c3fb27SDimitry Andric return false; 268*06c3fb27SDimitry Andric } 269*06c3fb27SDimitry Andric 270*06c3fb27SDimitry Andric SmallVector<ArgInfo, 32> SplitArgInfos; 271*06c3fb27SDimitry Andric SmallVector<ISD::OutputArg, 8> Outs; 272*06c3fb27SDimitry Andric for (auto &AInfo : Info.OrigArgs) { 273*06c3fb27SDimitry Andric // Handle any required unmerging of split value types from a given VReg into 274*06c3fb27SDimitry Andric // physical registers. ArgInfo objects are constructed correspondingly and 275*06c3fb27SDimitry Andric // appended to SplitArgInfos. 276*06c3fb27SDimitry Andric splitToValueTypes(AInfo, SplitArgInfos, DL, CC); 277*06c3fb27SDimitry Andric } 278*06c3fb27SDimitry Andric 279*06c3fb27SDimitry Andric // TODO: Support tail calls. 280*06c3fb27SDimitry Andric Info.IsTailCall = false; 281*06c3fb27SDimitry Andric 282*06c3fb27SDimitry Andric if (!Info.Callee.isReg()) 283*06c3fb27SDimitry Andric Info.Callee.setTargetFlags(RISCVII::MO_CALL); 284*06c3fb27SDimitry Andric 285*06c3fb27SDimitry Andric MachineInstrBuilder Call = 286*06c3fb27SDimitry Andric MIRBuilder 287*06c3fb27SDimitry Andric .buildInstrNoInsert(Info.Callee.isReg() ? RISCV::PseudoCALLIndirect 288*06c3fb27SDimitry Andric : RISCV::PseudoCALL) 289*06c3fb27SDimitry Andric .add(Info.Callee); 290*06c3fb27SDimitry Andric 291*06c3fb27SDimitry Andric RISCVOutgoingValueAssigner ArgAssigner( 292*06c3fb27SDimitry Andric CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV, 293*06c3fb27SDimitry Andric /*IsRet=*/false); 294*06c3fb27SDimitry Andric RISCVOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), Call); 295*06c3fb27SDimitry Andric if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgInfos, 296*06c3fb27SDimitry Andric MIRBuilder, CC, Info.IsVarArg)) 297*06c3fb27SDimitry Andric return false; 298*06c3fb27SDimitry Andric 299*06c3fb27SDimitry Andric MIRBuilder.insertInstr(Call); 300*06c3fb27SDimitry Andric 301*06c3fb27SDimitry Andric if (Info.OrigRet.Ty->isVoidTy()) 302*06c3fb27SDimitry Andric return true; 303*06c3fb27SDimitry Andric 304*06c3fb27SDimitry Andric // TODO: Only integer, pointer and aggregate types are supported now. 305*06c3fb27SDimitry Andric if (!Info.OrigRet.Ty->isIntOrPtrTy() && !Info.OrigRet.Ty->isAggregateType()) 306*06c3fb27SDimitry Andric return false; 307*06c3fb27SDimitry Andric 308*06c3fb27SDimitry Andric SmallVector<ArgInfo, 4> SplitRetInfos; 309*06c3fb27SDimitry Andric splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC); 310*06c3fb27SDimitry Andric 311*06c3fb27SDimitry Andric // Assignments should be handled *before* the merging of values takes place. 312*06c3fb27SDimitry Andric // To ensure this, the insert point is temporarily adjusted to just after the 313*06c3fb27SDimitry Andric // call instruction. 314*06c3fb27SDimitry Andric MachineBasicBlock::iterator CallInsertPt = Call; 315*06c3fb27SDimitry Andric MIRBuilder.setInsertPt(MIRBuilder.getMBB(), std::next(CallInsertPt)); 316*06c3fb27SDimitry Andric 317*06c3fb27SDimitry Andric RISCVIncomingValueAssigner RetAssigner( 318*06c3fb27SDimitry Andric CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV, 319*06c3fb27SDimitry Andric /*IsRet=*/true); 320*06c3fb27SDimitry Andric RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call); 321*06c3fb27SDimitry Andric if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos, 322*06c3fb27SDimitry Andric MIRBuilder, CC, Info.IsVarArg)) 323*06c3fb27SDimitry Andric return false; 324*06c3fb27SDimitry Andric 325*06c3fb27SDimitry Andric // Readjust insert point to end of basic block. 326*06c3fb27SDimitry Andric MIRBuilder.setMBB(MIRBuilder.getMBB()); 327*06c3fb27SDimitry Andric 328*06c3fb27SDimitry Andric return true; 329bdd1243dSDimitry Andric } 330