diff options
-rw-r--r-- | llvm/include/llvm/Analysis/ValueTracking.h | 6 | ||||
-rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 73 | ||||
-rw-r--r-- | llvm/test/Transforms/InstSimplify/known-never-nan.ll | 39 |
3 files changed, 111 insertions, 7 deletions
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 8d5533b7ece..13803798598 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 f03a4a6eee4..51d92cca214 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 37cfc932aa4..109775607bc 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 |