Skip to content

Commit 07203b1

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 07203b1

File tree

3 files changed

+476
-1
lines changed

3 files changed

+476
-1
lines changed

llvm/lib/Target/Mips/MipsISelLowering.cpp

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,13 @@ 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.isFP64bit() || Subtarget.isSingleFloat() ||
460+
Subtarget.isFPXX()) {
461+
setOperationAction(ISD::FMINIMUM, MVT::f32, Custom);
462+
setOperationAction(ISD::FMAXIMUM, MVT::f32, Custom);
463+
setOperationAction(ISD::FMINIMUM, MVT::f64, Custom);
464+
setOperationAction(ISD::FMAXIMUM, MVT::f64, Custom);
465+
}
460466
// Lower f16 conversion operations into library calls
461467
setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
462468
setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
@@ -1267,6 +1273,9 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
12671273
case ISD::STORE: return lowerSTORE(Op, DAG);
12681274
case ISD::EH_DWARF_CFA: return lowerEH_DWARF_CFA(Op, DAG);
12691275
case ISD::FP_TO_SINT: return lowerFP_TO_SINT(Op, DAG);
1276+
case ISD::FMINIMUM:
1277+
case ISD::FMAXIMUM:
1278+
return lowerFMINIMUM_FMAXIMUM(Op, DAG);
12701279
}
12711280
return SDValue();
12721281
}
@@ -2525,6 +2534,94 @@ SDValue MipsTargetLowering::lowerFABS(SDValue Op, SelectionDAG &DAG) const {
25252534
return lowerFABS32(Op, DAG, Subtarget.hasExtractInsert());
25262535
}
25272536

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