[llvm] [IR] Handle fabs LHS in `fcmpImpliesClass` (PR #152913)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 10 06:04:28 PDT 2025
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/152913
>From 7ac29cb4c40f35a7a1bbccfaff021e1a0de7aa90 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 10 Aug 2025 19:50:14 +0800
Subject: [PATCH 1/3] [IR] Add pre-commit tests. NFC.
---
.../InstSimplify/floating-point-arithmetic.ll | 20 +++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll b/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll
index ab4448b460bfc..e79371b165f9c 100644
--- a/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll
+++ b/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll
@@ -213,7 +213,7 @@ define double @fmul_nnan_ninf_nneg_n0.0_commute(i127 %x) {
define float @fmul_ninf_nnan_mul_zero_nsz(float nofpclass(inf nan) %f) {
; CHECK-LABEL: @fmul_ninf_nnan_mul_zero_nsz(
-; CHECK-NEXT: ret float 0.000000e+00
+; CHECK-NEXT: ret float 0.000000e+00
;
%r = fmul nsz float %f, 0.0
ret float %r
@@ -221,7 +221,7 @@ define float @fmul_ninf_nnan_mul_zero_nsz(float nofpclass(inf nan) %f) {
define float @fmul_ninf_nnan_mul_nzero_nsz(float nofpclass(inf nan) %f) {
; CHECK-LABEL: @fmul_ninf_nnan_mul_nzero_nsz(
-; CHECK-NEXT: ret float 0.000000e+00
+; CHECK-NEXT: ret float 0.000000e+00
;
%r = fmul nsz float %f, -0.0
ret float %r
@@ -1255,3 +1255,19 @@ define i1 @fptrunc_round_unknown_positive(double %unknown) {
%cmp = fcmp nnan oge float %op, 0.0
ret i1 %cmp
}
+
+define half @fabs_select_fabs(half noundef %x) {
+; CHECK-LABEL: @fabs_select_fabs(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ABS1:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt half [[ABS1]], 0xH0000
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], half [[X]], half 0xH0000
+; CHECK-NEXT: ret half [[SEL]]
+;
+entry:
+ %abs1 = call half @llvm.fabs.f16(half %x)
+ %cmp = fcmp ogt half %abs1, 0xH0000
+ %sel = select i1 %cmp, half %x, half 0xH0000
+ %abs2 = call half @llvm.fabs.f16(half %sel)
+ ret half %abs2
+}
>From 2c6cad157f655736ea09c904a5883903ae5c6e47 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 10 Aug 2025 20:47:56 +0800
Subject: [PATCH 2/3] [IR] Handle fabs LHS in `fcmpImpliesClass`
---
.../IR/GenericFloatingPointPredicateUtils.h | 18 ++++++++--
.../InstSimplify/floating-point-arithmetic.ll | 3 +-
llvm/unittests/Analysis/ValueTrackingTest.cpp | 36 +++++++++++++++++++
3 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/IR/GenericFloatingPointPredicateUtils.h b/llvm/include/llvm/IR/GenericFloatingPointPredicateUtils.h
index 8aac9d5b49dbb..6c592adbd7333 100644
--- a/llvm/include/llvm/IR/GenericFloatingPointPredicateUtils.h
+++ b/llvm/include/llvm/IR/GenericFloatingPointPredicateUtils.h
@@ -151,26 +151,40 @@ template <typename ContextT> class GenericFloatingPointPredicateUtils {
case FCmpInst::FCMP_UNO:
return exactClass(Src, fcNan);
case FCmpInst::FCMP_OGT: // x > 0
+ if (IsFabs)
+ return exactClass(Src, fcSubnormal | fcNormal | fcInf);
return exactClass(Src, fcPosSubnormal | fcPosNormal | fcPosInf);
case FCmpInst::FCMP_UGT: // isnan(x) || x > 0
+ if (IsFabs)
+ return exactClass(Src, fcSubnormal | fcNormal | fcInf | fcNan);
return exactClass(Src, fcPosSubnormal | fcPosNormal | fcPosInf | fcNan);
case FCmpInst::FCMP_OGE: // x >= 0
+ if (IsFabs)
+ return exactClass(Src, ~fcNan);
return exactClass(Src, fcPositive | fcNegZero);
case FCmpInst::FCMP_UGE: // isnan(x) || x >= 0
+ if (IsFabs)
+ return exactClass(Src, fcAllFlags);
return exactClass(Src, fcPositive | fcNegZero | fcNan);
case FCmpInst::FCMP_OLT: // x < 0
+ if (IsFabs)
+ return exactClass(Src, fcNone);
return exactClass(Src, fcNegSubnormal | fcNegNormal | fcNegInf);
case FCmpInst::FCMP_ULT: // isnan(x) || x < 0
+ if (IsFabs)
+ return exactClass(Src, fcNan);
return exactClass(Src, fcNegSubnormal | fcNegNormal | fcNegInf | fcNan);
case FCmpInst::FCMP_OLE: // x <= 0
+ if (IsFabs)
+ return exactClass(Src, fcZero);
return exactClass(Src, fcNegative | fcPosZero);
case FCmpInst::FCMP_ULE: // isnan(x) || x <= 0
+ if (IsFabs)
+ return exactClass(Src, fcZero | fcNan);
return exactClass(Src, fcNegative | fcPosZero | fcNan);
default:
llvm_unreachable("all compare types are handled");
}
-
- return {Invalid, fcAllFlags, fcAllFlags};
}
const bool IsDenormalRHS = (OrigClass & fcSubnormal) == OrigClass;
diff --git a/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll b/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll
index e79371b165f9c..820fff433e9e0 100644
--- a/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll
+++ b/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll
@@ -1262,7 +1262,8 @@ define half @fabs_select_fabs(half noundef %x) {
; CHECK-NEXT: [[ABS1:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt half [[ABS1]], 0xH0000
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], half [[X]], half 0xH0000
-; CHECK-NEXT: ret half [[SEL]]
+; CHECK-NEXT: [[ABS2:%.*]] = call half @llvm.fabs.f16(half [[SEL]])
+; CHECK-NEXT: ret half [[ABS2]]
;
entry:
%abs1 = call half @llvm.fabs.f16(half %x)
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 6af20065213ac..559a0b724f383 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/FloatingPointPredicateUtils.h"
#include "llvm/AsmParser/Parser.h"
@@ -2208,6 +2209,41 @@ TEST_F(ComputeKnownFPClassTest, Constants) {
}
}
+TEST_F(ComputeKnownFPClassTest, fcmpImpliesClass_fabs_zero) {
+ parseAssembly("define float @test(float %x) {\n"
+ " %A = call float @llvm.fabs.f32(float %x)\n"
+ " ret float %A\n"
+ "}\n");
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_OEQ, *F, A, fcZero)),
+ fcZero);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_UEQ, *F, A, fcZero)),
+ fcZero | fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_UNE, *F, A, fcZero)),
+ ~fcZero);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_ONE, *F, A, fcZero)),
+ ~fcNan & ~fcZero);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_ORD, *F, A, fcZero)),
+ ~fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_UNO, *F, A, fcZero)),
+ fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_OGT, *F, A, fcZero)),
+ fcSubnormal | fcNormal | fcInf);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_UGT, *F, A, fcZero)),
+ fcSubnormal | fcNormal | fcInf | fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_OGE, *F, A, fcZero)),
+ ~fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_UGE, *F, A, fcZero)),
+ fcAllFlags);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_OLT, *F, A, fcZero)),
+ fcNone);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_ULT, *F, A, fcZero)),
+ fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_OLE, *F, A, fcZero)),
+ fcZero);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_ULE, *F, A, fcZero)),
+ fcZero | fcNan);
+}
+
TEST_F(ValueTrackingTest, isNonZeroRecurrence) {
parseAssembly(R"(
define i1 @test(i8 %n, i8 %r) {
>From 2d18613610c51bc192bf787af758564b4e4f1f78 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 10 Aug 2025 21:04:09 +0800
Subject: [PATCH 3/3] [IR] Use `llvm::invert_fabs`
---
.../IR/GenericFloatingPointPredicateUtils.h | 38 +++++++------------
1 file changed, 14 insertions(+), 24 deletions(-)
diff --git a/llvm/include/llvm/IR/GenericFloatingPointPredicateUtils.h b/llvm/include/llvm/IR/GenericFloatingPointPredicateUtils.h
index 6c592adbd7333..448a6e913eb86 100644
--- a/llvm/include/llvm/IR/GenericFloatingPointPredicateUtils.h
+++ b/llvm/include/llvm/IR/GenericFloatingPointPredicateUtils.h
@@ -135,6 +135,12 @@ template <typename ContextT> class GenericFloatingPointPredicateUtils {
if (Mode.Input != DenormalMode::IEEE)
return {Invalid, fcAllFlags, fcAllFlags};
+ auto ExactClass = [IsFabs, Src](FPClassTest Mask) {
+ if (IsFabs)
+ Mask = llvm::inverse_fabs(Mask);
+ return exactClass(Src, Mask);
+ };
+
switch (Pred) {
case FCmpInst::FCMP_OEQ: // Match x == 0.0
return exactClass(Src, fcZero);
@@ -151,37 +157,21 @@ template <typename ContextT> class GenericFloatingPointPredicateUtils {
case FCmpInst::FCMP_UNO:
return exactClass(Src, fcNan);
case FCmpInst::FCMP_OGT: // x > 0
- if (IsFabs)
- return exactClass(Src, fcSubnormal | fcNormal | fcInf);
- return exactClass(Src, fcPosSubnormal | fcPosNormal | fcPosInf);
+ return ExactClass(fcPosSubnormal | fcPosNormal | fcPosInf);
case FCmpInst::FCMP_UGT: // isnan(x) || x > 0
- if (IsFabs)
- return exactClass(Src, fcSubnormal | fcNormal | fcInf | fcNan);
- return exactClass(Src, fcPosSubnormal | fcPosNormal | fcPosInf | fcNan);
+ return ExactClass(fcPosSubnormal | fcPosNormal | fcPosInf | fcNan);
case FCmpInst::FCMP_OGE: // x >= 0
- if (IsFabs)
- return exactClass(Src, ~fcNan);
- return exactClass(Src, fcPositive | fcNegZero);
+ return ExactClass(fcPositive | fcNegZero);
case FCmpInst::FCMP_UGE: // isnan(x) || x >= 0
- if (IsFabs)
- return exactClass(Src, fcAllFlags);
- return exactClass(Src, fcPositive | fcNegZero | fcNan);
+ return ExactClass(fcPositive | fcNegZero | fcNan);
case FCmpInst::FCMP_OLT: // x < 0
- if (IsFabs)
- return exactClass(Src, fcNone);
- return exactClass(Src, fcNegSubnormal | fcNegNormal | fcNegInf);
+ return ExactClass(fcNegSubnormal | fcNegNormal | fcNegInf);
case FCmpInst::FCMP_ULT: // isnan(x) || x < 0
- if (IsFabs)
- return exactClass(Src, fcNan);
- return exactClass(Src, fcNegSubnormal | fcNegNormal | fcNegInf | fcNan);
+ return ExactClass(fcNegSubnormal | fcNegNormal | fcNegInf | fcNan);
case FCmpInst::FCMP_OLE: // x <= 0
- if (IsFabs)
- return exactClass(Src, fcZero);
- return exactClass(Src, fcNegative | fcPosZero);
+ return ExactClass(fcNegative | fcPosZero);
case FCmpInst::FCMP_ULE: // isnan(x) || x <= 0
- if (IsFabs)
- return exactClass(Src, fcZero | fcNan);
- return exactClass(Src, fcNegative | fcPosZero | fcNan);
+ return ExactClass(fcNegative | fcPosZero | fcNan);
default:
llvm_unreachable("all compare types are handled");
}
More information about the llvm-commits
mailing list