diff options
author | Matt Arsenault <Matthew.Arsenault@amd.com> | 2023-04-13 10:07:13 -0400 |
---|---|---|
committer | Matt Arsenault <arsenm2@gmail.com> | 2023-05-16 14:33:34 +0100 |
commit | c9f88e5bf027edcebd3ecbc2cebcda57887e04cf (patch) | |
tree | 1e712ac8eaf78b27c5aab4cdb4e94e56813115a0 /llvm/lib/Analysis/ValueTracking.cpp | |
parent | 44e99c75b7a83a302767fcf55805e4ef82b9baed (diff) | |
download | llvm-c9f88e5bf027edcebd3ecbc2cebcda57887e04cf.zip llvm-c9f88e5bf027edcebd3ecbc2cebcda57887e04cf.tar.gz llvm-c9f88e5bf027edcebd3ecbc2cebcda57887e04cf.tar.bz2 |
ValueTracking: fadd/fsub +0 cannot return -0
Copied from CannotBeNegativeZero and extended to cover fsub.
Diffstat (limited to 'llvm/lib/Analysis/ValueTracking.cpp')
-rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 7c2e98d..5947a68 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4300,6 +4300,13 @@ static bool inputDenormalIsIEEEOrPosZero(const Function &F, const Type *Ty) { Mode.Input == DenormalMode::PositiveZero; } +static bool outputDenormalIsIEEEOrPosZero(const Function &F, const Type *Ty) { + Ty = Ty->getScalarType(); + DenormalMode Mode = F.getDenormalMode(Ty->getFltSemantics()); + return Mode.Output == DenormalMode::IEEE || + Mode.Output == DenormalMode::PositiveZero; +} + bool KnownFPClass::isKnownNeverLogicalZero(const Function &F, Type *Ty) const { return isKnownNeverZero() && (isKnownNeverSubnormal() || inputDenormalIsIEEE(F, Ty)); @@ -4311,6 +4318,31 @@ bool KnownFPClass::isKnownNeverLogicalNegZero(const Function &F, (isKnownNeverNegSubnormal() || inputDenormalIsIEEEOrPosZero(F, Ty)); } +bool KnownFPClass::isKnownNeverLogicalPosZero(const Function &F, + Type *Ty) const { + if (!isKnownNeverPosZero()) + return false; + + // If we know there are no denormals, nothing can be flushed to zero. + if (isKnownNeverSubnormal()) + return true; + + DenormalMode Mode = F.getDenormalMode(Ty->getScalarType()->getFltSemantics()); + switch (Mode.Input) { + case DenormalMode::IEEE: + return true; + case DenormalMode::PreserveSign: + // Negative subnormal won't flush to +0 + return isKnownNeverPosSubnormal(); + case DenormalMode::PositiveZero: + default: + // Both positive and negative subnormal could flush to +0 + return false; + } + + llvm_unreachable("covered switch over denormal mode"); +} + /// Returns a pair of values, which if passed to llvm.is.fpclass, returns the /// same result as an fcmp with the given operands. std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred, @@ -5015,16 +5047,35 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, KnownFPClass KnownLHS, KnownRHS; computeKnownFPClass(Op->getOperand(1), DemandedElts, fcNan | fcInf, KnownRHS, Depth + 1, Q, TLI); - if (KnownRHS.isKnownNeverNaN()) { + + if (KnownRHS.isKnownNeverNaN() || KnownRHS.isKnownNeverNegZero() || + (Opc == Instruction::FSub && KnownRHS.isKnownNeverPosZero())) { // RHS is canonically cheaper to compute. Skip inspecting the LHS if // there's no point. computeKnownFPClass(Op->getOperand(0), DemandedElts, fcNan | fcInf, KnownLHS, Depth + 1, Q, TLI); // Adding positive and negative infinity produces NaN. // TODO: Check sign of infinities. - if (KnownLHS.isKnownNeverNaN() && + if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() && (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity())) Known.knownNot(fcNan); + + const Function *F = cast<Instruction>(Op)->getFunction(); + if (Op->getOpcode() == Instruction::FAdd) { + // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0. + if ((KnownLHS.isKnownNeverLogicalNegZero(*F, Op->getType()) || + KnownRHS.isKnownNeverLogicalNegZero(*F, Op->getType())) && + // Make sure output negative denormal can't flush to -0 + outputDenormalIsIEEEOrPosZero(*F, Op->getType())) + Known.knownNot(fcNegZero); + } else { + // Only fsub -0, +0 can return -0 + if ((KnownLHS.isKnownNeverLogicalNegZero(*F, Op->getType()) || + KnownRHS.isKnownNeverLogicalPosZero(*F, Op->getType())) && + // Make sure output negative denormal can't flush to -0 + outputDenormalIsIEEEOrPosZero(*F, Op->getType())) + Known.knownNot(fcNegZero); + } } break; |