diff options
| -rw-r--r-- | llvm/include/llvm/Analysis/ValueTracking.h | 5 | ||||
| -rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 35 | ||||
| -rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 21 | ||||
| -rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 13 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/and-fcmp.ll | 6 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/fcmp-special.ll | 18 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/or-fcmp.ll | 6 |
7 files changed, 69 insertions, 35 deletions
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 2705eb3f3c4..190b2520376 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -185,6 +185,11 @@ class Value; /// 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) diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index a9619746797..f47559b850a 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -2695,6 +2695,41 @@ bool llvm::SignBitMustBeZero(const Value *V, const TargetLibraryInfo *TLI) { 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, diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 006ed418c73..a81f295b91d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -938,21 +938,12 @@ Value *InstCombiner::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS, bool IsAnd) 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); } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index c2de45a3699..240a9c41b5f 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4963,6 +4963,19 @@ Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) { } } + // 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 diff --git a/llvm/test/Transforms/InstCombine/and-fcmp.ll b/llvm/test/Transforms/InstCombine/and-fcmp.ll index 7bf300d9a14..04c6a2a08e7 100644 --- a/llvm/test/Transforms/InstCombine/and-fcmp.ll +++ b/llvm/test/Transforms/InstCombine/and-fcmp.ll @@ -41,10 +41,8 @@ define i1 @fcmp_ord_nonzero(float %x, float %y) { 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> diff --git a/llvm/test/Transforms/InstCombine/fcmp-special.ll b/llvm/test/Transforms/InstCombine/fcmp-special.ll index faf153a8b96..565da9621ca 100644 --- a/llvm/test/Transforms/InstCombine/fcmp-special.ll +++ b/llvm/test/Transforms/InstCombine/fcmp-special.ll @@ -35,7 +35,7 @@ define i1 @ord_zero(float %x) { 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 @@ -62,7 +62,7 @@ define i1 @uno_zero(double %x) { 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 @@ -89,7 +89,7 @@ define <2 x i1> @ord_zero_vec(<2 x double> %x) { 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> @@ -116,7 +116,7 @@ define <2 x i1> @uno_zero_vec(<2 x float> %x) { 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> @@ -148,10 +148,7 @@ define <2 x i1> @uno_vec_with_nan(<2 x double> %x) { 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 @@ -163,10 +160,7 @@ define i1 @nnan_ops_to_fcmp_ord(float %x, float %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 diff --git a/llvm/test/Transforms/InstCombine/or-fcmp.ll b/llvm/test/Transforms/InstCombine/or-fcmp.ll index ede6853b657..7b95f9dde0e 100644 --- a/llvm/test/Transforms/InstCombine/or-fcmp.ll +++ b/llvm/test/Transforms/InstCombine/or-fcmp.ll @@ -14,10 +14,8 @@ define i1 @fcmp_uno_nonzero(float %x, float %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> |

