Index: lib/Target/Mips/MipsCallingConv.td =================================================================== --- lib/Target/Mips/MipsCallingConv.td +++ lib/Target/Mips/MipsCallingConv.td @@ -20,6 +20,27 @@ // The inverse of CCIfSubtarget class CCIfNotSubtarget : CCIfSubtarget; +// For soft-float, f128 values are returned in A0_64 rather than V1_64. +def RetCC_F128SoftFloat : CallingConv<[ + CCAssignToReg<[V0_64, A0_64]> +]>; + +// For hard-float, f128 values are returned as a pair of f64's rather than a +// pair of i64's. +def RetCC_F128HardFloat : CallingConv<[ + CCBitConvertToType, + CCAssignToReg<[D0_64, D2_64]> +]>; + +// Handle F128 specially since we can't identify the original type during the +// tablegen-erated code. +def RetCC_F128 : CallingConv<[ + CCIfSubtarget<"abiUsesSoftFloat()", + CCIfType<[i64], CCDelegateTo>>, + CCIfNotSubtarget<"abiUsesSoftFloat()", + CCIfType<[i64], CCDelegateTo>> +]>; + //===----------------------------------------------------------------------===// // Mips O32 Calling Convention //===----------------------------------------------------------------------===// @@ -92,6 +113,20 @@ ]>; def RetCC_MipsN : CallingConv<[ + // f128 needs to be handled similarly to f32 and f64. However, f128 is not + // legal and is lowered to i128 which is further lowered to a pair of i64's. + // This presents us with a problem for the calling convention since hard-float + // still needs to pass them in FPU registers, and soft-float needs to use $v0, + // and $a0 instead of the usual $v0, and $v1. We therefore resort to a + // pre-analyze (see PreAnalyzeReturnForF128()) step to pass information on + // whether the result was originally an f128 into the tablegen-erated code. + // + // f128 should only occur for the N64 ABI where long double is 128-bit. On + // N32, long double is equivalent to double. + CCIfType<[i64], + CCIf<"static_cast(&State)->WasOriginalArgF128(ValNo)", + CCDelegateTo>>, + // Aggregate returns are positioned at the lowest address in the slot for // both little and big-endian targets. When passing in registers, this // requires that big-endian targets shift the value into the upper bits. @@ -113,27 +148,6 @@ CCIfType<[f64], CCAssignToReg<[D0_64, D2_64]>> ]>; -// For soft-float, f128 values are returned in A0_64 rather than V1_64. -def RetCC_F128SoftFloat : CallingConv<[ - CCAssignToReg<[V0_64, A0_64]> -]>; - -// For hard-float, f128 values are returned as a pair of f64's rather than a -// pair of i64's. -def RetCC_F128HardFloat : CallingConv<[ - CCBitConvertToType, - CCAssignToReg<[D0_64, D2_64]> -]>; - -// Handle F128 specially since we can't identify the original type during the -// tablegen-erated code. -def RetCC_F128 : CallingConv<[ - CCIfSubtarget<"abiUsesSoftFloat()", - CCIfType<[i64], CCDelegateTo>>, - CCIfNotSubtarget<"abiUsesSoftFloat()", - CCIfType<[i64], CCDelegateTo>> -]>; - //===----------------------------------------------------------------------===// // Mips EABI Calling Convention //===----------------------------------------------------------------------===// Index: lib/Target/Mips/MipsISelLowering.h =================================================================== --- lib/Target/Mips/MipsISelLowering.h +++ lib/Target/Mips/MipsISelLowering.h @@ -449,13 +449,13 @@ unsigned Flag) const; MipsCC::SpecialCallingConvType getSpecialCallingConv(SDValue Callee) const; + // Lower Operand helpers SDValue LowerCallResult(SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg, - const SmallVectorImpl &Ins, - SDLoc dl, SelectionDAG &DAG, - SmallVectorImpl &InVals, - const SDNode *CallNode, const Type *RetTy) const; + const SmallVectorImpl &Ins, SDLoc dl, + SelectionDAG &DAG, SmallVectorImpl &InVals, + TargetLowering::CallLoweringInfo &CLI) const; // Lower Operand specifics SDValue lowerBR_JT(SDValue Op, SelectionDAG &DAG) const; Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -71,6 +71,66 @@ 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 { +private: + /// Identify lowered values that originated from f128 arguments and record + /// this for use by RetCC_MipsN. + void + PreAnalyzeCallResultForF128(const SmallVectorImpl &Ins, + const TargetLowering::CallLoweringInfo &CLI) { + const MachineFunction &MF = getMachineFunction(); + 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 &Outs) { + const MachineFunction &MF = getMachineFunction(); + for (unsigned i = 0; i < Outs.size(); ++i) + OriginalArgWasF128.push_back( + originalTypeIsF128(MF.getFunction()->getReturnType(), nullptr)); + } + + /// Records whether the value has been lowered from an f128. + SmallVector OriginalArgWasF128; + +public: + MipsCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF, + SmallVectorImpl &locs, LLVMContext &C) + : CCState(CC, isVarArg, MF, locs, C) {} + + void AnalyzeCallResult(const SmallVectorImpl &Ins, + CCAssignFn Fn, + const TargetLowering::CallLoweringInfo &CLI) { + PreAnalyzeCallResultForF128(Ins, CLI); + CCState::AnalyzeCallResult(Ins, Fn); + OriginalArgWasF128.clear(); + } + + void AnalyzeReturn(const SmallVectorImpl &Outs, + CCAssignFn Fn) { + PreAnalyzeReturnForF128(Outs); + CCState::AnalyzeReturn(Outs, Fn); + OriginalArgWasF128.clear(); + } + + bool CheckReturn(const SmallVectorImpl &ArgsFlags, + CCAssignFn Fn) { + PreAnalyzeReturnForF128(ArgsFlags); + bool Return = CCState::CheckReturn(ArgsFlags, Fn); + OriginalArgWasF128.clear(); + return Return; + } + + bool WasOriginalArgF128(unsigned ValNo) { return OriginalArgWasF128[ValNo]; } +}; +} + // 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). @@ -2373,8 +2433,6 @@ return CC_MipsO32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State, F64Regs); } -static bool originalTypeIsF128(const Type *Ty, const SDNode *CallNode); - #include "MipsGenCallingConv.inc" //===----------------------------------------------------------------------===// @@ -2670,29 +2728,22 @@ // Handle result values, copying them out of physregs into vregs that we // return. - return LowerCallResult(Chain, InFlag, CallConv, IsVarArg, - Ins, DL, DAG, InVals, CLI.Callee.getNode(), CLI.RetTy); + return LowerCallResult(Chain, InFlag, CallConv, IsVarArg, Ins, DL, DAG, + InVals, CLI); } /// LowerCallResult - Lower the result values of a call into the /// appropriate copies out of appropriate physical registers. -SDValue -MipsTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, - CallingConv::ID CallConv, bool IsVarArg, - const SmallVectorImpl &Ins, - SDLoc DL, SelectionDAG &DAG, - SmallVectorImpl &InVals, - const SDNode *CallNode, - const Type *RetTy) const { +SDValue MipsTargetLowering::LowerCallResult( + SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals, + TargetLowering::CallLoweringInfo &CLI) const { // Assign locations to each value returned by this call. SmallVector RVLocs; - CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, - *DAG.getContext()); - - if (originalTypeIsF128(RetTy, CallNode)) - CCInfo.AnalyzeCallResult(Ins, RetCC_F128); - else - CCInfo.AnalyzeCallResult(Ins, RetCC_Mips); + MipsCCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, + *DAG.getContext()); + CCInfo.AnalyzeCallResult(Ins, RetCC_Mips, CLI); // Copy all of the result registers out of their specified physreg. for (unsigned i = 0; i != RVLocs.size(); ++i) { @@ -2905,7 +2956,7 @@ const SmallVectorImpl &Outs, LLVMContext &Context) const { SmallVector RVLocs; - CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); + MipsCCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); return CCInfo.CheckReturn(Outs, RetCC_Mips); } @@ -2921,14 +2972,11 @@ MachineFunction &MF = DAG.getMachineFunction(); // CCState - Info about the registers and stack slot. - CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); + MipsCCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); MipsCC MipsCCInfo(CallConv, Subtarget, CCInfo); // Analyze return values. - if (originalTypeIsF128(MF.getFunction()->getReturnType(), nullptr)) - CCInfo.AnalyzeReturn(Outs, RetCC_F128); - else - CCInfo.AnalyzeReturn(Outs, RetCC_Mips); + CCInfo.AnalyzeReturn(Outs, RetCC_Mips); SDValue Flag; SmallVector RetOps(1, Chain);