The delayed stack protector feature which is currently used for SDAG (and thus allows for more commonly generating tail calls) depends on being able to extract the tail call into a separate return block. To do this it also has to extract the vreg->physreg copies that set up the call's arguments, since if it doesn't then the call inst ends up using undefined physregs in it's new spliced block. SelectionDAG implementations can do this because they delay emitting register copies until *after* the stack arguments are set up. GISel however just processes and emits the arguments in IR order, so stack arguments always end up last, and thus this breaks the code that looks for any register arg copies that precede the call instruction. This patch adds a thunk argument to the assignValueToReg() and custom assignment hooks. For outgoing arguments, register assignments use this return param to return a thunk that does the actual generating of the copies. We collect these until all the outgoing stack assignments have been done and then execute them, so that the copies (and perhaps some artifacts like G_SEXTs) are placed after any stores. Differential Revision: https://reviews.llvm.org/D110610
577 lines
20 KiB
C++
577 lines
20 KiB
C++
//===- MipsCallLowering.cpp -------------------------------------*- 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 "MipsCallLowering.h"
|
|
#include "MipsCCState.h"
|
|
#include "MipsMachineFunction.h"
|
|
#include "MipsTargetMachine.h"
|
|
#include "llvm/CodeGen/Analysis.h"
|
|
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
|
|
|
using namespace llvm;
|
|
|
|
MipsCallLowering::MipsCallLowering(const MipsTargetLowering &TLI)
|
|
: CallLowering(&TLI) {}
|
|
|
|
struct MipsOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner {
|
|
/// This is the name of the function being called
|
|
/// FIXME: Relying on this is unsound
|
|
const char *Func = nullptr;
|
|
|
|
/// Is this a return value, or an outgoing call operand.
|
|
bool IsReturn;
|
|
|
|
MipsOutgoingValueAssigner(CCAssignFn *AssignFn_, const char *Func,
|
|
bool IsReturn)
|
|
: OutgoingValueAssigner(AssignFn_), Func(Func), IsReturn(IsReturn) {}
|
|
|
|
bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
|
|
CCValAssign::LocInfo LocInfo,
|
|
const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
|
|
CCState &State_) override {
|
|
MipsCCState &State = static_cast<MipsCCState &>(State_);
|
|
|
|
if (IsReturn)
|
|
State.PreAnalyzeReturnValue(EVT::getEVT(Info.Ty));
|
|
else
|
|
State.PreAnalyzeCallOperand(Info.Ty, Info.IsFixed, Func);
|
|
|
|
return CallLowering::OutgoingValueAssigner::assignArg(
|
|
ValNo, OrigVT, ValVT, LocVT, LocInfo, Info, Flags, State);
|
|
}
|
|
};
|
|
|
|
struct MipsIncomingValueAssigner : public CallLowering::IncomingValueAssigner {
|
|
/// This is the name of the function being called
|
|
/// FIXME: Relying on this is unsound
|
|
const char *Func = nullptr;
|
|
|
|
/// Is this a call return value, or an incoming function argument.
|
|
bool IsReturn;
|
|
|
|
MipsIncomingValueAssigner(CCAssignFn *AssignFn_, const char *Func,
|
|
bool IsReturn)
|
|
: IncomingValueAssigner(AssignFn_), Func(Func), IsReturn(IsReturn) {}
|
|
|
|
bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
|
|
CCValAssign::LocInfo LocInfo,
|
|
const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
|
|
CCState &State_) override {
|
|
MipsCCState &State = static_cast<MipsCCState &>(State_);
|
|
|
|
if (IsReturn)
|
|
State.PreAnalyzeCallResult(Info.Ty, Func);
|
|
else
|
|
State.PreAnalyzeFormalArgument(Info.Ty, Flags);
|
|
|
|
return CallLowering::IncomingValueAssigner::assignArg(
|
|
ValNo, OrigVT, ValVT, LocVT, LocInfo, Info, Flags, State);
|
|
}
|
|
};
|
|
|
|
namespace {
|
|
class MipsIncomingValueHandler : public CallLowering::IncomingValueHandler {
|
|
const MipsSubtarget &STI;
|
|
|
|
public:
|
|
MipsIncomingValueHandler(MachineIRBuilder &MIRBuilder,
|
|
MachineRegisterInfo &MRI)
|
|
: IncomingValueHandler(MIRBuilder, MRI),
|
|
STI(MIRBuilder.getMF().getSubtarget<MipsSubtarget>()) {}
|
|
|
|
private:
|
|
void assignValueToReg(Register ValVReg, Register PhysReg,
|
|
CCValAssign VA) override;
|
|
|
|
Register getStackAddress(uint64_t Size, int64_t Offset,
|
|
MachinePointerInfo &MPO,
|
|
ISD::ArgFlagsTy Flags) override;
|
|
void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
|
|
MachinePointerInfo &MPO, CCValAssign &VA) override;
|
|
|
|
unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
|
|
ArrayRef<CCValAssign> VAs,
|
|
std::function<void()> *Thunk = nullptr) override;
|
|
|
|
virtual void markPhysRegUsed(unsigned PhysReg) {
|
|
MIRBuilder.getMRI()->addLiveIn(PhysReg);
|
|
MIRBuilder.getMBB().addLiveIn(PhysReg);
|
|
}
|
|
};
|
|
|
|
class CallReturnHandler : public MipsIncomingValueHandler {
|
|
public:
|
|
CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
|
|
MachineInstrBuilder &MIB)
|
|
: MipsIncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
|
|
|
|
private:
|
|
void markPhysRegUsed(unsigned PhysReg) override {
|
|
MIB.addDef(PhysReg, RegState::Implicit);
|
|
}
|
|
|
|
MachineInstrBuilder &MIB;
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
void MipsIncomingValueHandler::assignValueToReg(Register ValVReg,
|
|
Register PhysReg,
|
|
CCValAssign VA) {
|
|
markPhysRegUsed(PhysReg);
|
|
IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);
|
|
}
|
|
|
|
Register MipsIncomingValueHandler::getStackAddress(uint64_t Size,
|
|
int64_t Offset,
|
|
MachinePointerInfo &MPO,
|
|
ISD::ArgFlagsTy Flags) {
|
|
|
|
MachineFunction &MF = MIRBuilder.getMF();
|
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
|
|
|
// FIXME: This should only be immutable for non-byval memory arguments.
|
|
int FI = MFI.CreateFixedObject(Size, Offset, true);
|
|
MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
|
|
|
|
return MIRBuilder.buildFrameIndex(LLT::pointer(0, 32), FI).getReg(0);
|
|
}
|
|
|
|
void MipsIncomingValueHandler::assignValueToAddress(Register ValVReg,
|
|
Register Addr, LLT MemTy,
|
|
MachinePointerInfo &MPO,
|
|
CCValAssign &VA) {
|
|
MachineFunction &MF = MIRBuilder.getMF();
|
|
auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy,
|
|
inferAlignFromPtrInfo(MF, MPO));
|
|
MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
|
|
}
|
|
|
|
/// Handle cases when f64 is split into 2 32-bit GPRs. This is a custom
|
|
/// assignment because generic code assumes getNumRegistersForCallingConv is
|
|
/// accurate. In this case it is not because the type/number are context
|
|
/// dependent on other arguments.
|
|
unsigned
|
|
MipsIncomingValueHandler::assignCustomValue(CallLowering::ArgInfo &Arg,
|
|
ArrayRef<CCValAssign> VAs,
|
|
std::function<void()> *Thunk) {
|
|
const CCValAssign &VALo = VAs[0];
|
|
const CCValAssign &VAHi = VAs[1];
|
|
|
|
assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
|
|
VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
|
|
"unexpected custom value");
|
|
|
|
auto CopyLo = MIRBuilder.buildCopy(LLT::scalar(32), VALo.getLocReg());
|
|
auto CopyHi = MIRBuilder.buildCopy(LLT::scalar(32), VAHi.getLocReg());
|
|
if (!STI.isLittle())
|
|
std::swap(CopyLo, CopyHi);
|
|
|
|
Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end());
|
|
Arg.Regs = { CopyLo.getReg(0), CopyHi.getReg(0) };
|
|
MIRBuilder.buildMerge(Arg.OrigRegs[0], {CopyLo, CopyHi});
|
|
|
|
markPhysRegUsed(VALo.getLocReg());
|
|
markPhysRegUsed(VAHi.getLocReg());
|
|
return 2;
|
|
}
|
|
|
|
namespace {
|
|
class MipsOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
|
|
const MipsSubtarget &STI;
|
|
|
|
public:
|
|
MipsOutgoingValueHandler(MachineIRBuilder &MIRBuilder,
|
|
MachineRegisterInfo &MRI, MachineInstrBuilder &MIB)
|
|
: OutgoingValueHandler(MIRBuilder, MRI),
|
|
STI(MIRBuilder.getMF().getSubtarget<MipsSubtarget>()), MIB(MIB) {}
|
|
|
|
private:
|
|
void assignValueToReg(Register ValVReg, Register PhysReg,
|
|
CCValAssign VA) override;
|
|
|
|
Register getStackAddress(uint64_t Size, int64_t Offset,
|
|
MachinePointerInfo &MPO,
|
|
ISD::ArgFlagsTy Flags) override;
|
|
|
|
void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
|
|
MachinePointerInfo &MPO, CCValAssign &VA) override;
|
|
unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
|
|
ArrayRef<CCValAssign> VAs,
|
|
std::function<void()> *Thunk) override;
|
|
|
|
MachineInstrBuilder &MIB;
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
void MipsOutgoingValueHandler::assignValueToReg(Register ValVReg,
|
|
Register PhysReg,
|
|
CCValAssign VA) {
|
|
Register ExtReg = extendRegister(ValVReg, VA);
|
|
MIRBuilder.buildCopy(PhysReg, ExtReg);
|
|
MIB.addUse(PhysReg, RegState::Implicit);
|
|
}
|
|
|
|
Register MipsOutgoingValueHandler::getStackAddress(uint64_t Size,
|
|
int64_t Offset,
|
|
MachinePointerInfo &MPO,
|
|
ISD::ArgFlagsTy Flags) {
|
|
MachineFunction &MF = MIRBuilder.getMF();
|
|
MPO = MachinePointerInfo::getStack(MF, Offset);
|
|
|
|
LLT p0 = LLT::pointer(0, 32);
|
|
LLT s32 = LLT::scalar(32);
|
|
auto SPReg = MIRBuilder.buildCopy(p0, Register(Mips::SP));
|
|
|
|
auto OffsetReg = MIRBuilder.buildConstant(s32, Offset);
|
|
auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg);
|
|
return AddrReg.getReg(0);
|
|
}
|
|
|
|
void MipsOutgoingValueHandler::assignValueToAddress(Register ValVReg,
|
|
Register Addr, LLT MemTy,
|
|
MachinePointerInfo &MPO,
|
|
CCValAssign &VA) {
|
|
MachineFunction &MF = MIRBuilder.getMF();
|
|
uint64_t LocMemOffset = VA.getLocMemOffset();
|
|
|
|
auto MMO = MF.getMachineMemOperand(
|
|
MPO, MachineMemOperand::MOStore, MemTy,
|
|
commonAlignment(STI.getStackAlignment(), LocMemOffset));
|
|
|
|
Register ExtReg = extendRegister(ValVReg, VA);
|
|
MIRBuilder.buildStore(ExtReg, Addr, *MMO);
|
|
}
|
|
|
|
unsigned
|
|
MipsOutgoingValueHandler::assignCustomValue(CallLowering::ArgInfo &Arg,
|
|
ArrayRef<CCValAssign> VAs,
|
|
std::function<void()> *Thunk) {
|
|
const CCValAssign &VALo = VAs[0];
|
|
const CCValAssign &VAHi = VAs[1];
|
|
|
|
assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
|
|
VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
|
|
"unexpected custom value");
|
|
|
|
auto Unmerge =
|
|
MIRBuilder.buildUnmerge({LLT::scalar(32), LLT::scalar(32)}, Arg.Regs[0]);
|
|
Register Lo = Unmerge.getReg(0);
|
|
Register Hi = Unmerge.getReg(1);
|
|
|
|
Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end());
|
|
Arg.Regs = { Lo, Hi };
|
|
if (!STI.isLittle())
|
|
std::swap(Lo, Hi);
|
|
|
|
// If we can return a thunk, just include the register copies. The unmerge can
|
|
// be emitted earlier.
|
|
if (Thunk) {
|
|
*Thunk = [=]() {
|
|
MIRBuilder.buildCopy(VALo.getLocReg(), Lo);
|
|
MIRBuilder.buildCopy(VAHi.getLocReg(), Hi);
|
|
};
|
|
return 2;
|
|
}
|
|
MIRBuilder.buildCopy(VALo.getLocReg(), Lo);
|
|
MIRBuilder.buildCopy(VAHi.getLocReg(), Hi);
|
|
return 2;
|
|
}
|
|
|
|
static bool isSupportedArgumentType(Type *T) {
|
|
if (T->isIntegerTy())
|
|
return true;
|
|
if (T->isPointerTy())
|
|
return true;
|
|
if (T->isFloatingPointTy())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static bool isSupportedReturnType(Type *T) {
|
|
if (T->isIntegerTy())
|
|
return true;
|
|
if (T->isPointerTy())
|
|
return true;
|
|
if (T->isFloatingPointTy())
|
|
return true;
|
|
if (T->isAggregateType())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool MipsCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
|
|
const Value *Val, ArrayRef<Register> VRegs,
|
|
FunctionLoweringInfo &FLI) const {
|
|
|
|
MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(Mips::RetRA);
|
|
|
|
if (Val != nullptr && !isSupportedReturnType(Val->getType()))
|
|
return false;
|
|
|
|
if (!VRegs.empty()) {
|
|
MachineFunction &MF = MIRBuilder.getMF();
|
|
const Function &F = MF.getFunction();
|
|
const DataLayout &DL = MF.getDataLayout();
|
|
const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
|
|
|
|
SmallVector<ArgInfo, 8> RetInfos;
|
|
|
|
ArgInfo ArgRetInfo(VRegs, *Val, 0);
|
|
setArgFlags(ArgRetInfo, AttributeList::ReturnIndex, DL, F);
|
|
splitToValueTypes(ArgRetInfo, RetInfos, DL, F.getCallingConv());
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
|
SmallVector<ISD::OutputArg, 8> Outs;
|
|
|
|
MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
|
|
F.getContext());
|
|
|
|
MipsOutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret);
|
|
std::string FuncName = F.getName().str();
|
|
MipsOutgoingValueAssigner Assigner(TLI.CCAssignFnForReturn(),
|
|
FuncName.c_str(), /*IsReturn*/ true);
|
|
|
|
if (!determineAssignments(Assigner, RetInfos, CCInfo))
|
|
return false;
|
|
|
|
if (!handleAssignments(RetHandler, RetInfos, CCInfo, ArgLocs, MIRBuilder))
|
|
return false;
|
|
}
|
|
|
|
MIRBuilder.insertInstr(Ret);
|
|
return true;
|
|
}
|
|
|
|
bool MipsCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
|
|
const Function &F,
|
|
ArrayRef<ArrayRef<Register>> VRegs,
|
|
FunctionLoweringInfo &FLI) const {
|
|
|
|
// Quick exit if there aren't any args.
|
|
if (F.arg_empty())
|
|
return true;
|
|
|
|
for (auto &Arg : F.args()) {
|
|
if (!isSupportedArgumentType(Arg.getType()))
|
|
return false;
|
|
}
|
|
|
|
MachineFunction &MF = MIRBuilder.getMF();
|
|
const DataLayout &DL = MF.getDataLayout();
|
|
const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
|
|
|
|
SmallVector<ArgInfo, 8> ArgInfos;
|
|
unsigned i = 0;
|
|
for (auto &Arg : F.args()) {
|
|
ArgInfo AInfo(VRegs[i], Arg, i);
|
|
setArgFlags(AInfo, i + AttributeList::FirstArgIndex, DL, F);
|
|
|
|
splitToValueTypes(AInfo, ArgInfos, DL, F.getCallingConv());
|
|
++i;
|
|
}
|
|
|
|
SmallVector<ISD::InputArg, 8> Ins;
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
|
MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
|
|
F.getContext());
|
|
|
|
const MipsTargetMachine &TM =
|
|
static_cast<const MipsTargetMachine &>(MF.getTarget());
|
|
const MipsABIInfo &ABI = TM.getABI();
|
|
CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(F.getCallingConv()),
|
|
Align(1));
|
|
|
|
const std::string FuncName = F.getName().str();
|
|
MipsIncomingValueAssigner Assigner(TLI.CCAssignFnForCall(), FuncName.c_str(),
|
|
/*IsReturn*/ false);
|
|
if (!determineAssignments(Assigner, ArgInfos, CCInfo))
|
|
return false;
|
|
|
|
MipsIncomingValueHandler Handler(MIRBuilder, MF.getRegInfo());
|
|
if (!handleAssignments(Handler, ArgInfos, CCInfo, ArgLocs, MIRBuilder))
|
|
return false;
|
|
|
|
if (F.isVarArg()) {
|
|
ArrayRef<MCPhysReg> ArgRegs = ABI.GetVarArgRegs();
|
|
unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
|
|
|
|
int VaArgOffset;
|
|
unsigned RegSize = 4;
|
|
if (ArgRegs.size() == Idx)
|
|
VaArgOffset = alignTo(CCInfo.getNextStackOffset(), RegSize);
|
|
else {
|
|
VaArgOffset =
|
|
(int)ABI.GetCalleeAllocdArgSizeInBytes(CCInfo.getCallingConv()) -
|
|
(int)(RegSize * (ArgRegs.size() - Idx));
|
|
}
|
|
|
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
|
int FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true);
|
|
MF.getInfo<MipsFunctionInfo>()->setVarArgsFrameIndex(FI);
|
|
|
|
for (unsigned I = Idx; I < ArgRegs.size(); ++I, VaArgOffset += RegSize) {
|
|
MIRBuilder.getMBB().addLiveIn(ArgRegs[I]);
|
|
LLT RegTy = LLT::scalar(RegSize * 8);
|
|
MachineInstrBuilder Copy =
|
|
MIRBuilder.buildCopy(RegTy, Register(ArgRegs[I]));
|
|
FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true);
|
|
MachinePointerInfo MPO = MachinePointerInfo::getFixedStack(MF, FI);
|
|
|
|
const LLT PtrTy = LLT::pointer(MPO.getAddrSpace(), 32);
|
|
auto FrameIndex = MIRBuilder.buildFrameIndex(PtrTy, FI);
|
|
MachineMemOperand *MMO = MF.getMachineMemOperand(
|
|
MPO, MachineMemOperand::MOStore, RegTy, Align(RegSize));
|
|
MIRBuilder.buildStore(Copy, FrameIndex, *MMO);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
|
|
CallLoweringInfo &Info) const {
|
|
|
|
if (Info.CallConv != CallingConv::C)
|
|
return false;
|
|
|
|
for (auto &Arg : Info.OrigArgs) {
|
|
if (!isSupportedArgumentType(Arg.Ty))
|
|
return false;
|
|
if (Arg.Flags[0].isByVal())
|
|
return false;
|
|
if (Arg.Flags[0].isSRet() && !Arg.Ty->isPointerTy())
|
|
return false;
|
|
}
|
|
|
|
if (!Info.OrigRet.Ty->isVoidTy() && !isSupportedReturnType(Info.OrigRet.Ty))
|
|
return false;
|
|
|
|
MachineFunction &MF = MIRBuilder.getMF();
|
|
const Function &F = MF.getFunction();
|
|
const DataLayout &DL = MF.getDataLayout();
|
|
const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
|
|
const MipsTargetMachine &TM =
|
|
static_cast<const MipsTargetMachine &>(MF.getTarget());
|
|
const MipsABIInfo &ABI = TM.getABI();
|
|
|
|
MachineInstrBuilder CallSeqStart =
|
|
MIRBuilder.buildInstr(Mips::ADJCALLSTACKDOWN);
|
|
|
|
const bool IsCalleeGlobalPIC =
|
|
Info.Callee.isGlobal() && TM.isPositionIndependent();
|
|
|
|
MachineInstrBuilder MIB = MIRBuilder.buildInstrNoInsert(
|
|
Info.Callee.isReg() || IsCalleeGlobalPIC ? Mips::JALRPseudo : Mips::JAL);
|
|
MIB.addDef(Mips::SP, RegState::Implicit);
|
|
if (IsCalleeGlobalPIC) {
|
|
Register CalleeReg =
|
|
MF.getRegInfo().createGenericVirtualRegister(LLT::pointer(0, 32));
|
|
MachineInstr *CalleeGlobalValue =
|
|
MIRBuilder.buildGlobalValue(CalleeReg, Info.Callee.getGlobal());
|
|
if (!Info.Callee.getGlobal()->hasLocalLinkage())
|
|
CalleeGlobalValue->getOperand(1).setTargetFlags(MipsII::MO_GOT_CALL);
|
|
MIB.addUse(CalleeReg);
|
|
} else
|
|
MIB.add(Info.Callee);
|
|
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
|
|
MIB.addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));
|
|
|
|
TargetLowering::ArgListTy FuncOrigArgs;
|
|
FuncOrigArgs.reserve(Info.OrigArgs.size());
|
|
|
|
SmallVector<ArgInfo, 8> ArgInfos;
|
|
for (auto &Arg : Info.OrigArgs)
|
|
splitToValueTypes(Arg, ArgInfos, DL, Info.CallConv);
|
|
|
|
SmallVector<CCValAssign, 8> ArgLocs;
|
|
bool IsCalleeVarArg = false;
|
|
if (Info.Callee.isGlobal()) {
|
|
const Function *CF = static_cast<const Function *>(Info.Callee.getGlobal());
|
|
IsCalleeVarArg = CF->isVarArg();
|
|
}
|
|
|
|
// FIXME: Should use MipsCCState::getSpecialCallingConvForCallee, but it
|
|
// depends on looking directly at the call target.
|
|
MipsCCState CCInfo(Info.CallConv, IsCalleeVarArg, MF, ArgLocs,
|
|
F.getContext());
|
|
|
|
CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(Info.CallConv),
|
|
Align(1));
|
|
|
|
const char *Call =
|
|
Info.Callee.isSymbol() ? Info.Callee.getSymbolName() : nullptr;
|
|
|
|
MipsOutgoingValueAssigner Assigner(TLI.CCAssignFnForCall(), Call,
|
|
/*IsReturn*/ false);
|
|
if (!determineAssignments(Assigner, ArgInfos, CCInfo))
|
|
return false;
|
|
|
|
MipsOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), MIB);
|
|
if (!handleAssignments(ArgHandler, ArgInfos, CCInfo, ArgLocs, MIRBuilder))
|
|
return false;
|
|
|
|
unsigned NextStackOffset = CCInfo.getNextStackOffset();
|
|
unsigned StackAlignment = F.getParent()->getOverrideStackAlignment();
|
|
if (!StackAlignment) {
|
|
const TargetFrameLowering *TFL = MF.getSubtarget().getFrameLowering();
|
|
StackAlignment = TFL->getStackAlignment();
|
|
}
|
|
NextStackOffset = alignTo(NextStackOffset, StackAlignment);
|
|
CallSeqStart.addImm(NextStackOffset).addImm(0);
|
|
|
|
if (IsCalleeGlobalPIC) {
|
|
MIRBuilder.buildCopy(
|
|
Register(Mips::GP),
|
|
MF.getInfo<MipsFunctionInfo>()->getGlobalBaseRegForGlobalISel(MF));
|
|
MIB.addDef(Mips::GP, RegState::Implicit);
|
|
}
|
|
MIRBuilder.insertInstr(MIB);
|
|
if (MIB->getOpcode() == Mips::JALRPseudo) {
|
|
const MipsSubtarget &STI =
|
|
static_cast<const MipsSubtarget &>(MIRBuilder.getMF().getSubtarget());
|
|
MIB.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
|
|
*STI.getRegBankInfo());
|
|
}
|
|
|
|
if (!Info.OrigRet.Ty->isVoidTy()) {
|
|
ArgInfos.clear();
|
|
|
|
CallLowering::splitToValueTypes(Info.OrigRet, ArgInfos, DL,
|
|
F.getCallingConv());
|
|
|
|
const std::string FuncName = F.getName().str();
|
|
SmallVector<ISD::InputArg, 8> Ins;
|
|
SmallVector<CCValAssign, 8> ArgLocs;
|
|
MipsIncomingValueAssigner Assigner(TLI.CCAssignFnForReturn(),
|
|
FuncName.c_str(),
|
|
/*IsReturn*/ true);
|
|
CallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), MIB);
|
|
|
|
MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
|
|
F.getContext());
|
|
|
|
if (!determineAssignments(Assigner, ArgInfos, CCInfo))
|
|
return false;
|
|
|
|
if (!handleAssignments(RetHandler, ArgInfos, CCInfo, ArgLocs, MIRBuilder))
|
|
return false;
|
|
}
|
|
|
|
MIRBuilder.buildInstr(Mips::ADJCALLSTACKUP).addImm(NextStackOffset).addImm(0);
|
|
|
|
return true;
|
|
}
|