[llvm] [DAG] computeKnownFPClass - add ISD::FCOPYSIGN handling (PR #193672)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 28 04:13:27 PDT 2026


https://github.com/RKSimon updated https://github.com/llvm/llvm-project/pull/193672

>From 1048f569791d38416cd7bb1dcce1e1b0e604537f Mon Sep 17 00:00:00 2001
From: xinlongchen <xinlongchen at tencent.com>
Date: Thu, 23 Apr 2026 14:10:53 +0800
Subject: [PATCH 1/4] [DAG] computeKnownFPClass - add ISD::FCOPYSIGN handling

---
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 88 +++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index 71621b8837d6b..addcaaa322c68 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -256,3 +256,91 @@ define <4 x i1> @fneg_vec_unknown_sign(<4 x i32> %vecbits) nounwind {
   %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %neg, i32 60) ; any negative
   ret <4 x i1> %res
 }
+
+define i1 @copysign_nan_mag_is_finite_or_inf(float %y) nounwind {
+; CHECK-LABEL: copysign_nan_mag_is_finite_or_inf:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lui a0, 523264
+; CHECK-NEXT:    fmv.w.x fa5, a0
+; CHECK-NEXT:    fsgnj.s fa5, fa5, fa0
+; CHECK-NEXT:    fclass.s a0, fa5
+; CHECK-NEXT:    zext.b a0, a0
+; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    ret
+  %r = call float @llvm.copysign.f32(float 0x7FF8000000000000, float %y)
+  %res = call i1 @llvm.is.fpclass.f32(float %r, i32 1020) ; 0x3FC = finite | inf
+  ret i1 %res
+}
+
+define i1 @copysign_zero_mag_isnan(float %y) nounwind {
+; CHECK-LABEL: copysign_zero_mag_isnan:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fmv.w.x fa5, zero
+; CHECK-NEXT:    fsgnj.s fa5, fa5, fa0
+; CHECK-NEXT:    fclass.s a0, fa5
+; CHECK-NEXT:    andi a0, a0, 768
+; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    ret
+  %r = call float @llvm.copysign.f32(float 0.0, float %y)
+  %res = call i1 @llvm.is.fpclass.f32(float %r, i32 3) ; 0x3 = nan
+  ret i1 %res
+}
+
+define i1 @copysign_inf_mag_isfinite_or_nan(float %y) nounwind {
+; CHECK-LABEL: copysign_inf_mag_isfinite_or_nan:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lui a0, 522240
+; CHECK-NEXT:    fmv.w.x fa5, a0
+; CHECK-NEXT:    fsgnj.s fa5, fa5, fa0
+; CHECK-NEXT:    fclass.s a0, fa5
+; CHECK-NEXT:    andi a0, a0, 894
+; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    ret
+  %r = call float @llvm.copysign.f32(float 0x7FF0000000000000, float %y)
+  %res = call i1 @llvm.is.fpclass.f32(float %r, i32 507) ; 0x1FB = finite (0x1F8) | nan (0x3)
+  ret i1 %res
+}
+
+define i1 @copysign_normal_mag_not_normal(float %y) nounwind {
+; CHECK-LABEL: copysign_normal_mag_not_normal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lui a0, 260096
+; CHECK-NEXT:    fmv.w.x fa5, a0
+; CHECK-NEXT:    fsgnj.s fa5, fa5, fa0
+; CHECK-NEXT:    fclass.s a0, fa5
+; CHECK-NEXT:    andi a0, a0, 957
+; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    ret
+  %r = call float @llvm.copysign.f32(float 1.0, float %y)
+  %res = call i1 @llvm.is.fpclass.f32(float %r, i32 759) ; 0x2F7 = all classes except +/-normal (0x108)
+  ret i1 %res
+}
+
+; fold-to-true test, not fold now
+define i1 @copysign_normal_mag_is_normal(float %y) nounwind {
+; CHECK-LABEL: copysign_normal_mag_is_normal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lui a0, 260096
+; CHECK-NEXT:    fmv.w.x fa5, a0
+; CHECK-NEXT:    fsgnj.s fa5, fa5, fa0
+; CHECK-NEXT:    fclass.s a0, fa5
+; CHECK-NEXT:    andi a0, a0, 66
+; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    ret
+  %r = call float @llvm.copysign.f32(float 1.0, float %y)
+  %res = call i1 @llvm.is.fpclass.f32(float %r, i32 264) ; 0x108 = +/-normal
+  ret i1 %res
+}
+
+define i1 @copysign_unknown_sign_no_fold(float %x, float %y) nounwind {
+; CHECK-LABEL: copysign_unknown_sign_no_fold:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fsgnj.s fa5, fa0, fa1
+; CHECK-NEXT:    fclass.s a0, fa5
+; CHECK-NEXT:    andi a0, a0, 15
+; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    ret
+  %r = call float @llvm.copysign.f32(float %x, float %y)
+  %res = call i1 @llvm.is.fpclass.f32(float %r, i32 60) ; 0x3C = any negative
+  ret i1 %res
+}

>From 0e037f0b503b3562295823714d26be760be80ea3 Mon Sep 17 00:00:00 2001
From: xinlongchen <xinlongchen at tencent.com>
Date: Thu, 23 Apr 2026 20:30:44 +0800
Subject: [PATCH 2/4] add ISD::FCOPYSIGN handling

---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  8 ++++++
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 27 +++----------------
 2 files changed, 12 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 3a0b5cb0de0be..bd962600fa8d5 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6146,6 +6146,14 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
     Known.fabs();
     break;
   }
