/// x < -0 --> false
bool CannotBeOrderedLessThanZero(const Value *V, const TargetLibraryInfo *TLI);
+ /// Return true if the floating-point scalar value is not a NaN or if the
+ /// floating-point vector value has no NaN elements. Return false if a value
+ /// could ever be NaN.
+ bool isKnownNeverNaN(const Value *V);
+
/// Return true if we can prove that the specified FP value's sign bit is 0.
///
/// NaN --> true/false (depending on the NaN's sign bit)
return cannotBeOrderedLessThanZeroImpl(V, TLI, true, 0);
}
+bool llvm::isKnownNeverNaN(const Value *V) {
+ assert(V->getType()->isFPOrFPVectorTy() && "Querying for NaN on non-FP type");
+
+ // If we're told that NaNs won't happen, assume they won't.
+ if (auto *FPMathOp = dyn_cast<FPMathOperator>(V))
+ if (FPMathOp->hasNoNaNs())
+ return true;
+
+ // TODO: Handle instructions and potentially recurse like other 'isKnown'
+ // functions. For example, the result of sitofp is never NaN.
+
+ // Handle scalar constants.
+ if (auto *CFP = dyn_cast<ConstantFP>(V))
+ return !CFP->isNaN();
+
+ // Bail out for constant expressions, but try to handle vector constants.
+ if (!V->getType()->isVectorTy() || !isa<Constant>(V))
+ return false;
+
+ // For vectors, verify that each element is not NaN.
+ unsigned NumElts = V->getType()->getVectorNumElements();
+ for (unsigned i = 0; i != NumElts; ++i) {
+ Constant *Elt = cast<Constant>(V)->getAggregateElement(i);
+ if (!Elt)
+ return false;
+ if (isa<UndefValue>(Elt))
+ continue;
+ auto *CElt = dyn_cast<ConstantFP>(Elt);
+ if (!CElt || CElt->isNaN())
+ return false;
+ }
+ // All elements were confirmed not-NaN or undefined.
+ return true;
+}
+
/// If the specified value can be set by repeating the same byte in memory,
/// return the i8 value that it is represented with. This is
/// true for all i8 values obviously, but is also true for i32 0, i32 -1,
if (LHS0->getType() != RHS0->getType())
return nullptr;
- auto *LHSC = dyn_cast<ConstantFP>(LHS1);
- auto *RHSC = dyn_cast<ConstantFP>(RHS1);
- if (LHSC && RHSC) {
- assert(!LHSC->getValueAPF().isNaN() && !RHSC->getValueAPF().isNaN() &&
- "Failed to simplify fcmp ord/uno with NAN operand");
- // Ignore the constants because they can't be NANs:
- // (fcmp ord x, c) & (fcmp ord y, c) -> (fcmp ord x, y)
- // (fcmp uno x, c) & (fcmp uno y, c) -> (fcmp uno x, y)
- return Builder.CreateFCmp(PredL, LHS0, RHS0);
- }
-
- // Handle vector zeros. This occurs because the canonical form of
- // "fcmp ord/uno x,x" is "fcmp ord/uno x, 0".
- if (isa<ConstantAggregateZero>(LHS1) &&
- isa<ConstantAggregateZero>(RHS1))
+ // FCmp canonicalization ensures that (fcmp ord/uno X, X) and
+ // (fcmp ord/uno X, C) will be transformed to (fcmp X, 0.0).
+ if (match(LHS1, m_Zero()) && LHS1 == RHS1)
+ // Ignore the constants because they are obviously not NANs:
+ // (fcmp ord x, 0.0) & (fcmp ord y, 0.0) -> (fcmp ord x, y)
+ // (fcmp uno x, 0.0) | (fcmp uno y, 0.0) -> (fcmp uno x, y)
return Builder.CreateFCmp(PredL, LHS0, RHS0);
}
}
}
+ // If we're just checking for a NaN (ORD/UNO) and have a non-NaN operand,
+ // then canonicalize the operand to 0.0.
+ if (Pred == CmpInst::FCMP_ORD || Pred == CmpInst::FCMP_UNO) {
+ if (!match(Op0, m_Zero()) && isKnownNeverNaN(Op0)) {
+ I.setOperand(0, ConstantFP::getNullValue(Op0->getType()));
+ return &I;
+ }
+ if (!match(Op1, m_Zero()) && isKnownNeverNaN(Op1)) {
+ I.setOperand(1, ConstantFP::getNullValue(Op0->getType()));
+ return &I;
+ }
+ }
+
// Test if the FCmpInst instruction is used exclusively by a select as
// part of a minimum or maximum operation. If so, refrain from doing
// any other folding. This helps out other analyses which understand
define <3 x i1> @fcmp_ord_nonzero_vec(<3 x float> %x, <3 x float> %y) {
; CHECK-LABEL: @fcmp_ord_nonzero_vec(
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord <3 x float> %x, <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00>
-; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord <3 x float> %y, <float 3.000000e+00, float 2.000000e+00, float 1.000000e+00>
-; CHECK-NEXT: [[AND:%.*]] = and <3 x i1> [[CMP1]], [[CMP2]]
-; CHECK-NEXT: ret <3 x i1> [[AND]]
+; CHECK-NEXT: [[TMP1:%.*]] = fcmp ord <3 x float> %x, %y
+; CHECK-NEXT: ret <3 x i1> [[TMP1]]
;
%cmp1 = fcmp ord <3 x float> %x, <float 1.0, float 2.0, float 3.0>
%cmp2 = fcmp ord <3 x float> %y, <float 3.0, float 2.0, float 1.0>
define i1 @ord_nonzero(double %x) {
; CHECK-LABEL: @ord_nonzero(
-; CHECK-NEXT: [[F:%.*]] = fcmp ord double %x, 3.000000e+00
+; CHECK-NEXT: [[F:%.*]] = fcmp ord double %x, 0.000000e+00
; CHECK-NEXT: ret i1 [[F]]
;
%f = fcmp ord double %x, 3.0
define i1 @uno_nonzero(float %x) {
; CHECK-LABEL: @uno_nonzero(
-; CHECK-NEXT: [[F:%.*]] = fcmp uno float %x, 3.000000e+00
+; CHECK-NEXT: [[F:%.*]] = fcmp uno float %x, 0.000000e+00
; CHECK-NEXT: ret i1 [[F]]
;
%f = fcmp uno float %x, 3.0
define <2 x i1> @ord_nonzero_vec(<2 x float> %x) {
; CHECK-LABEL: @ord_nonzero_vec(
-; CHECK-NEXT: [[F:%.*]] = fcmp ord <2 x float> %x, <float 3.000000e+00, float 5.000000e+00>
+; CHECK-NEXT: [[F:%.*]] = fcmp ord <2 x float> %x, zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[F]]
;
%f = fcmp ord <2 x float> %x, <float 3.0, float 5.0>
define <2 x i1> @uno_nonzero_vec(<2 x double> %x) {
; CHECK-LABEL: @uno_nonzero_vec(
-; CHECK-NEXT: [[F:%.*]] = fcmp uno <2 x double> %x, <double 3.000000e+00, double 5.000000e+00>
+; CHECK-NEXT: [[F:%.*]] = fcmp uno <2 x double> %x, zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[F]]
;
%f = fcmp uno <2 x double> %x, <double 3.0, double 5.0>
define i1 @nnan_ops_to_fcmp_ord(float %x, float %y) {
; CHECK-LABEL: @nnan_ops_to_fcmp_ord(
-; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float %x, %y
-; CHECK-NEXT: [[DIV:%.*]] = fdiv nnan float %x, %y
-; CHECK-NEXT: [[CMP:%.*]] = fcmp ord float [[MUL]], [[DIV]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%mul = fmul nnan float %x, %y
%div = fdiv nnan float %x, %y
define i1 @nnan_ops_to_fcmp_uno(float %x, float %y) {
; CHECK-LABEL: @nnan_ops_to_fcmp_uno(
-; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float %x, %y
-; CHECK-NEXT: [[DIV:%.*]] = fdiv nnan float %x, %y
-; CHECK-NEXT: [[CMP:%.*]] = fcmp uno float [[MUL]], [[DIV]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%mul = fmul nnan float %x, %y
%div = fdiv nnan float %x, %y
define <3 x i1> @fcmp_uno_nonzero_vec(<3 x float> %x, <3 x float> %y) {
; CHECK-LABEL: @fcmp_uno_nonzero_vec(
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno <3 x float> %x, <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00>
-; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno <3 x float> %y, <float 3.000000e+00, float 2.000000e+00, float 1.000000e+00>
-; CHECK-NEXT: [[OR:%.*]] = or <3 x i1> [[CMP1]], [[CMP2]]
-; CHECK-NEXT: ret <3 x i1> [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno <3 x float> %x, %y
+; CHECK-NEXT: ret <3 x i1> [[TMP1]]
;
%cmp1 = fcmp uno <3 x float> %x, <float 1.0, float 2.0, float 3.0>
%cmp2 = fcmp uno <3 x float> %y, <float 3.0, float 2.0, float 1.0>