diff options
author | Alina Sbirlea <asbirlea@google.com> | 2023-05-18 21:48:01 -0700 |
---|---|---|
committer | Alina Sbirlea <asbirlea@google.com> | 2023-05-18 23:31:51 -0700 |
commit | d1dc3e13a791fe1b99a341406b5dafec64750cb1 (patch) | |
tree | b10b18f1d39d0b2d7ec6f59f49b43c0411685225 /llvm/lib/Analysis/ValueTracking.cpp | |
parent | b357f379c81811409348dd0e0273a248b055bb7a (diff) | |
download | llvm-d1dc3e13a791fe1b99a341406b5dafec64750cb1.zip llvm-d1dc3e13a791fe1b99a341406b5dafec64750cb1.tar.gz llvm-d1dc3e13a791fe1b99a341406b5dafec64750cb1.tar.bz2 |
Revert "ValueTracking: Delete body of isKnownNeverInfinity"
This reverts commit 73925ef8b0eacc6792f0e3ea21a3e6d51f5ee8b0.
Introduces test failures, mismatch inf/nan
Diffstat (limited to 'llvm/lib/Analysis/ValueTracking.cpp')
-rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 6a008c2..4cbba93 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4037,6 +4037,150 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, const DataLayout &DL, return cannotBeOrderedLessThanZeroImpl(V, DL, TLI, false, 0); } +bool llvm::isKnownNeverInfinity(const Value *V, const DataLayout &DL, + const TargetLibraryInfo *TLI, unsigned Depth, + AssumptionCache *AC, const Instruction *CtxI, + const DominatorTree *DT, + OptimizationRemarkEmitter *ORE, + bool UseInstrInfo) { + assert(V->getType()->isFPOrFPVectorTy() && "Querying for Inf on non-FP type"); + + // If we're told that infinities won't happen, assume they won't. + if (auto *FPMathOp = dyn_cast<FPMathOperator>(V)) + if (FPMathOp->hasNoInfs()) + return true; + + if (const auto *Arg = dyn_cast<Argument>(V)) { + if ((Arg->getNoFPClass() & fcInf) == fcInf) + return true; + } + + // TODO: Use fpclass like API for isKnown queries and distinguish +inf from + // -inf. + if (const auto *CB = dyn_cast<CallBase>(V)) { + if ((CB->getRetNoFPClass() & fcInf) == fcInf) + return true; + } + + // Handle scalar constants. + if (auto *CFP = dyn_cast<ConstantFP>(V)) + return !CFP->isInfinity(); + + if (Depth == MaxAnalysisRecursionDepth) + return false; + + if (auto *Inst = dyn_cast<Instruction>(V)) { + switch (Inst->getOpcode()) { + case Instruction::Select: { + return isKnownNeverInfinity(Inst->getOperand(1), DL, TLI, Depth + 1) && + isKnownNeverInfinity(Inst->getOperand(2), DL, TLI, Depth + 1); + } + case Instruction::SIToFP: + case Instruction::UIToFP: { + // Get width of largest magnitude integer (remove a bit if signed). + // This still works for a signed minimum value because the largest FP + // value is scaled by some fraction close to 2.0 (1.0 + 0.xxxx). + int IntSize = Inst->getOperand(0)->getType()->getScalarSizeInBits(); + if (Inst->getOpcode() == Instruction::SIToFP) + --IntSize; + + // If the exponent of the largest finite FP value can hold the largest + // integer, the result of the cast must be finite. + Type *FPTy = Inst->getType()->getScalarType(); + return ilogb(APFloat::getLargest(FPTy->getFltSemantics())) >= IntSize; + } + case Instruction::FNeg: + case Instruction::FPExt: { + // Peek through to source op. If it is not infinity, this is not infinity. + return isKnownNeverInfinity(Inst->getOperand(0), DL, TLI, Depth + 1); + } + case Instruction::FPTrunc: { + // Need a range check. + return false; + } + default: + break; + } + + if (const auto *II = dyn_cast<IntrinsicInst>(V)) { + switch (II->getIntrinsicID()) { + case Intrinsic::sin: + case Intrinsic::cos: + // Return NaN on infinite inputs. + return true; + case Intrinsic::fabs: + case Intrinsic::sqrt: + case Intrinsic::canonicalize: + case Intrinsic::copysign: + case Intrinsic::arithmetic_fence: + case Intrinsic::trunc: + return isKnownNeverInfinity(Inst->getOperand(0), DL, TLI, Depth + 1); + case Intrinsic::floor: + case Intrinsic::ceil: + case Intrinsic::rint: + case Intrinsic::nearbyint: + case Intrinsic::round: + case Intrinsic::roundeven: + // PPC_FP128 is a special case. + if (V->getType()->isMultiUnitFPType()) + return false; + return isKnownNeverInfinity(Inst->getOperand(0), DL, TLI, Depth + 1); + case Intrinsic::fptrunc_round: + // Requires knowing the value range. + return false; + case Intrinsic::minnum: + case Intrinsic::maxnum: + case Intrinsic::minimum: + case Intrinsic::maximum: + return isKnownNeverInfinity(Inst->getOperand(0), DL, TLI, Depth + 1) && + isKnownNeverInfinity(Inst->getOperand(1), DL, TLI, Depth + 1); + case Intrinsic::log: + case Intrinsic::log10: + case Intrinsic::log2: + // log(+inf) -> +inf + // log([+-]0.0) -> -inf + // log(-inf) -> nan + // log(-x) -> nan + // TODO: We lack API to check the == 0 case. + return false; + case Intrinsic::exp: + case Intrinsic::exp2: + case Intrinsic::pow: + case Intrinsic::powi: + case Intrinsic::fma: + case Intrinsic::fmuladd: + // These can return infinities on overflow cases, so it's hard to prove + // anything about it. + return false; + default: + break; + } + } + } + + // try to handle fixed width vector constants + auto *VFVTy = dyn_cast<FixedVectorType>(V->getType()); + if (VFVTy && isa<Constant>(V)) { + // For vectors, verify that each element is not infinity. + unsigned NumElts = VFVTy->getNumElements(); + for (unsigned i = 0; i != NumElts; ++i) { + Constant *Elt = cast<Constant>(V)->getAggregateElement(i); + if (!Elt) + return false; + if (isa<UndefValue>(Elt)) + continue; + auto *CElt = dyn_cast<ConstantFP>(Elt); + if (!CElt || CElt->isInfinity()) + return false; + } + // All elements were confirmed non-infinity or undefined. + return true; + } + + // was not able to prove that V never contains infinity + return false; +} + bool llvm::SignBitMustBeZero(const Value *V, const DataLayout &DL, const TargetLibraryInfo *TLI) { return cannotBeOrderedLessThanZeroImpl(V, DL, TLI, true, 0); |