aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/ValueTracking.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis/ValueTracking.cpp')
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp55
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;