-/// 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 or i128 which was originally a
-/// fp128.
-static bool originalTypeIsF128(const Type *Ty, const SDNode *CallNode) {
- if (Ty->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::SpecialCallingConvType
- MipsTargetLowering::getSpecialCallingConv(SDValue Callee) const {
- MipsCC::SpecialCallingConvType SpecialCallingConv =
- MipsCC::NoSpecialCallingConv;
- if (Subtarget.inMips16HardFloat()) {
- if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
- llvm::StringRef Sym = G->getGlobal()->getName();
- Function *F = G->getGlobal()->getParent()->getFunction(Sym);
- if (F && F->hasFnAttribute("__Mips16RetHelper")) {
- SpecialCallingConv = MipsCC::Mips16RetHelperConv;
- }
- }
- }
- return SpecialCallingConv;
-}
-
-MipsTargetLowering::MipsCC::MipsCC(
- CallingConv::ID CC, bool IsO32_, bool IsFP64_, CCState &Info,
- MipsCC::SpecialCallingConvType SpecialCallingConv_)
- : CCInfo(Info), CallConv(CC), IsO32(IsO32_), IsFP64(IsFP64_),
- SpecialCallingConv(SpecialCallingConv_){
- // Pre-allocate reserved argument area.
- CCInfo.AllocateStack(reservedArgArea(), 1);
-}
-
-
-void MipsTargetLowering::MipsCC::
-analyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Args,
- bool IsVarArg, bool IsSoftFloat, const SDNode *CallNode,
- std::vector<ArgListEntry> &FuncArgs) {
- assert((CallConv != CallingConv::Fast || !IsVarArg) &&
- "CallingConv::Fast shouldn't be used for vararg functions.");
-
- unsigned NumOpnds = Args.size();
- llvm::CCAssignFn *FixedFn = fixedArgFn(), *VarFn = varArgFn();
-
- for (unsigned I = 0; I != NumOpnds; ++I) {
- MVT ArgVT = Args[I].VT;
- ISD::ArgFlagsTy ArgFlags = Args[I].Flags;
- bool R;
-
- if (ArgFlags.isByVal()) {
- handleByValArg(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags);
- continue;
- }
-
- if (IsVarArg && !Args[I].IsFixed)
- R = VarFn(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo);
- else {
- MVT RegVT = getRegVT(ArgVT, FuncArgs[Args[I].OrigArgIndex].Ty, CallNode,
- IsSoftFloat);
- R = FixedFn(I, ArgVT, RegVT, CCValAssign::Full, ArgFlags, CCInfo);
- }
-
- if (R) {
-#ifndef NDEBUG
- dbgs() << "Call operand #" << I << " has unhandled type "
- << EVT(ArgVT).getEVTString();
-#endif
- llvm_unreachable(nullptr);
- }
- }
-}
-
-void MipsTargetLowering::MipsCC::
-analyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Args,
- bool IsSoftFloat, Function::const_arg_iterator FuncArg) {
- unsigned NumArgs = Args.size();
- llvm::CCAssignFn *FixedFn = fixedArgFn();
- unsigned CurArgIdx = 0;
-
- for (unsigned I = 0; I != NumArgs; ++I) {
- MVT ArgVT = Args[I].VT;
- ISD::ArgFlagsTy ArgFlags = Args[I].Flags;
- std::advance(FuncArg, Args[I].OrigArgIndex - CurArgIdx);
- CurArgIdx = Args[I].OrigArgIndex;
-
- if (ArgFlags.isByVal()) {
- handleByValArg(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags);
- continue;
- }
-
- MVT RegVT = getRegVT(ArgVT, FuncArg->getType(), nullptr, IsSoftFloat);
-
- if (!FixedFn(I, ArgVT, RegVT, CCValAssign::Full, ArgFlags, CCInfo))
- continue;
-
-#ifndef NDEBUG
- dbgs() << "Formal Arg #" << I << " has unhandled type "
- << EVT(ArgVT).getEVTString();
-#endif
- llvm_unreachable(nullptr);
- }
-}
-
-template<typename Ty>
-void MipsTargetLowering::MipsCC::
-analyzeReturn(const SmallVectorImpl<Ty> &RetVals, bool IsSoftFloat,
- const SDNode *CallNode, const Type *RetTy) const {
- CCAssignFn *Fn;
-
- if (IsSoftFloat && originalTypeIsF128(RetTy, CallNode))
- Fn = RetCC_F128Soft;
- else
- Fn = RetCC_Mips;
-
- for (unsigned I = 0, E = RetVals.size(); I < E; ++I) {
- MVT VT = RetVals[I].VT;
- ISD::ArgFlagsTy Flags = RetVals[I].Flags;
- MVT RegVT = this->getRegVT(VT, RetTy, CallNode, IsSoftFloat);
-
- if (Fn(I, VT, RegVT, CCValAssign::Full, Flags, this->CCInfo)) {
-#ifndef NDEBUG
- dbgs() << "Call result #" << I << " has unhandled type "
- << EVT(VT).getEVTString() << '\n';
-#endif
- llvm_unreachable(nullptr);
- }
- }
-}
-
-void MipsTargetLowering::MipsCC::
-analyzeCallResult(const SmallVectorImpl<ISD::InputArg> &Ins, bool IsSoftFloat,
- const SDNode *CallNode, const Type *RetTy) const {
- analyzeReturn(Ins, IsSoftFloat, CallNode, RetTy);
-}
-
-void MipsTargetLowering::MipsCC::
-analyzeReturn(const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsSoftFloat,
- const Type *RetTy) const {
- analyzeReturn(Outs, IsSoftFloat, nullptr, RetTy);
-}
-
-void MipsTargetLowering::MipsCC::handleByValArg(unsigned ValNo, MVT ValVT,
- MVT LocVT,
- CCValAssign::LocInfo LocInfo,
- ISD::ArgFlagsTy ArgFlags) {
- assert(ArgFlags.getByValSize() && "Byval argument's size shouldn't be 0.");
-
- struct ByValArgInfo ByVal;
- unsigned RegSize = regSize();
- unsigned ByValSize = RoundUpToAlignment(ArgFlags.getByValSize(), RegSize);
- unsigned Align = std::min(std::max(ArgFlags.getByValAlign(), RegSize),
- RegSize * 2);
-
- if (useRegsForByval())
- allocateRegs(ByVal, ByValSize, Align);
-
- // Allocate space on caller's stack.
- ByVal.Address = CCInfo.AllocateStack(ByValSize - RegSize * ByVal.NumRegs,
- Align);
- CCInfo.addLoc(CCValAssign::getMem(ValNo, ValVT, ByVal.Address, LocVT,
- LocInfo));
- ByValArgs.push_back(ByVal);
-}
-
-unsigned MipsTargetLowering::MipsCC::numIntArgRegs() const {
- return IsO32 ? array_lengthof(O32IntRegs) : array_lengthof(Mips64IntRegs);
-}
-
-unsigned MipsTargetLowering::MipsCC::reservedArgArea() const {
- return (IsO32 && (CallConv != CallingConv::Fast)) ? 16 : 0;
-}
-
-const MCPhysReg *MipsTargetLowering::MipsCC::intArgRegs() const {
- return IsO32 ? O32IntRegs : Mips64IntRegs;
-}
-
-llvm::CCAssignFn *MipsTargetLowering::MipsCC::fixedArgFn() const {
- if (CallConv == CallingConv::Fast)
- return CC_Mips_FastCC;
-
- if (SpecialCallingConv == Mips16RetHelperConv)
- return CC_Mips16RetHelper;
- return IsO32 ? (IsFP64 ? CC_MipsO32_FP64 : CC_MipsO32_FP32) : CC_MipsN;
-}
-
-llvm::CCAssignFn *MipsTargetLowering::MipsCC::varArgFn() const {
- return IsO32 ? (IsFP64 ? CC_MipsO32_FP64 : CC_MipsO32_FP32) : CC_MipsN_VarArg;
-}
-
-const MCPhysReg *MipsTargetLowering::MipsCC::shadowRegs() const {
- return IsO32 ? O32IntRegs : Mips64DPRegs;
-}
-
-void MipsTargetLowering::MipsCC::allocateRegs(ByValArgInfo &ByVal,
- unsigned ByValSize,
- unsigned Align) {
- unsigned RegSize = regSize(), NumIntArgRegs = numIntArgRegs();
- const MCPhysReg *IntArgRegs = intArgRegs(), *ShadowRegs = shadowRegs();
- assert(!(ByValSize % RegSize) && !(Align % RegSize) &&
- "Byval argument's size and alignment should be a multiple of"
- "RegSize.");
-
- ByVal.FirstIdx = CCInfo.getFirstUnallocated(IntArgRegs, NumIntArgRegs);
-
- // If Align > RegSize, the first arg register must be even.
- if ((Align > RegSize) && (ByVal.FirstIdx % 2)) {
- CCInfo.AllocateReg(IntArgRegs[ByVal.FirstIdx], ShadowRegs[ByVal.FirstIdx]);
- ++ByVal.FirstIdx;
- }
-
- // Mark the registers allocated.
- for (unsigned I = ByVal.FirstIdx; ByValSize && (I < NumIntArgRegs);
- ByValSize -= RegSize, ++I, ++ByVal.NumRegs)
- CCInfo.AllocateReg(IntArgRegs[I], ShadowRegs[I]);
-}
-
-MVT MipsTargetLowering::MipsCC::getRegVT(MVT VT, const Type *OrigTy,
- const SDNode *CallNode,
- bool IsSoftFloat) const {
- if (IsSoftFloat || IsO32)
- return VT;
-
- // Check if the original type was fp128.
- if (originalTypeIsF128(OrigTy, CallNode)) {
- assert(VT == MVT::i64);
- return MVT::f64;
- }
-
- return VT;