Add an expander for isnan using fclass.  Since isnan is
just a compare, enable it only with -fsignaling-nans to avoid
generating spurious exceptions.  This fixes part of PR66462.

int isnan1 (float x) { return __builtin_isnan (x); }

With -fno-signaling-nans:

        fcmp.cun.s      $fcc0,$f0,$f0
        movcf2fr        $f0,$fcc0
        movfr2gr.s      $r4,$f0
        jr      $r1

With -fsignaling-nans:

        fclass.s        $f0,$f0
        movfr2gr.s      $r4,$f0
        andi    $r4,$r4,3
        sltu    $r4,$r0,$r4
        jr      $r1

        PR middle-end/66462

gcc/

        * config/loongarch/loongarch.md (FCLASS_MASK): Add 3.
        (fclass_optab): Assign isnan for 3.
        (<FCLASS_MASK:fclass_optab><ANYF:mode>2): If FCLASS_MASK is 3,
        only enable when -fsignaling-nans.

gcc/testsuite:

        * gcc.target/loongarch/fclass-compile.c: Update test.
        * gcc.target/loongarch/fclass-run.c: Likewise.
---

Bootstrapped and regtested on loongarch64-linux-gnu.  Ok for trunk?

 gcc/config/loongarch/loongarch.md                   | 7 ++++---
 gcc/testsuite/gcc.target/loongarch/fclass-compile.c | 9 ++++++---
 gcc/testsuite/gcc.target/loongarch/fclass-run.c     | 8 ++++----
 3 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index f42dc102d10..a275a2d0158 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -4193,17 +4193,18 @@ (define_insn "fclass_<fmt>"
   [(set_attr "type" "unknown")
    (set_attr "mode" "<MODE>")])
 
-(define_int_iterator FCLASS_MASK [68 136 952])
+(define_int_iterator FCLASS_MASK [68 136 952 3])
 (define_int_attr fclass_optab
   [(68 "isinf")
    (136        "isnormal")
-   (952        "isfinite")])
+   (952        "isfinite")
+   (3  "isnan")])
 
 (define_expand "<FCLASS_MASK:fclass_optab><ANYF:mode>2"
   [(match_operand:SI   0 "register_operand" "=r")
    (match_operand:ANYF 1 "register_operand" " f")
    (const_int FCLASS_MASK)]
-  "TARGET_HARD_FLOAT"
+  "TARGET_HARD_FLOAT && (<FCLASS_MASK> != 3 || flag_signaling_nans)"
   {
     rtx ft0 = gen_reg_rtx (SImode);
     rtx t0 = gen_reg_rtx (word_mode);
diff --git a/gcc/testsuite/gcc.target/loongarch/fclass-compile.c 
b/gcc/testsuite/gcc.target/loongarch/fclass-compile.c
index 9c24d6e263c..3db83e7b31d 100644
--- a/gcc/testsuite/gcc.target/loongarch/fclass-compile.c
+++ b/gcc/testsuite/gcc.target/loongarch/fclass-compile.c
@@ -1,14 +1,16 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -march=loongarch64 -mfpu=64 -mabi=lp64d" } */
+/* { dg-options "-O2 -fsignaling-nans -march=loongarch64 -mfpu=64 -mabi=lp64d" 
} */
 /* { dg-final { scan-assembler-times "fclass\\.s" 1 } } */
 /* { dg-final { scan-assembler-times "fclass\\.d" 1 } } */
+/* { dg-final { scan-assembler-not "fcmp" } } */
 
 __attribute__ ((noipa)) int
 test_fclass_f (float f)
 {
   return __builtin_isinf (f)
         | __builtin_isnormal (f) << 1
-        | __builtin_isfinite (f) << 2;
+        | __builtin_isfinite (f) << 2
+        | __builtin_isnan (f) << 3;
 }
 
 __attribute__ ((noipa)) int
@@ -16,5 +18,6 @@ test_fclass_d (double d)
 {
   return __builtin_isinf (d)
         | __builtin_isnormal (d) << 1
-        | __builtin_isfinite (d) << 2;
+        | __builtin_isfinite (d) << 2
+        | __builtin_isnan (d) << 3;
 }
diff --git a/gcc/testsuite/gcc.target/loongarch/fclass-run.c 
b/gcc/testsuite/gcc.target/loongarch/fclass-run.c
index e5585f9d557..3852d2015b3 100644
--- a/gcc/testsuite/gcc.target/loongarch/fclass-run.c
+++ b/gcc/testsuite/gcc.target/loongarch/fclass-run.c
@@ -37,8 +37,8 @@ main (void)
   ASSERT_EQ (test_fclass_f (-f_normal), 0b110);
   ASSERT_EQ (test_fclass_f (f_subnormal), 0b100);
   ASSERT_EQ (test_fclass_f (-f_subnormal), 0b100);
-  ASSERT_EQ (test_fclass_f (f_qnan), 0);
-  ASSERT_EQ (test_fclass_f (f_snan), 0);
+  ASSERT_EQ (test_fclass_f (f_qnan), 0b1000);
+  ASSERT_EQ (test_fclass_f (f_snan), 0b1000);
 
   ASSERT_EQ (test_fclass_d (d_inf), 0b001);
   ASSERT_EQ (test_fclass_d (-d_inf), 0b001);
@@ -48,6 +48,6 @@ main (void)
   ASSERT_EQ (test_fclass_d (-d_normal), 0b110);
   ASSERT_EQ (test_fclass_d (d_subnormal), 0b100);
   ASSERT_EQ (test_fclass_d (-d_subnormal), 0b100);
-  ASSERT_EQ (test_fclass_d (d_qnan), 0);
-  ASSERT_EQ (test_fclass_d (d_snan), 0);
+  ASSERT_EQ (test_fclass_d (d_qnan), 0b1000);
+  ASSERT_EQ (test_fclass_d (d_snan), 0b1000);
 }
-- 
2.51.0

Reply via email to