From 7e3184c4122e90772e983e1fe16dccf3b32ad8b6 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Thu, 26 Jan 2017 00:10:26 +0000 Subject: [PATCH] [ValueTracking] Implement SignBitMustBeZero correctly for sqrt. Summary: Previously we assumed that the result of sqrt(x) always had 0 as its sign bit. But sqrt(-0) == -0. Reviewers: hfinkel, efriedma, sanjoy Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D28928 llvm-svn: 293115 --- llvm/lib/Analysis/ValueTracking.cpp | 16 ++++-- .../InstSimplify/floating-point-arithmetic.ll | 54 +++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index dc8de6d58a37..ad4e668efbf2 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -2645,7 +2645,8 @@ static bool cannotBeOrderedLessThanZeroImpl(const Value *V, return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly, Depth + 1); case Instruction::Call: - Intrinsic::ID IID = getIntrinsicForCallSite(cast(I), TLI); + const auto *CI = cast(I); + Intrinsic::ID IID = getIntrinsicForCallSite(CI, TLI); switch (IID) { default: break; @@ -2662,12 +2663,19 @@ static bool cannotBeOrderedLessThanZeroImpl(const Value *V, case Intrinsic::exp: case Intrinsic::exp2: case Intrinsic::fabs: - case Intrinsic::sqrt: return true; + + case Intrinsic::sqrt: + // sqrt(x) is always >= -0 or NaN. Moreover, sqrt(x) == -0 iff x == -0. + if (!SignBitOnly) + return true; + return CI->hasNoNaNs() && (CI->hasNoSignedZeros() || + CannotBeNegativeZero(CI->getOperand(0), TLI)); + case Intrinsic::powi: - if (ConstantInt *CI = dyn_cast(I->getOperand(1))) { + if (ConstantInt *Exponent = dyn_cast(I->getOperand(1))) { // powi(x,n) is non-negative if n is even. - if (CI->getBitWidth() <= 64 && CI->getSExtValue() % 2u == 0) + if (Exponent->getBitWidth() <= 64 && Exponent->getSExtValue() % 2u == 0) return true; } return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly, diff --git a/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll b/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll index dfdb88dcc858..e635032e6b71 100644 --- a/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll +++ b/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll @@ -104,6 +104,7 @@ define float @PR22688(float %x) { } declare float @llvm.fabs.f32(float) +declare float @llvm.sqrt.f32(float) ; CHECK-LABEL: @fabs_select_positive_constants( ; CHECK: %select = select i1 %cmp, float 1.000000e+00, float 2.000000e+00 @@ -195,3 +196,56 @@ define float @fabs_select_negnan_zero(float addrspace(1)* %out, i32 %c) { %fabs = call float @llvm.fabs.f32(float %select) ret float %fabs } + +; CHECK-LABEL: @fabs_sqrt +; CHECK: call float @llvm.sqrt.f32 +; CHECK: call float @llvm.fabs.f32 +define float @fabs_sqrt(float %a) { +; The fabs can't be eliminated because llvm.sqrt.f32 may return -0 or NaN with +; an arbitrary sign bit. + %sqrt = call float @llvm.sqrt.f32(float %a) + %fabs = call float @llvm.fabs.f32(float %sqrt) + ret float %fabs +} + +; CHECK-LABEL: @fabs_sqrt_nnan +; CHECK: call nnan float @llvm.sqrt.f32 +; CHECK: call float @llvm.fabs.f32 +define float @fabs_sqrt_nnan(float %a) { +; The fabs can't be eliminated because the nnan sqrt may still return -0. + %sqrt = call nnan float @llvm.sqrt.f32(float %a) + %fabs = call float @llvm.fabs.f32(float %sqrt) + ret float %fabs +} + +; CHECK-LABEL: @fabs_sqrt_nsz +; CHECK: call nsz float @llvm.sqrt.f32 +; CHECK: call float @llvm.fabs.f32 +define float @fabs_sqrt_nsz(float %a) { +; The fabs can't be eliminated because the nsz sqrt may still return NaN. + %sqrt = call nsz float @llvm.sqrt.f32(float %a) + %fabs = call float @llvm.fabs.f32(float %sqrt) + ret float %fabs +} + +; CHECK-LABEL: @fabs_sqrt_nnan_nsz +; CHECK: call nnan nsz float @llvm.sqrt.f32 +; CHECK-NOT: call float @llvm.fabs.f32 +define float @fabs_sqrt_nnan_nsz(float %a) { +; The fabs can be eliminated because we're nsz and nnan. + %sqrt = call nnan nsz float @llvm.sqrt.f32(float %a) + %fabs = call float @llvm.fabs.f32(float %sqrt) + ret float %fabs +} + +; CHECK-LABEL: @fabs_sqrt_nnan_fabs +; CHECK: call float @llvm.fabs.f32 +; CHECK: call nnan float @llvm.sqrt.f32 +; CHECK-NOT: call float @llvm.fabs.f32 +define float @fabs_sqrt_nnan_fabs(float %a) { +; The second fabs can be eliminated because the operand to sqrt cannot be -0. + %b = call float @llvm.fabs.f32(float %a) + %sqrt = call nnan float @llvm.sqrt.f32(float %b) + %fabs = call float @llvm.fabs.f32(float %sqrt) + ret float %fabs +}