[llvm] ValueTracking: Refactor computeKnownFPClass select handling (PR #174957)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 8 04:07:40 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Matt Arsenault (arsenm)
<details>
<summary>Changes</summary>
Match the structure of ComputeKnownBits. Expose the condition
handling as a utility function so SimplifyDemanedFPClass can make
use of this. Avoids some redundant code and improves accuracy in
at least one case.
---
Full diff: https://github.com/llvm/llvm-project/pull/174957.diff
4 Files Affected:
- (modified) llvm/include/llvm/Analysis/ValueTracking.h (+11)
- (modified) llvm/include/llvm/Support/KnownFPClass.h (+7-1)
- (modified) llvm/lib/Analysis/ValueTracking.cpp (+23-49)
- (modified) llvm/test/Transforms/Attributor/nofpclass-select.ll (+2-2)
``````````diff
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index b730a36488780..2ce49c558b241 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -116,6 +116,13 @@ LLVM_ABI void adjustKnownBitsForSelectArm(KnownBits &Known, Value *Cond,
const SimplifyQuery &Q,
unsigned Depth = 0);
+/// Adjust \p Known for the given select \p Arm to include information from the
+/// select \p Cond.
+LLVM_ABI void adjustKnownFPClassForSelectArm(KnownFPClass &Known, Value *Cond,
+ Value *Arm, bool Invert,
+ const SimplifyQuery &Q,
+ unsigned Depth = 0);
+
/// Return true if LHS and RHS have no common bits set.
LLVM_ABI bool haveNoCommonBitsSet(const WithCache<const Value *> &LHSCache,
const WithCache<const Value *> &RHSCache,
@@ -231,6 +238,10 @@ LLVM_ABI Intrinsic::ID getIntrinsicForCallSite(const CallBase &CB,
LLVM_ABI bool isSignBitCheck(ICmpInst::Predicate Pred, const APInt &RHS,
bool &TrueIfSigned);
+LLVM_ABI KnownFPClass analyzeKnownFPClassFromSelect(
+ const Instruction *I, const KnownFPClass &KnownLHS,
+ const KnownFPClass &KnownRHS, const SimplifyQuery &SQ, unsigned Depth = 0);
+
/// Determine which floating-point classes are valid for \p V, and return them
/// in KnownFPClass bit sets.
///
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index a3a485a961877..d140b4712c180 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -29,7 +29,8 @@ struct KnownFPClass {
/// definitely set or false if the sign bit is definitely unset.
std::optional<bool> SignBit;
- KnownFPClass() = default;
+ KnownFPClass(FPClassTest Known = fcAllFlags, std::optional<bool> Sign = {})
+ : KnownFPClasses(Known), SignBit(Sign) {}
KnownFPClass(const APFloat &C);
bool operator==(KnownFPClass Other) const {
@@ -135,6 +136,11 @@ struct KnownFPClass {
return isKnownNever(fcPositive) && isKnownNeverLogicalNegZero(Mode);
}
+ KnownFPClass intersectWith(const KnownFPClass &RHS) {
+ return KnownFPClass(~(~KnownFPClasses & ~RHS.KnownFPClasses),
+ SignBit == RHS.SignBit ? SignBit : std::nullopt);
+ }
+
KnownFPClass &operator|=(const KnownFPClass &RHS) {
KnownFPClasses = KnownFPClasses | RHS.KnownFPClasses;
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 77bb3be7bdb72..43f514b4b735d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4868,6 +4868,17 @@ static KnownFPClass computeKnownFPClassFromContext(const Value *V,
return KnownFromContext;
}
+void llvm::adjustKnownFPClassForSelectArm(KnownFPClass &Known, Value *Cond,
+ Value *Arm, bool Invert,
+ const SimplifyQuery &SQ,
+ unsigned Depth) {
+ computeKnownFPClassFromCond(Arm, Cond,
+ /*CondIsTrue=*/!Invert, SQ.CxtI, Known,
+ Depth + 1);
+ // TODO: Do we need to check isGuaranteedNotToBeUndef, like the KnownBits
+ // case?
+}
+
void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
FPClassTest InterestedClasses, KnownFPClass &Known,
const SimplifyQuery &Q, unsigned Depth);
@@ -5040,55 +5051,18 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
break;
}
case Instruction::Select: {
- Value *Cond = Op->getOperand(0);
- Value *LHS = Op->getOperand(1);
- Value *RHS = Op->getOperand(2);
-
- FPClassTest FilterLHS = fcAllFlags;
- FPClassTest FilterRHS = fcAllFlags;
-
- Value *TestedValue = nullptr;
- FPClassTest MaskIfTrue = fcAllFlags;
- FPClassTest MaskIfFalse = fcAllFlags;
- uint64_t ClassVal = 0;
- const Function *F = cast<Instruction>(Op)->getFunction();
- CmpPredicate Pred;
- Value *CmpLHS, *CmpRHS;
- if (F && match(Cond, m_FCmp(Pred, m_Value(CmpLHS), m_Value(CmpRHS)))) {
- // If the select filters out a value based on the class, it no longer
- // participates in the class of the result
-
- // TODO: In some degenerate cases we can infer something if we try again
- // without looking through sign operations.
- bool LookThroughFAbsFNeg = CmpLHS != LHS && CmpLHS != RHS;
- std::tie(TestedValue, MaskIfTrue, MaskIfFalse) =
- fcmpImpliesClass(Pred, *F, CmpLHS, CmpRHS, LookThroughFAbsFNeg);
- } else if (match(Cond,
- m_Intrinsic<Intrinsic::is_fpclass>(
- m_Value(TestedValue), m_ConstantInt(ClassVal)))) {
- FPClassTest TestedMask = static_cast<FPClassTest>(ClassVal);
- MaskIfTrue = TestedMask;
- MaskIfFalse = ~TestedMask;
- }
-
- if (TestedValue == LHS) {
- // match !isnan(x) ? x : y
- FilterLHS = MaskIfTrue;
- } else if (TestedValue == RHS) { // && IsExactClass
- // match !isnan(x) ? y : x
- FilterRHS = MaskIfFalse;
- }
-
- KnownFPClass Known2;
- computeKnownFPClass(LHS, DemandedElts, InterestedClasses & FilterLHS, Known,
- Q, Depth + 1);
- Known.KnownFPClasses &= FilterLHS;
-
- computeKnownFPClass(RHS, DemandedElts, InterestedClasses & FilterRHS,
- Known2, Q, Depth + 1);
- Known2.KnownFPClasses &= FilterRHS;
-
- Known |= Known2;
+ auto ComputeForArm = [&](Value *Arm, bool Invert) {
+ KnownFPClass Res;
+ computeKnownFPClass(Arm, DemandedElts, InterestedClasses, Res, Q,
+ Depth + 1);
+ adjustKnownFPClassForSelectArm(Res, Op->getOperand(0), Arm, Invert, Q,
+ Depth);
+ return Res;
+ };
+ // Only known if known in both the LHS and RHS.
+ Known =
+ ComputeForArm(Op->getOperand(1), /*Invert=*/false)
+ .intersectWith(ComputeForArm(Op->getOperand(2), /*Invert=*/true));
break;
}
case Instruction::Call: {
diff --git a/llvm/test/Transforms/Attributor/nofpclass-select.ll b/llvm/test/Transforms/Attributor/nofpclass-select.ll
index 3a8847590ce79..c9c995b9fb8bb 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-select.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-select.ll
@@ -265,7 +265,7 @@ define float @clamp_only_denormal_or_zero(float %arg) {
}
define float @clamp_inf_to_fabs(float %arg) {
-; CHECK-LABEL: define float @clamp_inf_to_fabs
+; CHECK-LABEL: define nofpclass(ninf) float @clamp_inf_to_fabs
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_INF:%.*]] = fcmp oeq float [[FABS]], 0x7FF0000000000000
@@ -279,7 +279,7 @@ define float @clamp_inf_to_fabs(float %arg) {
}
define float @not_clamp_inf_to_fabs(float %arg) {
-; CHECK-LABEL: define float @not_clamp_inf_to_fabs
+; CHECK-LABEL: define nofpclass(nzero nsub nnorm) float @not_clamp_inf_to_fabs
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: [[IS_INF:%.*]] = fcmp oeq float [[FABS]], 0x7FF0000000000000
``````````
</details>
https://github.com/llvm/llvm-project/pull/174957
More information about the llvm-commits
mailing list