Index: include/llvm/Analysis/ValueTracking.h =================================================================== --- include/llvm/Analysis/ValueTracking.h +++ include/llvm/Analysis/ValueTracking.h @@ -169,9 +169,18 @@ /// Return true if we can prove that the specified FP value is either a NaN or /// never less than 0.0. + /// If \p IncludeNeg0 is false, -0.0 is considered less than 0.0. bool CannotBeOrderedLessThanZero(const Value *V, const TargetLibraryInfo *TLI, + bool IncludeNeg0 = true, unsigned Depth = 0); + /// \returns true if we can prove that the specified FP value has a 0 sign + /// bit. + inline bool CannotBeNegative(const Value *V, const TargetLibraryInfo *TLI, + unsigned Depth = 0) { + return CannotBeOrderedLessThanZero(V, TLI, false, Depth); + } + /// 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, i16 0xF0F0, double Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -4288,10 +4288,21 @@ return nullptr; // Unary Ops - if (NumOperands == 1) - if (IntrinsicInst *II = dyn_cast(*ArgBegin)) + if (NumOperands == 1) { + if (IntrinsicInst *II = dyn_cast(*ArgBegin)) { if (II->getIntrinsicID() == IID) return II; + } + + switch (IID) { + case Intrinsic::fabs: { + if (CannotBeNegative(*ArgBegin, Q.TLI)) + return *ArgBegin; + } + default: + break; + } + } return nullptr; } Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -2585,21 +2585,26 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, const TargetLibraryInfo *TLI, + bool IncludeNeg0, unsigned Depth) { - if (const ConstantFP *CFP = dyn_cast(V)) - return !CFP->getValueAPF().isNegative() || CFP->getValueAPF().isZero(); + if (const ConstantFP *CFP = dyn_cast(V)) { + return !CFP->getValueAPF().isNegative() || + (IncludeNeg0 && CFP->getValueAPF().isZero()); + } // FIXME: Magic number! At the least, this should be given a name because it's // used similarly in CannotBeNegativeZero(). A better fix may be to // expose it as a parameter, so it can be used for testing / experimenting. if (Depth == MaxDepth) - return false; // Limit search depth. + return false; // Limit search depth. const Operator *I = dyn_cast(V); - if (!I) return false; + if (!I) + return false; switch (I->getOpcode()) { - default: break; + default: + break; // Unsigned integers are always nonnegative. case Instruction::UIToFP: return true; @@ -2611,26 +2616,35 @@ case Instruction::FAdd: case Instruction::FDiv: case Instruction::FRem: - return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1) && - CannotBeOrderedLessThanZero(I->getOperand(1), TLI, Depth + 1); + return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, IncludeNeg0, + Depth + 1) && + CannotBeOrderedLessThanZero(I->getOperand(1), TLI, IncludeNeg0, + Depth + 1); case Instruction::Select: - return CannotBeOrderedLessThanZero(I->getOperand(1), TLI, Depth + 1) && - CannotBeOrderedLessThanZero(I->getOperand(2), TLI, Depth + 1); + return CannotBeOrderedLessThanZero(I->getOperand(1), TLI, IncludeNeg0, + Depth + 1) && + CannotBeOrderedLessThanZero(I->getOperand(2), TLI, IncludeNeg0, + Depth + 1); case Instruction::FPExt: case Instruction::FPTrunc: // Widening/narrowing never change sign. - return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1); + return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, IncludeNeg0, + Depth + 1); case Instruction::Call: Intrinsic::ID IID = getIntrinsicForCallSite(cast(I), TLI); switch (IID) { default: break; case Intrinsic::maxnum: - return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1) || - CannotBeOrderedLessThanZero(I->getOperand(1), TLI, Depth + 1); + return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, IncludeNeg0, + Depth + 1) || + CannotBeOrderedLessThanZero(I->getOperand(1), TLI, IncludeNeg0, + Depth + 1); case Intrinsic::minnum: - return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1) && - CannotBeOrderedLessThanZero(I->getOperand(1), TLI, Depth + 1); + return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, IncludeNeg0, + Depth + 1) && + CannotBeOrderedLessThanZero(I->getOperand(1), TLI, IncludeNeg0, + Depth + 1); case Intrinsic::exp: case Intrinsic::exp2: case Intrinsic::fabs: @@ -2642,12 +2656,14 @@ if (CI->getBitWidth() <= 64 && CI->getSExtValue() % 2u == 0) return true; } - return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1); + return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, IncludeNeg0, + Depth + 1); case Intrinsic::fma: case Intrinsic::fmuladd: // x*x+y is non-negative if y is non-negative. return I->getOperand(0) == I->getOperand(1) && - CannotBeOrderedLessThanZero(I->getOperand(2), TLI, Depth + 1); + CannotBeOrderedLessThanZero(I->getOperand(2), TLI, IncludeNeg0, + Depth + 1); } break; } Index: test/Transforms/InstSimplify/floating-point-arithmetic.ll =================================================================== --- test/Transforms/InstSimplify/floating-point-arithmetic.ll +++ test/Transforms/InstSimplify/floating-point-arithmetic.ll @@ -103,3 +103,95 @@ ret float %7 } +declare float @llvm.fabs.f32(float) + +; CHECK-LABEL: @fabs_select_positive_constants( +; CHECK: %select = select i1 %cmp, float 1.000000e+00, float 2.000000e+00 +; CHECK-NEXT: ret float %select +define float @fabs_select_positive_constants(i32 %c) { + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 1.0, float 2.0 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +; CHECK-LABEL: @fabs_select_constant_variable( +; CHECK: %select = select i1 %cmp, float 1.000000e+00, float %x +; CHECK-NEXT: %fabs = call float @llvm.fabs.f32(float %select) +define float @fabs_select_constant_variable(i32 %c, float %x) { + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 1.0, float %x + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +; CHECK-LABEL: @fabs_select_neg0_pos0( +; CHECK: %select = select i1 %cmp, float -0.000000e+00, float 0.000000e+00 +; CHECK: %fabs = call float @llvm.fabs.f32(float %select) +; CHECK-NEXT: ret float %fabs +define float @fabs_select_neg0_pos0(float addrspace(1)* %out, i32 %c) { + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float -0.0, float 0.0 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +; CHECK-LABEL: @fabs_select_neg0_neg1( +; CHECK: %select = select i1 %cmp, float -0.000000e+00, float -1.000000e+00 +; CHECK: %fabs = call float @llvm.fabs.f32(float %select) +define float @fabs_select_neg0_neg1(float addrspace(1)* %out, i32 %c) { + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float -0.0, float -1.0 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +; CHECK-LABEL: @fabs_select_nan_nan( +; CHECK: %select = select i1 %cmp, float 0x7FF8000000000000, float 0x7FF8000100000000 +; CHECK-NEXT: ret float %select +define float @fabs_select_nan_nan(float addrspace(1)* %out, i32 %c) { + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 0x7FF8000000000000, float 0x7FF8000100000000 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +; CHECK-LABEL: @fabs_select_negnan_nan( +; CHECK: %select = select i1 %cmp, float 0xFFF8000000000000, float 0x7FF8000000000000 +; CHECK: %fabs = call float @llvm.fabs.f32(float %select) +define float @fabs_select_negnan_nan(float addrspace(1)* %out, i32 %c) { + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 0xFFF8000000000000, float 0x7FF8000000000000 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +; CHECK-LABEL: @fabs_select_negnan_negnan( +; CHECK: %select = select i1 %cmp, float 0xFFF8000000000000, float 0x7FF8000100000000 +; CHECK: %fabs = call float @llvm.fabs.f32(float %select) +define float @fabs_select_negnan_negnan(float addrspace(1)* %out, i32 %c) { + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 0xFFF8000000000000, float 0x7FF8000100000000 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +; CHECK-LABEL: @fabs_select_negnan_negzero( +; CHECK: %select = select i1 %cmp, float 0xFFF8000000000000, float -0.000000e+00 +; CHECK: %fabs = call float @llvm.fabs.f32(float %select) +define float @fabs_select_negnan_negzero(float addrspace(1)* %out, i32 %c) { + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 0xFFF8000000000000, float -0.0 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +; CHECK-LABEL: @fabs_select_negnan_zero( +; CHECK: %select = select i1 %cmp, float 0xFFF8000000000000, float 0.000000e+00 +; CHECK: %fabs = call float @llvm.fabs.f32(float %select) +define float @fabs_select_negnan_zero(float addrspace(1)* %out, i32 %c) { + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 0xFFF8000000000000, float 0.0 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +}