#include "MipsISelLowering.h"
#include "InstPrinter/MipsInstPrinter.h"
#include "MCTargetDesc/MipsBaseInfo.h"
+#include "MipsCCState.h"
#include "MipsMachineFunction.h"
#include "MipsSubtarget.h"
#include "MipsTargetMachine.h"
cl::desc("Allow mips-fast-isel to be used"),
cl::init(false));
-static const MCPhysReg O32IntRegs[4] = {
- Mips::A0, Mips::A1, Mips::A2, Mips::A3
-};
-
-static const MCPhysReg Mips64IntRegs[8] = {
- Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64,
- Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64
-};
-
static const MCPhysReg Mips64DPRegs[8] = {
Mips::D12_64, Mips::D13_64, Mips::D14_64, Mips::D15_64,
Mips::D16_64, Mips::D17_64, Mips::D18_64, Mips::D19_64
};
-static bool originalTypeIsF128(const Type *Ty, const SDNode *CallNode);
-
-namespace {
-class MipsCCState : public CCState {
-public:
- enum SpecialCallingConvType { Mips16RetHelperConv, NoSpecialCallingConv };
-
- /// Determine the SpecialCallingConvType for the given callee
- static SpecialCallingConvType
- getSpecialCallingConvForCallee(const SDNode *Callee,
- const MipsSubtarget &Subtarget) {
- SpecialCallingConvType SpecialCallingConv = NoSpecialCallingConv;
- if (Subtarget.inMips16HardFloat()) {
- if (const GlobalAddressSDNode *G =
- dyn_cast<const GlobalAddressSDNode>(Callee)) {
- llvm::StringRef Sym = G->getGlobal()->getName();
- Function *F = G->getGlobal()->getParent()->getFunction(Sym);
- if (F && F->hasFnAttribute("__Mips16RetHelper")) {
- SpecialCallingConv = Mips16RetHelperConv;
- }
- }
- }
- return SpecialCallingConv;
- }
-
-private:
- /// Identify lowered values that originated from f128 arguments and record
- /// this for use by RetCC_MipsN.
- void
- PreAnalyzeCallResultForF128(const SmallVectorImpl<ISD::InputArg> &Ins,
- const TargetLowering::CallLoweringInfo &CLI) {
- for (unsigned i = 0; i < Ins.size(); ++i)
- OriginalArgWasF128.push_back(
- originalTypeIsF128(CLI.RetTy, CLI.Callee.getNode()));
- }
-
- /// Identify lowered values that originated from f128 arguments and record
- /// this for use by RetCC_MipsN.
- void PreAnalyzeReturnForF128(const SmallVectorImpl<ISD::OutputArg> &Outs) {
- const MachineFunction &MF = getMachineFunction();
- for (unsigned i = 0; i < Outs.size(); ++i)
- OriginalArgWasF128.push_back(
- originalTypeIsF128(MF.getFunction()->getReturnType(), nullptr));
- }
-
- /// Identify lowered values that originated from f128 arguments and record
- /// this.
- void PreAnalyzeCallOperands(
- const SmallVectorImpl<ISD::OutputArg> &Outs,
- std::vector<TargetLowering::ArgListEntry> &FuncArgs,
- const SDNode *CallNode) {
- for (unsigned i = 0; i < Outs.size(); ++i) {
- OriginalArgWasF128.push_back(
- originalTypeIsF128(FuncArgs[Outs[i].OrigArgIndex].Ty, CallNode));
- CallOperandIsFixed.push_back(Outs[i].IsFixed);
- }
- }
-
- /// Identify lowered values that originated from f128 arguments and record
- /// this.
- void
- PreAnalyzeFormalArgumentsForF128(const SmallVectorImpl<ISD::InputArg> &Ins) {
- const MachineFunction &MF = getMachineFunction();
- for (unsigned i = 0; i < Ins.size(); ++i) {
- Function::const_arg_iterator FuncArg = MF.getFunction()->arg_begin();
-
- // SRet arguments cannot originate from f128 or {f128} returns so we just
- // push false. We have to handle this specially since SRet arguments
- // aren't mapped to an original argument.
- if (Ins[i].Flags.isSRet()) {
- OriginalArgWasF128.push_back(false);
- continue;
- }
-
- assert(Ins[i].OrigArgIndex < MF.getFunction()->arg_size());
- std::advance(FuncArg, Ins[i].OrigArgIndex);
- OriginalArgWasF128.push_back(
- originalTypeIsF128(FuncArg->getType(), nullptr));
- }
- }
-
- /// Records whether the value has been lowered from an f128.
- SmallVector<bool, 4> OriginalArgWasF128;
-
- /// Records whether the value was a fixed argument.
- /// See ISD::OutputArg::IsFixed,
- SmallVector<bool, 4> CallOperandIsFixed;
-
- // Used to handle MIPS16-specific calling convention tweaks.
- // FIXME: This should probably be a fully fledged calling convention.
- SpecialCallingConvType SpecialCallingConv;
-
-public:
-
- MipsCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF,
- SmallVectorImpl<CCValAssign> &locs, LLVMContext &C,
- SpecialCallingConvType SpecialCC = NoSpecialCallingConv)
- : CCState(CC, isVarArg, MF, locs, C), SpecialCallingConv(SpecialCC) {}
-
- void
- AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs,
- CCAssignFn Fn,
- std::vector<TargetLowering::ArgListEntry> &FuncArgs,
- const SDNode *CallNode) {
- PreAnalyzeCallOperands(Outs, FuncArgs, CallNode);
- CCState::AnalyzeCallOperands(Outs, Fn);
- OriginalArgWasF128.clear();
- CallOperandIsFixed.clear();
- }
-
- // The AnalyzeCallOperands in the base class is not usable since we must
- // provide a means of accessing ArgListEntry::IsFixed. Delete them from this
- // class. This doesn't stop them being used via the base class though.
- void AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs,
- CCAssignFn Fn) = delete;
- void AnalyzeCallOperands(const SmallVectorImpl<MVT> &Outs,
- SmallVectorImpl<ISD::ArgFlagsTy> &Flags,
- CCAssignFn Fn) = delete;
-
- void AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins,
- CCAssignFn Fn) {
- PreAnalyzeFormalArgumentsForF128(Ins);
- CCState::AnalyzeFormalArguments(Ins, Fn);
- OriginalArgWasF128.clear();
- }
-
- void AnalyzeCallResult(const SmallVectorImpl<ISD::InputArg> &Ins,
- CCAssignFn Fn,
- const TargetLowering::CallLoweringInfo &CLI) {
- PreAnalyzeCallResultForF128(Ins, CLI);
- CCState::AnalyzeCallResult(Ins, Fn);
- OriginalArgWasF128.clear();
- }
-
- void AnalyzeReturn(const SmallVectorImpl<ISD::OutputArg> &Outs,
- CCAssignFn Fn) {
- PreAnalyzeReturnForF128(Outs);
- CCState::AnalyzeReturn(Outs, Fn);
- OriginalArgWasF128.clear();
- }
-
- bool CheckReturn(const SmallVectorImpl<ISD::OutputArg> &ArgsFlags,
- CCAssignFn Fn) {
- PreAnalyzeReturnForF128(ArgsFlags);
- bool Return = CCState::CheckReturn(ArgsFlags, Fn);
- OriginalArgWasF128.clear();
- return Return;
- }
-
- bool WasOriginalArgF128(unsigned ValNo) { return OriginalArgWasF128[ValNo]; }
- bool IsCallOperandFixed(unsigned ValNo) { return CallOperandIsFixed[ValNo]; }
- SpecialCallingConvType getSpecialCallingConv() { return SpecialCallingConv; }
-};
-}
-
// If I is a shifted mask, set the size (Size) and the first bit of the
// mask (Pos), and return true.
// For example, if I is 0x003ff800, (Pos, Size) = (11, 11).
MipsCCState CCInfo(
CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, *DAG.getContext(),
MipsCCState::getSpecialCallingConvForCallee(Callee.getNode(), Subtarget));
- MipsCC MipsCCInfo(CallConv, Subtarget, CCInfo);
+
+ // Allocate the reserved argument area. It seems strange to do this from the
+ // caller side but removing it breaks the frame size calculation.
+ const MipsABIInfo &ABI = Subtarget.getABI();
+ CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(CallConv), 1);
CCInfo.AnalyzeCallOperands(Outs, CC_Mips, CLI.getArgs(), Callee.getNode());
assert(!IsTailCall &&
"Do not tail-call optimize if there is a byval argument.");
passByValArg(Chain, DL, RegsToPass, MemOpChains, StackPtr, MFI, DAG, Arg,
- MipsCCInfo, FirstByValReg, LastByValReg, Flags,
- Subtarget.isLittle(), VA);
+ FirstByValReg, LastByValReg, Flags, Subtarget.isLittle(),
+ VA);
CCInfo.nextInRegsParam();
continue;
}
SmallVector<CCValAssign, 16> ArgLocs;
MipsCCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext());
- MipsCC MipsCCInfo(CallConv, Subtarget, CCInfo);
+ const MipsABIInfo &ABI = Subtarget.getABI();
+ CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(CallConv), 1);
Function::const_arg_iterator FuncArg =
DAG.getMachineFunction().getFunction()->arg_begin();
"ByVal args of size 0 should have been ignored by front-end.");
assert(ByValIdx < CCInfo.getInRegsParamsCount());
copyByValRegs(Chain, DL, OutChains, DAG, Flags, InVals, &*FuncArg,
- MipsCCInfo, FirstByValReg, LastByValReg, VA);
+ FirstByValReg, LastByValReg, VA, CCInfo);
CCInfo.nextInRegsParam();
continue;
}
}
if (IsVarArg)
- writeVarArgRegs(OutChains, MipsCCInfo, Chain, DL, DAG, CCInfo);
+ writeVarArgRegs(OutChains, Chain, DL, DAG, CCInfo);
// All stores are grouped in one node to allow the matching between
// the size of Ins and InVals. This only happens when on varg functions
return TargetLowering::getJumpTableEncoding();
}
-/// This function returns true if CallSym is a long double emulation routine.
-static bool isF128SoftLibCall(const char *CallSym) {
- const char *const LibCalls[] =
- {"__addtf3", "__divtf3", "__eqtf2", "__extenddftf2", "__extendsftf2",
- "__fixtfdi", "__fixtfsi", "__fixtfti", "__fixunstfdi", "__fixunstfsi",
- "__fixunstfti", "__floatditf", "__floatsitf", "__floattitf",
- "__floatunditf", "__floatunsitf", "__floatuntitf", "__getf2", "__gttf2",
- "__letf2", "__lttf2", "__multf3", "__netf2", "__powitf2", "__subtf3",
- "__trunctfdf2", "__trunctfsf2", "__unordtf2",
- "ceill", "copysignl", "cosl", "exp2l", "expl", "floorl", "fmal", "fmodl",
- "log10l", "log2l", "logl", "nearbyintl", "powl", "rintl", "sinl", "sqrtl",
- "truncl"};
-
- const char *const *End = LibCalls + array_lengthof(LibCalls);
-
- // Check that LibCalls is sorted alphabetically.
- MipsTargetLowering::LTStr Comp;
-
-#ifndef NDEBUG
- for (const char *const *I = LibCalls; I < End - 1; ++I)
- assert(Comp(*I, *(I + 1)));
-#endif
-
- return std::binary_search(LibCalls, End, CallSym, Comp);
-}
-
-/// This function returns true if Ty is fp128, {f128} or i128 which was
-/// originally a fp128.
-static bool originalTypeIsF128(const Type *Ty, const SDNode *CallNode) {
- if (Ty->isFP128Ty())
- return true;
-
- if (Ty->isStructTy() && Ty->getStructNumElements() == 1 &&
- Ty->getStructElementType(0)->isFP128Ty())
- return true;
-
- const ExternalSymbolSDNode *ES =
- dyn_cast_or_null<const ExternalSymbolSDNode>(CallNode);
-
- // If the Ty is i128 and the function being called is a long double emulation
- // routine, then the original type is f128.
- return (ES && Ty->isIntegerTy(128) && isF128SoftLibCall(ES->getSymbol()));
-}
-
-MipsTargetLowering::MipsCC::MipsCC(CallingConv::ID CC,
- const MipsSubtarget &Subtarget_,
- CCState &Info)
- : CallConv(CC), Subtarget(Subtarget_) {
- // Pre-allocate reserved argument area.
- Info.AllocateStack(reservedArgArea(), 1);
-}
-
-unsigned MipsTargetLowering::MipsCC::reservedArgArea() const {
- return (Subtarget.isABI_O32() && (CallConv != CallingConv::Fast)) ? 16 : 0;
-}
-
-const ArrayRef<MCPhysReg> MipsTargetLowering::MipsCC::intArgRegs() const {
- if (Subtarget.isABI_O32())
- return makeArrayRef(O32IntRegs);
- return makeArrayRef(Mips64IntRegs);
-}
-
void MipsTargetLowering::copyByValRegs(
SDValue Chain, SDLoc DL, std::vector<SDValue> &OutChains, SelectionDAG &DAG,
const ISD::ArgFlagsTy &Flags, SmallVectorImpl<SDValue> &InVals,
- const Argument *FuncArg, const MipsCC &CC, unsigned FirstReg,
- unsigned LastReg, const CCValAssign &VA) const {
+ const Argument *FuncArg, unsigned FirstReg, unsigned LastReg,
+ const CCValAssign &VA, MipsCCState &State) const {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
unsigned GPRSizeInBytes = Subtarget.getGPRSizeInBytes();
unsigned RegAreaSize = NumRegs * GPRSizeInBytes;
unsigned FrameObjSize = std::max(Flags.getByValSize(), RegAreaSize);
int FrameObjOffset;
+ const MipsABIInfo &ABI = Subtarget.getABI();
+ ArrayRef<MCPhysReg> ByValArgRegs = ABI.GetByValArgRegs();
if (RegAreaSize)
FrameObjOffset =
- (int)CC.reservedArgArea() -
- (int)((CC.intArgRegs().size() - FirstReg) * GPRSizeInBytes);
+ (int)ABI.GetCalleeAllocdArgSizeInBytes(State.getCallingConv()) -
+ (int)((ByValArgRegs.size() - FirstReg) * GPRSizeInBytes);
else
FrameObjOffset = VA.getLocMemOffset();
const TargetRegisterClass *RC = getRegClassFor(RegTy);
for (unsigned I = 0; I < NumRegs; ++I) {
- unsigned ArgReg = CC.intArgRegs()[FirstReg + I];
+ unsigned ArgReg = ByValArgRegs[FirstReg + I];
unsigned VReg = addLiveIn(MF, ArgReg, RC);
unsigned Offset = I * GPRSizeInBytes;
SDValue StorePtr = DAG.getNode(ISD::ADD, DL, PtrTy, FIN,
SDValue Chain, SDLoc DL,
std::deque<std::pair<unsigned, SDValue>> &RegsToPass,
SmallVectorImpl<SDValue> &MemOpChains, SDValue StackPtr,
- MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, const MipsCC &CC,
- unsigned FirstReg, unsigned LastReg, const ISD::ArgFlagsTy &Flags,
- bool isLittle, const CCValAssign &VA) const {
+ MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, unsigned FirstReg,
+ unsigned LastReg, const ISD::ArgFlagsTy &Flags, bool isLittle,
+ const CCValAssign &VA) const {
unsigned ByValSizeInBytes = Flags.getByValSize();
unsigned OffsetInBytes = 0; // From beginning of struct
unsigned RegSizeInBytes = Subtarget.getGPRSizeInBytes();
unsigned NumRegs = LastReg - FirstReg;
if (NumRegs) {
- const ArrayRef<MCPhysReg> ArgRegs = CC.intArgRegs();
+ const ArrayRef<MCPhysReg> ArgRegs = Subtarget.getABI().GetByValArgRegs();
bool LeftoverBytes = (NumRegs * RegSizeInBytes > ByValSizeInBytes);
unsigned I = 0;
}
void MipsTargetLowering::writeVarArgRegs(std::vector<SDValue> &OutChains,
- const MipsCC &CC, SDValue Chain,
- SDLoc DL, SelectionDAG &DAG,
+ SDValue Chain, SDLoc DL,
+ SelectionDAG &DAG,
CCState &State) const {
- const ArrayRef<MCPhysReg> ArgRegs = CC.intArgRegs();
+ const ArrayRef<MCPhysReg> ArgRegs = Subtarget.getABI().GetVarArgRegs();
unsigned Idx = State.getFirstUnallocated(ArgRegs.data(), ArgRegs.size());
unsigned RegSizeInBytes = Subtarget.getGPRSizeInBytes();
MVT RegTy = MVT::getIntegerVT(RegSizeInBytes * 8);
if (ArgRegs.size() == Idx)
VaArgOffset =
RoundUpToAlignment(State.getNextStackOffset(), RegSizeInBytes);
- else
- VaArgOffset = (int)CC.reservedArgArea() -
- (int)(RegSizeInBytes * (ArgRegs.size() - Idx));
+ else {
+ const MipsABIInfo &ABI = Subtarget.getABI();
+ VaArgOffset =
+ (int)ABI.GetCalleeAllocdArgSizeInBytes(State.getCallingConv()) -
+ (int)(RegSizeInBytes * (ArgRegs.size() - Idx));
+ }
// Record the frame index of the first variable argument
// which is a value necessary to VASTART.