Index: llvm/include/llvm/Analysis/ValueTracking.h =================================================================== --- llvm/include/llvm/Analysis/ValueTracking.h +++ llvm/include/llvm/Analysis/ValueTracking.h @@ -288,7 +288,8 @@ return isKnownNever(fcZero); } - /// Return true if it's known this can never be a literal negative zero. + /// Return true if it's known this can never be a negative zero. This means a + /// literal -0 and does not include denormal inputs implicitly treated as -0. bool isKnownNeverNegZero() const { return isKnownNever(fcNegZero); } @@ -414,9 +415,19 @@ /// Return true if we can prove that the specified FP value is never equal to /// -0.0. -bool CannotBeNegativeZero(const Value *V, const TargetLibraryInfo *TLI, - unsigned Depth = 0); - +/// FIXME: This mishandles PreserveSign denormals-are-zero cases. +inline bool cannotBeNegativeZero(const Value *V, const DataLayout &DL, + const TargetLibraryInfo *TLI = nullptr, + unsigned Depth = 0, + AssumptionCache *AC = nullptr, + const Instruction *CtxI = nullptr, + const DominatorTree *DT = nullptr, + OptimizationRemarkEmitter *ORE = nullptr, + bool UseInstrInfo = true) { + KnownFPClass Known = computeKnownFPClass(V, DL, fcNegZero, Depth, TLI, AC, + CtxI, DT, ORE, UseInstrInfo); + return Known.isKnownNeverNegZero(); +} /// Return true if we can prove that the specified FP value is either NaN or /// never less than -0.0. /// Index: llvm/lib/Analysis/InstructionSimplify.cpp =================================================================== --- llvm/lib/Analysis/InstructionSimplify.cpp +++ llvm/lib/Analysis/InstructionSimplify.cpp @@ -5514,7 +5514,7 @@ // fadd X, 0 ==> X, when we know X is not -0 if (canIgnoreSNaN(ExBehavior, FMF)) if (match(Op1, m_PosZeroFP()) && - (FMF.noSignedZeros() || CannotBeNegativeZero(Op0, Q.TLI))) + (FMF.noSignedZeros() || cannotBeNegativeZero(Op0, Q.DL, Q.TLI))) return Op0; if (!isDefaultFPEnvironment(ExBehavior, Rounding)) @@ -5576,7 +5576,7 @@ // fsub X, -0 ==> X, when we know X is not -0 if (canIgnoreSNaN(ExBehavior, FMF)) if (match(Op1, m_NegZeroFP()) && - (FMF.noSignedZeros() || CannotBeNegativeZero(Op0, Q.TLI))) + (FMF.noSignedZeros() || cannotBeNegativeZero(Op0, Q.DL, Q.TLI))) return Op0; // fsub -0.0, (fsub -0.0, X) ==> X Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -3650,61 +3650,6 @@ return Intrinsic::not_intrinsic; } -/// Return true if we can prove that the specified FP value is never equal to -/// -0.0. -/// NOTE: Do not check 'nsz' here because that fast-math-flag does not guarantee -/// that a value is not -0.0. It only guarantees that -0.0 may be treated -/// the same as +0.0 in floating-point ops. -bool llvm::CannotBeNegativeZero(const Value *V, const TargetLibraryInfo *TLI, - unsigned Depth) { - if (auto *CFP = dyn_cast(V)) - return !CFP->getValueAPF().isNegZero(); - - if (Depth == MaxAnalysisRecursionDepth) - return false; - - auto *Op = dyn_cast(V); - if (!Op) - return false; - - // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0. - if (match(Op, m_FAdd(m_Value(), m_PosZeroFP()))) - return true; - - // sitofp and uitofp turn into +0.0 for zero. - if (isa(Op) || isa(Op)) - return true; - - if (auto *Call = dyn_cast(Op)) { - Intrinsic::ID IID = getIntrinsicForCallSite(*Call, TLI); - switch (IID) { - default: - break; - // sqrt(-0.0) = -0.0, no other negative results are possible. - case Intrinsic::sqrt: - case Intrinsic::canonicalize: - return CannotBeNegativeZero(Call->getArgOperand(0), TLI, Depth + 1); - case Intrinsic::experimental_constrained_sqrt: { - // NOTE: This rounding mode restriction may be too strict. - const auto *CI = cast(Call); - if (CI->getRoundingMode() == RoundingMode::NearestTiesToEven) - return CannotBeNegativeZero(Call->getArgOperand(0), TLI, Depth + 1); - else - return false; - } - // fabs(x) != -0.0 - case Intrinsic::fabs: - return true; - // sitofp and uitofp turn into +0.0 for zero. - case Intrinsic::experimental_constrained_sitofp: - case Intrinsic::experimental_constrained_uitofp: - return true; - } - } - - return false; -} - /// If \p SignBitOnly is true, test for a known 0 sign bit rather than a /// standard ordered compare. e.g. make -0.0 olt 0.0 be true because of the sign /// bit despite comparing equal. @@ -3857,8 +3802,9 @@ // 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)); + return CI->hasNoNaNs() && + (CI->hasNoSignedZeros() || + cannotBeNegativeZero(CI->getOperand(0), DL, TLI)); case Intrinsic::powi: if (ConstantInt *Exponent = dyn_cast(I->getOperand(1))) { @@ -4170,8 +4116,7 @@ computeKnownFPClass(V, DemandedElts, InterestedClasses, Known, Depth, Q, TLI); } -// TODO: Merge implementations of CannotBeNegativeZero, -// cannotBeOrderedLessThanZero into here. +// TODO: Merge implementation of cannotBeOrderedLessThanZero into here. void computeKnownFPClass(const Value *V, const APInt &DemandedElts, FPClassTest InterestedClasses, KnownFPClass &Known, unsigned Depth, const Query &Q, Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2618,7 +2618,7 @@ // Note that if this fsub was really an fneg, the fadd with -0.0 will get // killed later. We still limit that particular transform with 'hasOneUse' // because an fneg is assumed better/cheaper than a generic fsub. - if (I.hasNoSignedZeros() || CannotBeNegativeZero(Op0, SQ.TLI)) { + if (I.hasNoSignedZeros() || cannotBeNegativeZero(Op0, SQ.DL, SQ.TLI)) { if (match(Op1, m_OneUse(m_FSub(m_Value(X), m_Value(Y))))) { Value *NewSub = Builder.CreateFSubFMF(Y, X, &I); return BinaryOperator::CreateFAddFMF(Op0, NewSub, &I); Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -98,7 +98,8 @@ // +0.0 compares equal to -0.0, and so it does not behave as required for this // transform. Bail out if we can not exclude that possibility. if (isa(BO)) - if (!BO->hasNoSignedZeros() && !CannotBeNegativeZero(Y, &TLI)) + if (!BO->hasNoSignedZeros() && + !cannotBeNegativeZero(Y, IC.getDataLayout(), &TLI)) return nullptr; // BO = binop Y, X Index: llvm/test/Transforms/InstSimplify/strictfp-sqrt-nonneg.ll =================================================================== --- llvm/test/Transforms/InstSimplify/strictfp-sqrt-nonneg.ll +++ llvm/test/Transforms/InstSimplify/strictfp-sqrt-nonneg.ll @@ -88,8 +88,7 @@ ; CHECK-LABEL: @nonneg_u_downward( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] ; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[SQRA]] ; %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.downward", metadata !"fpexcept.ignore") #0 %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.downward", metadata !"fpexcept.ignore") #0 @@ -102,8 +101,7 @@ ; CHECK-LABEL: @nonneg_s_downward( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] ; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[SQRA]] ; %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.downward", metadata !"fpexcept.ignore") #0 %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.downward", metadata !"fpexcept.ignore") #0 @@ -116,8 +114,7 @@ ; CHECK-LABEL: @nonneg_u_upward( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] ; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[SQRA]] ; %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.upward", metadata !"fpexcept.ignore") #0 %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.upward", metadata !"fpexcept.ignore") #0 @@ -130,8 +127,7 @@ ; CHECK-LABEL: @nonneg_s_upward( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] ; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[SQRA]] ; %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.upward", metadata !"fpexcept.ignore") #0 %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.upward", metadata !"fpexcept.ignore") #0 @@ -144,8 +140,7 @@ ; CHECK-LABEL: @nonneg_u_towardzero( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] ; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[SQRA]] ; %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 @@ -158,8 +153,7 @@ ; CHECK-LABEL: @nonneg_s_towardzero( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] ; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[SQRA]] ; %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 @@ -172,8 +166,7 @@ ; CHECK-LABEL: @nonneg_u_tonearestaway( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] ; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[SQRA]] ; %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #0 %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #0 @@ -186,8 +179,7 @@ ; CHECK-LABEL: @nonneg_s_tonearestaway( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] ; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[SQRA]] ; %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #0 %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #0 @@ -200,8 +192,7 @@ ; CHECK-LABEL: @nonneg_u_dynamic( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] ; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[SQRA]] ; %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 @@ -214,8 +205,7 @@ ; CHECK-LABEL: @nonneg_s_dynamic( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] ; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[SQRA]] ; %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0