Skip to content

Commit a3047c3

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 090c92e commit a3047c3

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
@@ -447,7 +447,13 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
447447
setOperationAction(ISD::FMA, MVT::f64, Expand);
448448
setOperationAction(ISD::FREM, MVT::f32, Expand);
449449
setOperationAction(ISD::FREM, MVT::f64, Expand);
450-
450+
if (Subtarget.isFP64bit() || Subtarget.isSingleFloat() ||
451+
Subtarget.isFPXX()) {
452+
setOperationAction(ISD::FMINIMUM, MVT::f32, Custom);
453+
setOperationAction(ISD::FMAXIMUM, MVT::f32, Custom);
454+
setOperationAction(ISD::FMINIMUM, MVT::f64, Custom);
455+
setOperationAction(ISD::FMAXIMUM, MVT::f64, Custom);
456+
}
451457
// Lower f16 conversion operations into library calls
452458
setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
453459
setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
@@ -1258,6 +1264,9 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
12581264
case ISD::STORE: return lowerSTORE(Op, DAG);
12591265
case ISD::EH_DWARF_CFA: return lowerEH_DWARF_CFA(Op, DAG);
12601266
case ISD::FP_TO_SINT: return lowerFP_TO_SINT(Op, DAG);
1267+
case ISD::FMINIMUM:
1268+
case ISD::FMAXIMUM:
1269+
return lowerFMINIMUM_FMAXIMUM(Op, DAG);
12611270
}
12621271
return SDValue();
12631272
}
@@ -2516,6 +2525,94 @@ SDValue MipsTargetLowering::lowerFABS(SDValue Op, SelectionDAG &DAG) const {
25162525
return lowerFABS32(Op, DAG, Subtarget.hasExtractInsert());
25172526
}
25182527

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