[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