[llvm] cd48113 - [ValueTracking] Add a basic version of isKnownNonInfinity and use it to detect more NoNaNs

Benjamin Kramer via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 19 13:32:58 PST 2019


Author: Benjamin Kramer
Date: 2019-11-19T22:24:46+01:00
New Revision: cd4811360e2a1d23578073c6c99b2ef8ba276289

URL: https://github.com/llvm/llvm-project/commit/cd4811360e2a1d23578073c6c99b2ef8ba276289
DIFF: https://github.com/llvm/llvm-project/commit/cd4811360e2a1d23578073c6c99b2ef8ba276289.diff

LOG: [ValueTracking] Add a basic version of isKnownNonInfinity and use it to detect more NoNaNs

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/ValueTracking.h
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/test/Transforms/InstSimplify/known-never-nan.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 8d5533b7ece8..138037985986 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -203,6 +203,12 @@ class Value;
   ///   x < -0 --> false
   bool CannotBeOrderedLessThanZero(const Value *V, const TargetLibraryInfo *TLI);
 
+  /// Return true if the floating-point scalar value is not an infinity or if
+  /// the floating-point vector value has no infinities. Return false if a value
+  /// could ever be infinity.
+  bool isKnownNeverInfinity(const Value *V, const TargetLibraryInfo *TLI,
+                            unsigned Depth = 0);
+
   /// 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.

diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index f03a4a6eee45..51d92cca214b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3095,6 +3095,58 @@ bool llvm::SignBitMustBeZero(const Value *V, const TargetLibraryInfo *TLI) {
   return cannotBeOrderedLessThanZeroImpl(V, TLI, true, 0);
 }
 
