]> granicus.if.org Git - llvm/commitdiff
[ValueTracking, InstCombine] canonicalize fcmp ord/uno with non-NAN ops to null constants
authorSanjay Patel <spatel@rotateright.com>
Tue, 5 Sep 2017 23:13:13 +0000 (23:13 +0000)
committerSanjay Patel <spatel@rotateright.com>
Tue, 5 Sep 2017 23:13:13 +0000 (23:13 +0000)
This is a preliminary step towards solving the remaining part of PR27145 - IR for isfinite():
https://bugs.llvm.org/show_bug.cgi?id=27145

In order to solve that one more generally, we need to add matching for and/or of fcmp ord/uno
with a constant operand.

But while looking at those patterns, I realized we were missing a canonicalization for nonzero
constants. Rather than limiting to just folds for constants, we're adding a general value
tracking method for this based on an existing DAG helper.

By transforming everything to 0.0, we can simplify the existing code in foldLogicOfFCmps()
and pick up missing vector folds.

Differential Revision: https://reviews.llvm.org/D37427

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@312591 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/ValueTracking.h
lib/Analysis/ValueTracking.cpp
lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
lib/Transforms/InstCombine/InstCombineCompares.cpp
test/Transforms/InstCombine/and-fcmp.ll
test/Transforms/InstCombine/fcmp-special.ll
test/Transforms/InstCombine/or-fcmp.ll

index 2705eb3f3c4094c2b52550af611bcc32acc0a1da..190b2520376399562cd8b15fa30fb54a39d4e1f2 100644 (file)
@@ -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)
index a9619746797ea6de6fd3f263da98346c1b132458..f47559b850a4ddc72ee3e0821a2b5051d8918246 100644 (file)
@@ -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,
index 006ed418c733100ac91010e4f04a92bcb7c65fb0..a81f295b91d4e787455ebb9869edfc6ff7bb8450 100644 (file)
@@ -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);
   }
 
index c2de45a369945dd302d588b583bfac59a3e390b5..240a9c41b5feb9d66ca1ed3be788374135521dfd 100644 (file)
@@ -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
index 7bf300d9a1478357340be6c3f4a1cdc04805d4e6..04c6a2a08e7230972f1a129205f60d70eff2f534 100644 (file)
@@ -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>
index faf153a8b96469ef6739506d375d1411a06ca175..565da9621cafe400d1c004224bc4abaf35fcb402 100644 (file)
@@ -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
index ede6853b6572dc8f28a8ae0e62b36dafe9e09cf3..7b95f9dde0e9c19dccca86feb7af5a7f68707a37 100644 (file)
@@ -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>