Skip to content

Commit f2b9290

Browse files
committed
[MIPS] Implement llvm.fminimum and llvm.fmaximum
The implementation used various checks against signed zeroes and NaNs to ensure the correct value is returned.
1 parent c229f76 commit f2b9290

File tree

3 files changed

+476
-0
lines changed

3 files changed

+476
-0
lines changed

llvm/lib/Target/Mips/MipsISelLowering.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,13 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
457457
setOperationAction(ISD::FREM, MVT::f32, Expand);
458458
setOperationAction(ISD::FREM, MVT::f64, Expand);
459459

460+
// Lower ISD::FMINIMUM and ISD::FMAXIMUM for hard FP targets.
461+
if (!Subtarget.useSoftFloat()) {
462+
setOperationAction(ISD::FMINIMUM, MVT::f32, Custom);
463+
setOperationAction(ISD::FMAXIMUM, MVT::f32, Custom);
464+
setOperationAction(ISD::FMINIMUM, MVT::f64, Custom);
465+
setOperationAction(ISD::FMAXIMUM, MVT::f64, Custom);
466+
}
460467
// Lower f16 conversion operations into library calls
461468
setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
462469
setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
@@ -1267,6 +1274,9 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
12671274
case ISD::STORE: return lowerSTORE(Op, DAG);
12681275
case ISD::EH_DWARF_CFA: return lowerEH_DWARF_CFA(Op, DAG);
12691276
case ISD::FP_TO_SINT: return lowerFP_TO_SINT(Op, DAG);
1277+
case ISD::FMINIMUM:
1278+
case ISD::FMAXIMUM:
1279+
return lowerFMINIMUM_FMAXIMUM(Op, DAG);
12701280
}
12711281
return SDValue();
12721282
}
@@ -2525,6 +2535,94 @@ SDValue MipsTargetLowering::lowerFABS(SDValue Op, SelectionDAG &DAG) const {
25252535
return lowerFABS32(Op, DAG, Subtarget.hasExtractInsert());
25262536
}
25272537

