Files
clang-p2996/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
Craig Topper 3c5b42acd3 [RISCV] Allocate the varargs GPR save area as a single object. (#74354)
Previously we allocated one object for each GPR. We also allocated the
same offset twice, once to save for VASTART and then again for the first
register in the save loop.

This patch uses a single object for all the registers and shares this
with VASTART. This is more consistent with other targets like AArch64
and ARM.

I've removed the setValue(nullptr) from the memory operand now. Having a
single object makes me a lot more comfortable about alias analysis being
able to see what is going on. This led to the scheduling changes in
push-pop-popret.ll and vararg.ll.
2023-12-05 10:30:01 -08:00

632 lines
24 KiB
C++

//===-- RISCVCallLowering.cpp - Call lowering -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This file implements the lowering of LLVM calls to machine code calls for
/// GlobalISel.
//
//===----------------------------------------------------------------------===//
#include "RISCVCallLowering.h"
#include "RISCVISelLowering.h"
#include "RISCVMachineFunctionInfo.h"
#include "RISCVSubtarget.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
using namespace llvm;
namespace {
struct RISCVOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner {
private:
// The function used internally to assign args - we ignore the AssignFn stored
// by OutgoingValueAssigner since RISC-V implements its CC using a custom
// function with a different signature.
RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn;
// Whether this is assigning args for a return.
bool IsRet;
public:
RISCVOutgoingValueAssigner(
RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
: CallLowering::OutgoingValueAssigner(nullptr),
RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
CCValAssign::LocInfo LocInfo,
const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
CCState &State) override {
MachineFunction &MF = State.getMachineFunction();
const DataLayout &DL = MF.getDataLayout();
const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
if (RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT,
LocInfo, Flags, State, Info.IsFixed, IsRet, Info.Ty,
*Subtarget.getTargetLowering(),
/*FirstMaskArgument=*/std::nullopt))
return true;
StackSize = State.getStackSize();
return false;
}
};
struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
MachineInstrBuilder MIB)
: OutgoingValueHandler(B, MRI), MIB(MIB),
Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
Register getStackAddress(uint64_t MemSize, int64_t Offset,
MachinePointerInfo &MPO,
ISD::ArgFlagsTy Flags) override {
MachineFunction &MF = MIRBuilder.getMF();
LLT p0 = LLT::pointer(0, Subtarget.getXLen());
LLT sXLen = LLT::scalar(Subtarget.getXLen());
if (!SPReg)
SPReg = MIRBuilder.buildCopy(p0, Register(RISCV::X2)).getReg(0);
auto OffsetReg = MIRBuilder.buildConstant(sXLen, Offset);
auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg);
MPO = MachinePointerInfo::getStack(MF, Offset);
return AddrReg.getReg(0);
}
void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
const MachinePointerInfo &MPO,
const CCValAssign &VA) override {
MachineFunction &MF = MIRBuilder.getMF();
uint64_t LocMemOffset = VA.getLocMemOffset();
// TODO: Move StackAlignment to subtarget and share with FrameLowering.
auto MMO =
MF.getMachineMemOperand(MPO, MachineMemOperand::MOStore, MemTy,
commonAlignment(Align(16), LocMemOffset));
Register ExtReg = extendRegister(ValVReg, VA);
MIRBuilder.buildStore(ExtReg, Addr, *MMO);
}
void assignValueToReg(Register ValVReg, Register PhysReg,
const CCValAssign &VA) override {
// If we're passing an f32 value into an i64, anyextend before copying.
if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
ValVReg = MIRBuilder.buildAnyExt(LLT::scalar(64), ValVReg).getReg(0);
Register ExtReg = extendRegister(ValVReg, VA);
MIRBuilder.buildCopy(PhysReg, ExtReg);
MIB.addUse(PhysReg, RegState::Implicit);
}
unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
ArrayRef<CCValAssign> VAs,
std::function<void()> *Thunk) override {
assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
const CCValAssign &VALo = VAs[0];
const CCValAssign &VAHi = VAs[1];
assert(VAHi.needsCustom() && "Value doesn't need custom handling");
assert(VALo.getValNo() == VAHi.getValNo() &&
"Values belong to different arguments");
assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
"unexpected custom value");
Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
MRI.createGenericVirtualRegister(LLT::scalar(32))};
MIRBuilder.buildUnmerge(NewRegs, Arg.Regs[0]);
if (VAHi.isMemLoc()) {
LLT MemTy(VAHi.getLocVT());
MachinePointerInfo MPO;
Register StackAddr = getStackAddress(
MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
const_cast<CCValAssign &>(VAHi));
}
auto assignFunc = [=]() {
assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
if (VAHi.isRegLoc())
assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
};
if (Thunk) {
*Thunk = assignFunc;
return 1;
}
assignFunc();
return 1;
}
private:
MachineInstrBuilder MIB;
// Cache the SP register vreg if we need it more than once in this call site.
Register SPReg;
const RISCVSubtarget &Subtarget;
};
struct RISCVIncomingValueAssigner : public CallLowering::IncomingValueAssigner {
private:
// The function used internally to assign args - we ignore the AssignFn stored
// by IncomingValueAssigner since RISC-V implements its CC using a custom
// function with a different signature.
RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn;
// Whether this is assigning args from a return.
bool IsRet;
public:
RISCVIncomingValueAssigner(
RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet)
: CallLowering::IncomingValueAssigner(nullptr),
RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {}
bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
CCValAssign::LocInfo LocInfo,
const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
CCState &State) override {
MachineFunction &MF = State.getMachineFunction();
const DataLayout &DL = MF.getDataLayout();
const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
if (LocVT.isScalableVector())
MF.getInfo<RISCVMachineFunctionInfo>()->setIsVectorCall();
if (RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT,
LocInfo, Flags, State, /*IsFixed=*/true, IsRet, Info.Ty,
*Subtarget.getTargetLowering(),
/*FirstMaskArgument=*/std::nullopt))
return true;
StackSize = State.getStackSize();
return false;
}
};
struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
: IncomingValueHandler(B, MRI),
Subtarget(MIRBuilder.getMF().getSubtarget<RISCVSubtarget>()) {}
Register getStackAddress(uint64_t MemSize, int64_t Offset,
MachinePointerInfo &MPO,
ISD::ArgFlagsTy Flags) override {
MachineFrameInfo &MFI = MIRBuilder.getMF().getFrameInfo();
int FI = MFI.CreateFixedObject(MemSize, Offset, /*Immutable=*/true);
MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
return MIRBuilder.buildFrameIndex(LLT::pointer(0, Subtarget.getXLen()), FI)
.getReg(0);
}
void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
const MachinePointerInfo &MPO,
const CCValAssign &VA) override {
MachineFunction &MF = MIRBuilder.getMF();
auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy,
inferAlignFromPtrInfo(MF, MPO));
MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
}
void assignValueToReg(Register ValVReg, Register PhysReg,
const CCValAssign &VA) override {
markPhysRegUsed(PhysReg);
IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);
}
unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
ArrayRef<CCValAssign> VAs,
std::function<void()> *Thunk) override {
assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
const CCValAssign &VALo = VAs[0];
const CCValAssign &VAHi = VAs[1];
assert(VAHi.needsCustom() && "Value doesn't need custom handling");
assert(VALo.getValNo() == VAHi.getValNo() &&
"Values belong to different arguments");
assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
"unexpected custom value");
Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
MRI.createGenericVirtualRegister(LLT::scalar(32))};
if (VAHi.isMemLoc()) {
LLT MemTy(VAHi.getLocVT());
MachinePointerInfo MPO;
Register StackAddr = getStackAddress(
MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
const_cast<CCValAssign &>(VAHi));
}
assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
if (VAHi.isRegLoc())
assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
MIRBuilder.buildMergeLikeInstr(Arg.Regs[0], NewRegs);
return 1;
}
/// How the physical register gets marked varies between formal
/// parameters (it's a basic-block live-in), and a call instruction
/// (it's an implicit-def of the BL).
virtual void markPhysRegUsed(MCRegister PhysReg) = 0;
private:
const RISCVSubtarget &Subtarget;
};
struct RISCVFormalArgHandler : public RISCVIncomingValueHandler {
RISCVFormalArgHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI)
: RISCVIncomingValueHandler(B, MRI) {}
void markPhysRegUsed(MCRegister PhysReg) override {
MIRBuilder.getMRI()->addLiveIn(PhysReg);
MIRBuilder.getMBB().addLiveIn(PhysReg);
}
};
struct RISCVCallReturnHandler : public RISCVIncomingValueHandler {
RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI,
MachineInstrBuilder &MIB)
: RISCVIncomingValueHandler(B, MRI), MIB(MIB) {}
void markPhysRegUsed(MCRegister PhysReg) override {
MIB.addDef(PhysReg, RegState::Implicit);
}
MachineInstrBuilder MIB;
};
} // namespace
RISCVCallLowering::RISCVCallLowering(const RISCVTargetLowering &TLI)
: CallLowering(&TLI) {}
/// Return true if scalable vector with ScalarTy is legal for lowering.
static bool isLegalElementTypeForRVV(Type *EltTy,
const RISCVSubtarget &Subtarget) {
if (EltTy->isPointerTy())
return Subtarget.is64Bit() ? Subtarget.hasVInstructionsI64() : true;
if (EltTy->isIntegerTy(1) || EltTy->isIntegerTy(8) ||
EltTy->isIntegerTy(16) || EltTy->isIntegerTy(32))
return true;
if (EltTy->isIntegerTy(64))
return Subtarget.hasVInstructionsI64();
if (EltTy->isHalfTy())
return Subtarget.hasVInstructionsF16();
if (EltTy->isBFloatTy())
return Subtarget.hasVInstructionsBF16();
if (EltTy->isFloatTy())
return Subtarget.hasVInstructionsF32();
if (EltTy->isDoubleTy())
return Subtarget.hasVInstructionsF64();
return false;
}
// TODO: Support all argument types.
// TODO: Remove IsLowerArgs argument by adding support for vectors in lowerCall.
static bool isSupportedArgumentType(Type *T, const RISCVSubtarget &Subtarget,
bool IsLowerArgs = false) {
// TODO: Integers larger than 2*XLen are passed indirectly which is not
// supported yet.
if (T->isIntegerTy())
return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2;
if (T->isFloatTy() || T->isDoubleTy())
return true;
if (T->isPointerTy())
return true;
// TODO: Support fixed vector types.
if (IsLowerArgs && T->isVectorTy() && Subtarget.hasVInstructions() &&
T->isScalableTy() &&
isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
return true;
return false;
}
// TODO: Only integer, pointer and aggregate types are supported now.
// TODO: Remove IsLowerRetVal argument by adding support for vectors in
// lowerCall.
static bool isSupportedReturnType(Type *T, const RISCVSubtarget &Subtarget,
bool IsLowerRetVal = false) {
// TODO: Integers larger than 2*XLen are passed indirectly which is not
// supported yet.
if (T->isIntegerTy())
return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2;
if (T->isFloatTy() || T->isDoubleTy())
return true;
if (T->isPointerTy())
return true;
if (T->isArrayTy())
return isSupportedReturnType(T->getArrayElementType(), Subtarget);
if (T->isStructTy()) {
auto StructT = cast<StructType>(T);
for (unsigned i = 0, e = StructT->getNumElements(); i != e; ++i)
if (!isSupportedReturnType(StructT->getElementType(i), Subtarget))
return false;
return true;
}
if (IsLowerRetVal && T->isVectorTy() && Subtarget.hasVInstructions() &&
T->isScalableTy() &&
isLegalElementTypeForRVV(T->getScalarType(), Subtarget))
return true;
return false;
}
bool RISCVCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
const Value *Val,
ArrayRef<Register> VRegs,
MachineInstrBuilder &Ret) const {
if (!Val)
return true;
const RISCVSubtarget &Subtarget =
MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
if (!isSupportedReturnType(Val->getType(), Subtarget, /*IsLowerRetVal=*/true))
return false;
MachineFunction &MF = MIRBuilder.getMF();
const DataLayout &DL = MF.getDataLayout();
const Function &F = MF.getFunction();
CallingConv::ID CC = F.getCallingConv();
ArgInfo OrigRetInfo(VRegs, Val->getType(), 0);
setArgFlags(OrigRetInfo, AttributeList::ReturnIndex, DL, F);
SmallVector<ArgInfo, 4> SplitRetInfos;
splitToValueTypes(OrigRetInfo, SplitRetInfos, DL, CC);
RISCVOutgoingValueAssigner Assigner(
CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
/*IsRet=*/true);
RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret);
return determineAndHandleAssignments(Handler, Assigner, SplitRetInfos,
MIRBuilder, CC, F.isVarArg());
}
bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
const Value *Val, ArrayRef<Register> VRegs,
FunctionLoweringInfo &FLI) const {
assert(!Val == VRegs.empty() && "Return value without a vreg");
MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET);
if (!lowerReturnVal(MIRBuilder, Val, VRegs, Ret))
return false;
MIRBuilder.insertInstr(Ret);
return true;
}
/// If there are varargs that were passed in a0-a7, the data in those registers
/// must be copied to the varargs save area on the stack.
void RISCVCallLowering::saveVarArgRegisters(
MachineIRBuilder &MIRBuilder, CallLowering::IncomingValueHandler &Handler,
IncomingValueAssigner &Assigner, CCState &CCInfo) const {
MachineFunction &MF = MIRBuilder.getMF();
const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
unsigned XLenInBytes = Subtarget.getXLen() / 8;
ArrayRef<MCPhysReg> ArgRegs = RISCV::getArgGPRs();
MachineRegisterInfo &MRI = MF.getRegInfo();
unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
MachineFrameInfo &MFI = MF.getFrameInfo();
RISCVMachineFunctionInfo *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
// Size of the vararg save area. For now, the varargs save area is either
// zero or large enough to hold a0-a7.
int VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx);
int FI;
// If all registers are allocated, then all varargs must be passed on the
// stack and we don't need to save any argregs.
if (VarArgsSaveSize == 0) {
int VaArgOffset = Assigner.StackSize;
FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
} else {
int VaArgOffset = -VarArgsSaveSize;
FI = MFI.CreateFixedObject(VarArgsSaveSize, VaArgOffset, true);
// If saving an odd number of registers then create an extra stack slot to
// ensure that the frame pointer is 2*XLEN-aligned, which in turn ensures
// offsets to even-numbered registered remain 2*XLEN-aligned.
if (Idx % 2) {
MFI.CreateFixedObject(XLenInBytes,
VaArgOffset - static_cast<int>(XLenInBytes), true);
VarArgsSaveSize += XLenInBytes;
}
const LLT p0 = LLT::pointer(MF.getDataLayout().getAllocaAddrSpace(),
Subtarget.getXLen());
const LLT sXLen = LLT::scalar(Subtarget.getXLen());
auto FIN = MIRBuilder.buildFrameIndex(p0, FI);
auto Offset = MIRBuilder.buildConstant(
MRI.createGenericVirtualRegister(sXLen), XLenInBytes);
// Copy the integer registers that may have been used for passing varargs
// to the vararg save area.
const MVT XLenVT = Subtarget.getXLenVT();
for (unsigned I = Idx; I < ArgRegs.size(); ++I) {
const Register VReg = MRI.createGenericVirtualRegister(sXLen);
Handler.assignValueToReg(
VReg, ArgRegs[I],
CCValAssign::getReg(I + MF.getFunction().getNumOperands(), XLenVT,
ArgRegs[I], XLenVT, CCValAssign::Full));
auto MPO =
MachinePointerInfo::getFixedStack(MF, FI, (I - Idx) * XLenInBytes);
MIRBuilder.buildStore(VReg, FIN, MPO, inferAlignFromPtrInfo(MF, MPO));
FIN = MIRBuilder.buildPtrAdd(MRI.createGenericVirtualRegister(p0),
FIN.getReg(0), Offset);
}
}
// Record the frame index of the first variable argument which is a value
// necessary to G_VASTART.
RVFI->setVarArgsFrameIndex(FI);
RVFI->setVarArgsSaveSize(VarArgsSaveSize);
}
bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
const Function &F,
ArrayRef<ArrayRef<Register>> VRegs,
FunctionLoweringInfo &FLI) const {
// Early exit if there are no arguments. varargs are not part of F.args() but
// must be lowered.
if (F.arg_empty() && !F.isVarArg())
return true;
const RISCVSubtarget &Subtarget =
MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
for (auto &Arg : F.args()) {
if (!isSupportedArgumentType(Arg.getType(), Subtarget,
/*IsLowerArgs=*/true))
return false;
}
MachineFunction &MF = MIRBuilder.getMF();
const DataLayout &DL = MF.getDataLayout();
CallingConv::ID CC = F.getCallingConv();
SmallVector<ArgInfo, 32> SplitArgInfos;
unsigned Index = 0;
for (auto &Arg : F.args()) {
// Construct the ArgInfo object from destination register and argument type.
ArgInfo AInfo(VRegs[Index], Arg.getType(), Index);
setArgFlags(AInfo, Index + AttributeList::FirstArgIndex, DL, F);
// Handle any required merging from split value types from physical
// registers into the desired VReg. ArgInfo objects are constructed
// correspondingly and appended to SplitArgInfos.
splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
++Index;
}
RISCVIncomingValueAssigner Assigner(
CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
/*IsRet=*/false);
RISCVFormalArgHandler Handler(MIRBuilder, MF.getRegInfo());
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CC, F.isVarArg(), MIRBuilder.getMF(), ArgLocs, F.getContext());
if (!determineAssignments(Assigner, SplitArgInfos, CCInfo) ||
!handleAssignments(Handler, SplitArgInfos, CCInfo, ArgLocs, MIRBuilder))
return false;
if (F.isVarArg())
saveVarArgRegisters(MIRBuilder, Handler, Assigner, CCInfo);
return true;
}
bool RISCVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
CallLoweringInfo &Info) const {
MachineFunction &MF = MIRBuilder.getMF();
const DataLayout &DL = MF.getDataLayout();
const Function &F = MF.getFunction();
CallingConv::ID CC = F.getCallingConv();
const RISCVSubtarget &Subtarget =
MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
for (auto &AInfo : Info.OrigArgs) {
if (!isSupportedArgumentType(AInfo.Ty, Subtarget))
return false;
}
if (!Info.OrigRet.Ty->isVoidTy() &&
!isSupportedReturnType(Info.OrigRet.Ty, Subtarget))
return false;
MachineInstrBuilder CallSeqStart =
MIRBuilder.buildInstr(RISCV::ADJCALLSTACKDOWN);
SmallVector<ArgInfo, 32> SplitArgInfos;
SmallVector<ISD::OutputArg, 8> Outs;
for (auto &AInfo : Info.OrigArgs) {
// Handle any required unmerging of split value types from a given VReg into
// physical registers. ArgInfo objects are constructed correspondingly and
// appended to SplitArgInfos.
splitToValueTypes(AInfo, SplitArgInfos, DL, CC);
}
// TODO: Support tail calls.
Info.IsTailCall = false;
// Select the recommended relocation type R_RISCV_CALL_PLT.
if (!Info.Callee.isReg())
Info.Callee.setTargetFlags(RISCVII::MO_PLT);
MachineInstrBuilder Call =
MIRBuilder
.buildInstrNoInsert(Info.Callee.isReg() ? RISCV::PseudoCALLIndirect
: RISCV::PseudoCALL)
.add(Info.Callee);
const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
Call.addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));
RISCVOutgoingValueAssigner ArgAssigner(
CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
/*IsRet=*/false);
RISCVOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), Call);
if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgInfos,
MIRBuilder, CC, Info.IsVarArg))
return false;
MIRBuilder.insertInstr(Call);
CallSeqStart.addImm(ArgAssigner.StackSize).addImm(0);
MIRBuilder.buildInstr(RISCV::ADJCALLSTACKUP)
.addImm(ArgAssigner.StackSize)
.addImm(0);
// If Callee is a reg, since it is used by a target specific
// instruction, it must have a register class matching the
// constraint of that instruction.
if (Call->getOperand(0).isReg())
constrainOperandRegClass(MF, *TRI, MF.getRegInfo(),
*Subtarget.getInstrInfo(),
*Subtarget.getRegBankInfo(), *Call,
Call->getDesc(), Call->getOperand(0), 0);
if (Info.OrigRet.Ty->isVoidTy())
return true;
SmallVector<ArgInfo, 4> SplitRetInfos;
splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC);
RISCVIncomingValueAssigner RetAssigner(
CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
/*IsRet=*/true);
RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call);
if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos,
MIRBuilder, CC, Info.IsVarArg))
return false;
return true;
}