summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Target/ARM/ARMISelLowering.cpp53
-rw-r--r--test/CodeGen/ARM/neon_minmax.ll16
2 files changed, 47 insertions, 22 deletions
diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp
index e5333edd50..525edd21cd 100644
--- a/lib/Target/ARM/ARMISelLowering.cpp
+++ b/lib/Target/ARM/ARMISelLowering.cpp
@@ -3879,50 +3879,59 @@ static SDValue PerformSELECT_CCCombine(SDNode *N, SelectionDAG &DAG,
unsigned Opcode = 0;
bool IsReversed;
- if (LHS == CondLHS && RHS == CondRHS) {
+ if (DAG.isEqualTo(LHS, CondLHS) && DAG.isEqualTo(RHS, CondRHS)) {
IsReversed = false; // x CC y ? x : y
- } else if (LHS == CondRHS && RHS == CondLHS) {
+ } else if (DAG.isEqualTo(LHS, CondRHS) && DAG.isEqualTo(RHS, CondLHS)) {
IsReversed = true ; // x CC y ? y : x
} else {
return SDValue();
}
+ bool IsUnordered;
switch (CC) {
default: break;
case ISD::SETOLT:
case ISD::SETOLE:
case ISD::SETLT:
case ISD::SETLE:
- // This can be vmin if we can prove that the LHS is not a NaN.
- // (If either operand is NaN, the comparison will be false and the result
- // will be the RHS, which matches vmin if RHS is the NaN.)
- if (DAG.isKnownNeverNaN(LHS))
- Opcode = IsReversed ? ARMISD::FMAX : ARMISD::FMIN;
- break;
-
case ISD::SETULT:
case ISD::SETULE:
- // Likewise, for ULT/ULE we need to know that RHS is not a NaN.
- if (DAG.isKnownNeverNaN(RHS))
- Opcode = IsReversed ? ARMISD::FMAX : ARMISD::FMIN;
+ // If LHS is NaN, an ordered comparison will be false and the result will
+ // be the RHS, but vmin(NaN, RHS) = NaN. Avoid this by checking that LHS
+ // != NaN. Likewise, for unordered comparisons, check for RHS != NaN.
+ IsUnordered = (CC == ISD::SETULT || CC == ISD::SETULE);
+ if (!DAG.isKnownNeverNaN(IsUnordered ? RHS : LHS))
+ break;
+ // For less-than-or-equal comparisons, "+0 <= -0" will be true but vmin
+ // will return -0, so vmin can only be used for unsafe math or if one of
+ // the operands is known to be nonzero.
+ if ((CC == ISD::SETLE || CC == ISD::SETOLE || CC == ISD::SETULE) &&
+ !UnsafeFPMath &&
+ !(DAG.isKnownNeverZero(LHS) || DAG.isKnownNeverZero(RHS)))
+ break;
+ Opcode = IsReversed ? ARMISD::FMAX : ARMISD::FMIN;
break;
case ISD::SETOGT:
case ISD::SETOGE:
case ISD::SETGT:
case ISD::SETGE:
- // This can be vmax if we can prove that the LHS is not a NaN.
- // (If either operand is NaN, the comparison will be false and the result
- // will be the RHS, which matches vmax if RHS is the NaN.)
- if (DAG.isKnownNeverNaN(LHS))
- Opcode = IsReversed ? ARMISD::FMIN : ARMISD::FMAX;
- break;
-
case ISD::SETUGT:
case ISD::SETUGE:
- // Likewise, for UGT/UGE we need to know that RHS is not a NaN.
- if (DAG.isKnownNeverNaN(RHS))
- Opcode = IsReversed ? ARMISD::FMIN : ARMISD::FMAX;
+ // If LHS is NaN, an ordered comparison will be false and the result will
+ // be the RHS, but vmax(NaN, RHS) = NaN. Avoid this by checking that LHS
+ // != NaN. Likewise, for unordered comparisons, check for RHS != NaN.
+ IsUnordered = (CC == ISD::SETUGT || CC == ISD::SETUGE);
+ if (!DAG.isKnownNeverNaN(IsUnordered ? RHS : LHS))
+ break;
+ // For greater-than-or-equal comparisons, "-0 >= +0" will be true but vmax
+ // will return +0, so vmax can only be used for unsafe math or if one of
+ // the operands is known to be nonzero.
+ if ((CC == ISD::SETGE || CC == ISD::SETOGE || CC == ISD::SETUGE) &&
+ !UnsafeFPMath &&
+ !(DAG.isKnownNeverZero(LHS) || DAG.isKnownNeverZero(RHS)))
+ break;
+ Opcode = IsReversed ? ARMISD::FMIN : ARMISD::FMAX;
break;
}
diff --git a/test/CodeGen/ARM/neon_minmax.ll b/test/CodeGen/ARM/neon_minmax.ll
index 64349d650e..d301c6a4ca 100644
--- a/test/CodeGen/ARM/neon_minmax.ll
+++ b/test/CodeGen/ARM/neon_minmax.ll
@@ -8,6 +8,14 @@ define float @fmin_ole(float %x) nounwind {
ret float %min1
}
+define float @fmin_ole_zero(float %x) nounwind {
+;CHECK: fmin_ole_zero:
+;CHECK-NOT: vmin.f32
+ %cond = fcmp ole float 0.0, %x
+ %min1 = select i1 %cond, float 0.0, float %x
+ ret float %min1
+}
+
define float @fmin_ult(float %x) nounwind {
;CHECK: fmin_ult:
;CHECK: vmin.f32
@@ -32,6 +40,14 @@ define float @fmax_uge(float %x) nounwind {
ret float %max1
}
+define float @fmax_uge_zero(float %x) nounwind {
+;CHECK: fmax_uge_zero:
+;CHECK-NOT: vmax.f32
+ %cond = fcmp uge float %x, 0.0
+ %max1 = select i1 %cond, float %x, float 0.0
+ ret float %max1
+}
+
define float @fmax_olt_reverse(float %x) nounwind {
;CHECK: fmax_olt_reverse:
;CHECK: vmax.f32