2538+
SDValue MipsTargetLowering::lowerFMINIMUM_FMAXIMUM(SDValue Op,
2539+
SelectionDAG &DAG) const {
2540+
// Get information about X and Y:
2541+
// VT of the operand, the operand itself and its length,
2542+
// The possibility of X or Y being a NaN.
2543+
EVT VT = Op.getValueType();
2544+
assert(
2545+
(VT == MVT::f32 || VT == MVT::f64) &&
2546+
"Unsupported float point type or operands are not floating point values");
2547+
// Used to compare an operand to zero.
2548+
EVT IVT = VT.changeTypeToInteger();
2549+
// Whether it is fminimum or fmaximum.
2550+
ISD::NodeType CmpOp = (ISD::NodeType)Op->getOpcode();
2551+
bool IsMaxOp = (CmpOp == ISD::FMAXIMUM);
2552+
SDValue X = Op->getOperand(0);
2553+
SDValue Y = Op->getOperand(1);
2554+
// The constructed DAG.
2555+
SDValue MinMax;
2556+
// Location of current node.
2557+
SDLoc Loc(Op);
2558+
// VT for the usage of SETCC op.
2559+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
2560+
EVT SetCCType =
2561+
TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
2562+
2563+
bool IsXNeverNaN = DAG.isKnownNeverNaN(X);
2564+
bool IsYNeverNaN = DAG.isKnownNeverNaN(Y);
2565+
bool NaNMightPresent = (!IsXNeverNaN || !IsYNeverNaN);
2566+
bool IsXNeverZero = DAG.isKnownNeverZeroFloat(X);
2567+
bool IsYNeverZero = DAG.isKnownNeverZeroFloat(Y);
2568+
bool ZeroMightPresent = (!IsXNeverZero || !IsYNeverZero);
2569+
// Note that on Pre-R6 targets fmin and fmax will be replaced with SetCC.
2570+
if (Subtarget.hasMips32r6() || Subtarget.hasMips64r6()) {
2571+
// We have matched min.s/d and max.s/d to their corresponding SDAG
2572+
// operations.
2573+
MinMax =
2574+
DAG.getNode((IsMaxOp ? ISD::FMAXNUM : ISD::FMINNUM), Loc, VT, X, Y);
2575+
} else {
2576+
// Otherwise, use SETCC.
2577+
SDValue SetCCCmp =
2578+
DAG.getSetCC(Loc, SetCCType, X, Y,
2579+
IsMaxOp ? ISD::CondCode::SETGT : ISD::CondCode::SETLT);
2580+
MinMax = DAG.getSelect(Loc, VT, SetCCCmp, X, Y);
2581+
}
2582+
// Add NaN related checks.
2583+
if (NaNMightPresent) {
2584+
// If either X or Y is NaN, return NaN.
2585+
APFloat APNaN = APFloat::getNaN(DAG.EVTToAPFloatSemantics(VT));
2586+
SDValue TstNaN = DAG.getSetCC(Loc, SetCCType, X, Y, ISD::CondCode::SETUO);
2587+
MinMax = DAG.getSelect(Loc, VT, TstNaN, DAG.getConstantFP(APNaN, Loc, VT),
2588+
MinMax);
2589+
}
2590+
// Add zero related checks.
2591+
if (ZeroMightPresent) {
2592+
// Check if both X and Y are zeroes.
2593+
// MIPS ignores signage of zeroes when comparing against zeroes, so -0.0 ==
2594+
// +0.0.
2595+
APFloat FPZero = APFloat::getZero(DAG.EVTToAPFloatSemantics(VT));
2596+
SDValue ConstFPZero = DAG.getConstantFP(FPZero, Loc, VT);
2597+
SDValue Res = DAG.getNode(ISD::FADD, Loc, VT, X, Y);
2598+
SDValue TstZeroes =
2599+
DAG.getSetCC(Loc, SetCCType, Res, ConstFPZero, ISD::CondCode::SETEQ);
2600+
SDValue IsXSigned;
2601+
2602+
if (VT.getSizeInBits() == 64 && Subtarget.isGP32bit()) {
2603+
// Extract the higher 32 bits, and compare like how 64-bit does.
2604+
SDValue ConstInt32Zero = DAG.getConstant(0, Loc, MVT::i32);
2605+
SDValue XHiInt = DAG.getNode(MipsISD::ExtractElementF64, Loc, MVT::i32, X,
2606+
DAG.getConstant(1, Loc, MVT::i32));
2607+
IsXSigned = DAG.getSetCC(Loc, SetCCType, XHiInt, ConstInt32Zero,
2608+
ISD::CondCode::SETLT);
2609+
} else {
2610+
SDValue ConstIntZero = DAG.getConstant(0, Loc, IVT);
2611+
// Check if X is signed.
2612+
// Bitcast X to an integer, and see if it is -(U)INT_MAX (compared to 0).
2613+
SDValue XInt = DAG.getNode(ISD::BITCAST, Loc, IVT, X);
2614+
IsXSigned = DAG.getSetCC(Loc, SetCCType, XInt, ConstIntZero,
2615+
ISD::CondCode::SETLT);
2616+
}
2617+
// Return Y if X and Y are both zeroes and X == -0.0, if op is max;
2618+
// Otherwise return Y.
2619+
SDValue XOrY = IsMaxOp ? DAG.getSelect(Loc, VT, IsXSigned, Y, X)
2620+
: DAG.getSelect(Loc, VT, IsXSigned, X, Y);
2621+
MinMax = DAG.getSelect(Loc, VT, TstZeroes, XOrY, MinMax);
2622+
}
2623+
return MinMax;
2624+
}
2625+
25282626
SDValue MipsTargetLowering::
25292627
lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
25302628
// check the depth

llvm/lib/Target/Mips/MipsISelLowering.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,7 @@ class TargetRegisterClass;
550550
bool HasExtractInsert) const;
551551
SDValue lowerFABS64(SDValue Op, SelectionDAG &DAG,
552552
bool HasExtractInsert) const;
553+
SDValue lowerFMINIMUM_FMAXIMUM(SDValue Op, SelectionDAG &DAG) const;
553554
SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
554555
SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
555556
SDValue lowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;

0 commit comments

Comments
 (0)