+bool llvm::isKnownNeverInfinity(const Value *V, const TargetLibraryInfo *TLI,
+                                unsigned Depth) {
+  assert(V->getType()->isFPOrFPVectorTy() && "Querying for Inf on non-FP type");
+
+  // If we're told that infinities won't happen, assume they won't.
+  if (auto *FPMathOp = dyn_cast<FPMathOperator>(V))
+    if (FPMathOp->hasNoInfs())
+      return true;
+
+  // Handle scalar constants.
+  if (auto *CFP = dyn_cast<ConstantFP>(V))
+    return !CFP->isInfinity();
+
+  if (Depth == MaxDepth)
+    return false;
+
+  if (auto *Inst = dyn_cast<Instruction>(V)) {
+    switch (Inst->getOpcode()) {
+    case Instruction::Select: {
+      return isKnownNeverInfinity(Inst->getOperand(1), TLI, Depth + 1) &&
+             isKnownNeverInfinity(Inst->getOperand(2), TLI, Depth + 1);
+    }
+    case Instruction::UIToFP:
+      // If the input type fits into the floating type the result is finite.
+      return ilogb(APFloat::getLargest(
+                 Inst->getType()->getScalarType()->getFltSemantics())) >=
+             (int)Inst->getOperand(0)->getType()->getScalarSizeInBits();
+    default:
+      break;
+    }
+  }
+
+  // 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 infinity.
+  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->isInfinity())
+      return false;
+  }
+  // All elements were confirmed non-infinity or undefined.
+  return true;
+}
+
 bool llvm::isKnownNeverNaN(const Value *V, const TargetLibraryInfo *TLI,
                            unsigned Depth) {
   assert(V->getType()->isFPOrFPVectorTy() && "Querying for NaN on non-FP type");
@@ -3114,13 +3166,26 @@ bool llvm::isKnownNeverNaN(const Value *V, const TargetLibraryInfo *TLI,
   if (auto *Inst = dyn_cast<Instruction>(V)) {
     switch (Inst->getOpcode()) {
     case Instruction::FAdd:
-    case Instruction::FMul:
     case Instruction::FSub:
+      // Adding positive and negative infinity produces NaN.
+      return isKnownNeverNaN(Inst->getOperand(0), TLI, Depth + 1) &&
+             isKnownNeverNaN(Inst->getOperand(1), TLI, Depth + 1) &&
+             (isKnownNeverInfinity(Inst->getOperand(0), TLI, Depth + 1) ||
+              isKnownNeverInfinity(Inst->getOperand(1), TLI, Depth + 1));
+
+    case Instruction::FMul:
+      // Zero multiplied with infinity produces NaN.
+      // FIXME: If neither side can be zero fmul never produces NaN.
+      return isKnownNeverNaN(Inst->getOperand(0), TLI, Depth + 1) &&
+             isKnownNeverInfinity(Inst->getOperand(0), TLI, Depth + 1) &&
+             isKnownNeverNaN(Inst->getOperand(1), TLI, Depth + 1) &&
+             isKnownNeverInfinity(Inst->getOperand(1), TLI, Depth + 1);
+
     case Instruction::FDiv:
-    case Instruction::FRem: {
-      // TODO: Need isKnownNeverInfinity
+    case Instruction::FRem:
+      // FIXME: Only 0/0, Inf/Inf, Inf REM x and x REM 0 produce NaN.
       return false;
-    }
+
     case Instruction::Select: {
       return isKnownNeverNaN(Inst->getOperand(1), TLI, Depth + 1) &&
              isKnownNeverNaN(Inst->getOperand(2), TLI, Depth + 1);

diff  --git a/llvm/test/Transforms/InstSimplify/known-never-nan.ll b/llvm/test/Transforms/InstSimplify/known-never-nan.ll
index 37cfc932aa43..109775607bcc 100644
--- a/llvm/test/Transforms/InstSimplify/known-never-nan.ll
+++ b/llvm/test/Transforms/InstSimplify/known-never-nan.ll
@@ -158,6 +158,18 @@ define i1 @known_nan_select(i1 %cond, double %arg0, double %arg1) {
   ret i1 %tmp
 }
 
+define i1 @nnan_ninf_known_nan_select(i1 %cond, double %arg0, double %arg1) {
+; CHECK-LABEL: @nnan_ninf_known_nan_select(
+; CHECK-NEXT:    ret i1 true
+;
+  %lhs = fadd nnan ninf double %arg0, 1.0
+  %rhs = fadd nnan ninf double %arg1, 2.0
+  %op = select i1 %cond, double %lhs, double %rhs
+  %mul = fmul double %op, 2.0
+  %tmp = fcmp ord double %mul, %mul
+  ret i1 %tmp
+}
+
 define i1 @select_maybe_nan_lhs(i1 %cond, double %lhs, double %arg1) {
 ; CHECK-LABEL: @select_maybe_nan_lhs(
 ; CHECK-NEXT:    [[RHS:%.*]] = fadd nnan double [[ARG1:%.*]], 1.000000e+00
@@ -258,9 +270,7 @@ define i1 @nnan_fsub(double %arg0, double %arg1) {
 define i1 @nnan_binary_fneg() {
 ; CHECK-LABEL: @nnan_binary_fneg(
 ; CHECK-NEXT:    [[NNAN:%.*]] = call nnan double @func()
-; CHECK-NEXT:    [[OP:%.*]] = fsub double -0.000000e+00, [[NNAN]]
-; CHECK-NEXT:    [[TMP:%.*]] = fcmp ord double [[OP]], [[OP]]
-; CHECK-NEXT:    ret i1 [[TMP]]
+; CHECK-NEXT:    ret i1 true
 ;
   %nnan = call nnan double @func()
   %op = fsub double -0.0, %nnan
@@ -299,6 +309,29 @@ define i1 @uitofp(i32 %arg0) {
   ret i1 %tmp
 }
 
+define i1 @uitofp_add(i32 %arg0) {
+; CHECK-LABEL: @uitofp_add(
+; CHECK-NEXT:    ret i1 true
+;
+  %op = uitofp i32 %arg0 to double
+  %add = fadd double %op, %op
+  %tmp = fcmp ord double %add, %add
+  ret i1 %tmp
+}
+
+define i1 @uitofp_add_big(i1024 %arg0) {
+; CHECK-LABEL: @uitofp_add_big(
+; CHECK-NEXT:    [[OP:%.*]] = uitofp i1024 [[ARG0:%.*]] to double
+; CHECK-NEXT:    [[ADD:%.*]] = fadd double [[OP]], [[OP]]
+; CHECK-NEXT:    [[TMP:%.*]] = fcmp ord double [[ADD]], [[ADD]]
+; CHECK-NEXT:    ret i1 [[TMP]]
+;
+  %op = uitofp i1024 %arg0 to double
+  %add = fadd double %op, %op
+  %tmp = fcmp ord double %add, %add
+  ret i1 %tmp
+}
+
 define i1 @fpext(float %arg0) {
 ; CHECK-LABEL: @fpext(
 ; CHECK-NEXT:    ret i1 false


        


More information about the llvm-commits mailing list