Skip to content

Commit 6c7457f

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 6c7457f

File tree

3 files changed

+475
-1
lines changed

3 files changed

+475
-1
lines changed

llvm/lib/Target/Mips/MipsISelLowering.cpp

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,12 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
456456
setOperationAction(ISD::FMA, MVT::f64, Expand);
457457
setOperationAction(ISD::FREM, MVT::f32, Expand);
458458
setOperationAction(ISD::FREM, MVT::f64, Expand);
459-
459+
if (!Subtarget.isSingleFloat()) {
460+
setOperationAction(ISD::FMINIMUM, MVT::f32, Custom);
461+
setOperationAction(ISD::FMAXIMUM, MVT::f32, Custom);
462+
setOperationAction(ISD::FMINIMUM, MVT::f64, Custom);
463+
setOperationAction(ISD::FMAXIMUM, MVT::f64, Custom);
464+
}
460465
// Lower f16 conversion operations into library calls
461466
setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
462467
setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
@@ -1267,6 +1272,9 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
12671272
case ISD::STORE: return lowerSTORE(Op, DAG);
12681273
case ISD::EH_DWARF_CFA: return lowerEH_DWARF_CFA(Op, DAG);
12691274
case ISD::FP_TO_SINT: return lowerFP_TO_SINT(Op, DAG);
1275+
case ISD::FMINIMUM:
1276+
case ISD::FMAXIMUM:
1277+
return lowerFMINIMUM_FMAXIMUM(Op, DAG);
12701278
}
12711279
return SDValue();
12721280
}
@@ -2525,6 +2533,94 @@ SDValue MipsTargetLowering::lowerFABS(SDValue Op, SelectionDAG &DAG) const {
25252533
return lowerFABS32(Op, DAG, Subtarget.hasExtractInsert());
25262534
}
25272535

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