+  case ISD::FCOPYSIGN: {
+    Known = computeKnownFPClass(Op.getOperand(0), DemandedElts,
+                                InterestedClasses, Depth + 1);
+    KnownFPClass KnownSign = computeKnownFPClass(Op.getOperand(1), DemandedElts,
+                                                 InterestedClasses, Depth + 1);
+    Known.copysign(KnownSign);
+    break;
+  }
   case ISD::AssertNoFPClass: {
     Known = computeKnownFPClass(Op.getOperand(0), DemandedElts,
                                 InterestedClasses, Depth + 1);
diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index addcaaa322c68..00a8cebb00280 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -260,12 +260,7 @@ define <4 x i1> @fneg_vec_unknown_sign(<4 x i32> %vecbits) nounwind {
 define i1 @copysign_nan_mag_is_finite_or_inf(float %y) nounwind {
 ; CHECK-LABEL: copysign_nan_mag_is_finite_or_inf:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, 523264
-; CHECK-NEXT:    fmv.w.x fa5, a0
-; CHECK-NEXT:    fsgnj.s fa5, fa5, fa0
-; CHECK-NEXT:    fclass.s a0, fa5
-; CHECK-NEXT:    zext.b a0, a0
-; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
   %r = call float @llvm.copysign.f32(float 0x7FF8000000000000, float %y)
   %res = call i1 @llvm.is.fpclass.f32(float %r, i32 1020) ; 0x3FC = finite | inf
@@ -275,11 +270,7 @@ define i1 @copysign_nan_mag_is_finite_or_inf(float %y) nounwind {
 define i1 @copysign_zero_mag_isnan(float %y) nounwind {
 ; CHECK-LABEL: copysign_zero_mag_isnan:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    fmv.w.x fa5, zero
-; CHECK-NEXT:    fsgnj.s fa5, fa5, fa0
-; CHECK-NEXT:    fclass.s a0, fa5
-; CHECK-NEXT:    andi a0, a0, 768
-; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
   %r = call float @llvm.copysign.f32(float 0.0, float %y)
   %res = call i1 @llvm.is.fpclass.f32(float %r, i32 3) ; 0x3 = nan
@@ -289,12 +280,7 @@ define i1 @copysign_zero_mag_isnan(float %y) nounwind {
 define i1 @copysign_inf_mag_isfinite_or_nan(float %y) nounwind {
 ; CHECK-LABEL: copysign_inf_mag_isfinite_or_nan:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, 522240
-; CHECK-NEXT:    fmv.w.x fa5, a0
-; CHECK-NEXT:    fsgnj.s fa5, fa5, fa0
-; CHECK-NEXT:    fclass.s a0, fa5
-; CHECK-NEXT:    andi a0, a0, 894
-; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
   %r = call float @llvm.copysign.f32(float 0x7FF0000000000000, float %y)
   %res = call i1 @llvm.is.fpclass.f32(float %r, i32 507) ; 0x1FB = finite (0x1F8) | nan (0x3)
@@ -304,12 +290,7 @@ define i1 @copysign_inf_mag_isfinite_or_nan(float %y) nounwind {
 define i1 @copysign_normal_mag_not_normal(float %y) nounwind {
 ; CHECK-LABEL: copysign_normal_mag_not_normal:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, 260096
-; CHECK-NEXT:    fmv.w.x fa5, a0
-; CHECK-NEXT:    fsgnj.s fa5, fa5, fa0
-; CHECK-NEXT:    fclass.s a0, fa5
-; CHECK-NEXT:    andi a0, a0, 957
-; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
   %r = call float @llvm.copysign.f32(float 1.0, float %y)
   %res = call i1 @llvm.is.fpclass.f32(float %r, i32 759) ; 0x2F7 = all classes except +/-normal (0x108)

>From a38b9fbe2d74a6e172dc14ed699da7d9ed7a892a Mon Sep 17 00:00:00 2001
From: xinlongchen <xinlongchen at tencent.com>
Date: Fri, 24 Apr 2026 23:04:21 +0800
Subject: [PATCH 3/4] update fold-to-true test

---
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index 1a9170f37635a..b65bc0302b09d 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -307,16 +307,10 @@ define i1 @copysign_normal_mag_not_normal(float %y) nounwind {
   ret i1 %res
 }
 
-; fold-to-true test, not fold now
 define i1 @copysign_normal_mag_is_normal(float %y) nounwind {
 ; CHECK-LABEL: copysign_normal_mag_is_normal:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, 260096
-; CHECK-NEXT:    fmv.w.x fa5, a0
-; CHECK-NEXT:    fsgnj.s fa5, fa5, fa0
-; CHECK-NEXT:    fclass.s a0, fa5
-; CHECK-NEXT:    andi a0, a0, 66
-; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    li a0, 1
 ; CHECK-NEXT:    ret
   %r = call float @llvm.copysign.f32(float 1.0, float %y)
   %res = call i1 @llvm.is.fpclass.f32(float %r, i32 264) ; 0x108 = +/-normal

>From b257eba845f794ccec6f11d75608d921e1cb5dab Mon Sep 17 00:00:00 2001
From: xinlongchen <xinlongchen at tencent.com>
Date: Tue, 28 Apr 2026 09:37:23 +0800
Subject: [PATCH 4/4] fix merge conflict

---
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index 2aba8fb71129b..1e4c8ba5e2ea3 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -328,6 +328,8 @@ define i1 @copysign_unknown_sign_no_fold(float %x, float %y) nounwind {
   %r = call float @llvm.copysign.f32(float %x, float %y)
   %res = call i1 @llvm.is.fpclass.f32(float %r, i32 60) ; 0x3C = any negative
   ret i1 %res
+}
+
 define <vscale x 4 x i1> @extract_subvec_scalable_isneg_false(<vscale x 8 x float> %a0) {
 ; CHECK-LABEL: extract_subvec_scalable_isneg_false:
 ; CHECK:       # %bb.0:



More information about the llvm-commits mailing list