From c4281fd5af49229376e33726730b308a6fa81032 Mon Sep 17 00:00:00 2001 From: Max Graey Date: Mon, 6 Apr 2026 17:23:20 +0300 Subject: [PATCH] [Support][ValueTraking] Improve KnownFPClass for fadd. Handle infinity signs (#190559) Improve KnownFPClass reasoning for fadd: - Refine NaN handling for infinities by checking opposite-sign cases: - `-inf` + `+inf` --> `nan` - `+inf` + `-inf` --> `nan` - `+inf` + `+inf` --> `+inf` - `-inf` + `-inf` --> `-inf` - Introduce `cannotBeOrderedLessEqZero` as pair to `cannotBeOrderedGreaterEqZero`. --- llvm/include/llvm/Support/KnownFPClass.h | 11 +++++ llvm/lib/Support/KnownFPClass.cpp | 7 +-- llvm/test/Transforms/Attributor/nofpclass.ll | 44 +++++++++++++++++++ .../simplify-demanded-fpclass-fadd.ll | 4 +- .../InstSimplify/known-never-nan.ll | 5 +-- 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h index c48e0f8b7b65..8986d4b17c85 100644 --- a/llvm/include/llvm/Support/KnownFPClass.h +++ b/llvm/include/llvm/Support/KnownFPClass.h @@ -127,6 +127,17 @@ struct KnownFPClass { return isKnownNever(OrderedGreaterThanZeroMask); } + /// Return true if it's known this can never be a positive value or a logical + /// 0. + /// + /// NaN --> true + /// x <= +0 --> false + /// psub --> true if mode is ieee, false otherwise. + /// x > +0 --> true + bool cannotBeOrderedLessEqZero(DenormalMode Mode) const { + return isKnownNever(fcNegative) && isKnownNeverLogicalPosZero(Mode); + } + /// Return true if it's know this can never be a negative value or a logical /// 0. /// diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp index 4f704eabfc6e..56da9880c733 100644 --- a/llvm/lib/Support/KnownFPClass.cpp +++ b/llvm/lib/Support/KnownFPClass.cpp @@ -292,10 +292,11 @@ static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS, const KnownFPClass &KnownRHS, DenormalMode Mode) { KnownFPClass Known; - // Adding positive and negative infinity produces NaN. - // TODO: Check sign of infinities. + // Adding positive and negative infinity produces NaN, but only if both + // opposite-sign infinity combinations are possible. if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() && - (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity())) + (KnownLHS.isKnownNever(fcPosInf) || KnownRHS.isKnownNever(fcNegInf)) && + (KnownLHS.isKnownNever(fcNegInf) || KnownRHS.isKnownNever(fcPosInf))) Known.knownNot(fcNan); if (KnownLHS.cannotBeOrderedLessThanZero() && diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll index efe0d7a0a092..df1f4d11479e 100644 --- a/llvm/test/Transforms/Attributor/nofpclass.ll +++ b/llvm/test/Transforms/Attributor/nofpclass.ll @@ -2297,6 +2297,50 @@ define float @fadd_known_positive_daz(float nofpclass(ninf nsub nnorm) %arg0, fl ret float %add } +define float @test_fadd_no_nan_from_no_ninf(float nofpclass(nan ninf) %arg0, float nofpclass(nan ninf) %arg1) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nan) float @test_fadd_no_nan_from_no_ninf +; CHECK-SAME: (float nofpclass(nan ninf) [[ARG0:%.*]], float nofpclass(nan ninf) [[ARG1:%.*]]) #[[ATTR:[0-9]+]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @test_fadd_no_nan_from_no_pinf(float nofpclass(nan pinf) %arg0, float nofpclass(nan pinf) %arg1) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nan) float @test_fadd_no_nan_from_no_pinf +; CHECK-SAME: (float nofpclass(nan pinf) [[ARG0:%.*]], float nofpclass(nan pinf) [[ARG1:%.*]]) #[[ATTR:[0-9]+]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @test_fadd_may_nan_from_no_pinf_no_ninf(float nofpclass(nan pinf) %arg0, float nofpclass(nan ninf) %arg1) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @test_fadd_may_nan_from_no_pinf_no_ninf +; CHECK-SAME: (float nofpclass(nan pinf) [[ARG0:%.*]], float nofpclass(nan ninf) [[ARG1:%.*]]) #[[ATTR:[0-9]+]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + +define float @test_fadd_may_nan_from_no_ninf_no_pinf(float nofpclass(nan ninf) %arg0, float nofpclass(nan pinf) %arg1) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define float @test_fadd_may_nan_from_no_ninf_no_pinf +; CHECK-SAME: (float nofpclass(nan ninf) [[ARG0:%.*]], float nofpclass(nan pinf) [[ARG1:%.*]]) #[[ATTR:[0-9]+]] { +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[ADD]] +; + %add = fadd float %arg0, %arg1 + ret float %add +} + define float @fadd_known_positive_nzero_lhs(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm) %arg1) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fadd_known_positive_nzero_lhs diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fadd.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fadd.ll index eee3405e9b8c..b7338f435531 100644 --- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fadd.ll +++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fadd.ll @@ -490,7 +490,7 @@ define nofpclass(nzero) half @inferred_nan_output__fadd__no_pinf_no_nan__no_nan( define nofpclass(nzero) half @inferred_nan_output__fadd__no_pinf_no_nan__no_pinf_no_nan(half nofpclass(nan pinf) %x, half nofpclass(nan pinf) %y) { ; CHECK-LABEL: define nofpclass(nzero) half @inferred_nan_output__fadd__no_pinf_no_nan__no_pinf_no_nan( ; CHECK-SAME: half nofpclass(nan pinf) [[X:%.*]], half nofpclass(nan pinf) [[Y:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = fadd half [[X]], [[Y]] +; CHECK-NEXT: [[ADD:%.*]] = fadd nnan half [[X]], [[Y]] ; CHECK-NEXT: ret half [[ADD]] ; %add = fadd half %x, %y @@ -500,7 +500,7 @@ define nofpclass(nzero) half @inferred_nan_output__fadd__no_pinf_no_nan__no_pinf define nofpclass(nzero) half @inferred_nan_output__fadd__no_ninf_no_nan__no_ninf_no_nan(half nofpclass(nan ninf) %x, half nofpclass(nan ninf) %y) { ; CHECK-LABEL: define nofpclass(nzero) half @inferred_nan_output__fadd__no_ninf_no_nan__no_ninf_no_nan( ; CHECK-SAME: half nofpclass(nan ninf) [[X:%.*]], half nofpclass(nan ninf) [[Y:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = fadd half [[X]], [[Y]] +; CHECK-NEXT: [[ADD:%.*]] = fadd nnan half [[X]], [[Y]] ; CHECK-NEXT: ret half [[ADD]] ; %add = fadd half %x, %y diff --git a/llvm/test/Transforms/InstSimplify/known-never-nan.ll b/llvm/test/Transforms/InstSimplify/known-never-nan.ll index 907eca0a856a..98c873ac8a3d 100644 --- a/llvm/test/Transforms/InstSimplify/known-never-nan.ll +++ b/llvm/test/Transforms/InstSimplify/known-never-nan.ll @@ -340,10 +340,7 @@ define i1 @uitofp_add(i32 %arg0) { define i1 @uitofp_add_big(i1024 %arg0) { ; CHECK-LABEL: @uitofp_add_big( -; CHECK-NEXT: [[OP:%.*]] = uitofp i1024 [[ARG0:%.*]] to double -; CHECK-NEXT: [[ADD:%.*]] = fadd double [[OP]], [[OP]] -; CHECK-NEXT: [[TMP:%.*]] = fcmp ord double [[ADD]], [[ADD]] -; CHECK-NEXT: ret i1 [[TMP]] +; CHECK-NEXT: ret i1 true ; %op = uitofp i1024 %arg0 to double %add = fadd double %op, %op