https://gcc.gnu.org/g:ee4a6343225b6e44b3d2b2c90c355c21f7ec6855

commit r15-2931-gee4a6343225b6e44b3d2b2c90c355c21f7ec6855
Author: Xi Ruoyao <xry...@xry111.site>
Date:   Thu Jul 4 02:49:28 2024 +0800

    LoongArch: Implement scalar isinf, isnormal, and isfinite via fclass
    
    Doing so can avoid loading FP constants from the memory.  It also
    partially fixes PR 66262 as fclass does not signal on sNaN.
    
    gcc/ChangeLog:
    
            * config/loongarch/loongarch.md (extendsidi2): Add ("=r", "f")
            alternative and use movfr2gr.s for it.  The spec clearly states
            movfr2gr.s sign extends the value to GRLEN.
            (fclass_<fmt>): Make the result SImode instead of a floating
            mode.  The fclass results are really not FP values.
            (FCLASS_MASK): New define_int_iterator.
            (fclass_optab): New define_int_attr.
            (<FCLASS_MASK:fclass_optab><ANYF:mode>): New define_expand
            template.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/loongarch/fclass-compile.c: New test.
            * gcc.target/loongarch/fclass-run.c: New test.

Diff:
---
 gcc/config/loongarch/loongarch.md                  | 53 +++++++++++++++++++---
 .../gcc.target/loongarch/fclass-compile.c          | 20 ++++++++
 gcc/testsuite/gcc.target/loongarch/fclass-run.c    | 53 ++++++++++++++++++++++
 3 files changed, 119 insertions(+), 7 deletions(-)

diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index 73cdb38a406..f70ca85bfb3 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -1851,16 +1851,17 @@
 ;;  ....................
 
 (define_insn "extendsidi2"
-  [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
+  [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r")
        (sign_extend:DI
-           (match_operand:SI 1 "nonimmediate_operand" "r,ZC,m,k")))]
+           (match_operand:SI 1 "nonimmediate_operand" "r,ZC,m,k,f")))]
   "TARGET_64BIT"
   "@
    slli.w\t%0,%1,0
    ldptr.w\t%0,%1
    ld.w\t%0,%1
-   ldx.w\t%0,%1"
-  [(set_attr "move_type" "sll0,load,load,load")
+   ldx.w\t%0,%1
+   movfr2gr.s\t%0,%1"
+  [(set_attr "move_type" "sll0,load,load,load,mftg")
    (set_attr "mode" "DI")])
 
 (define_insn "extend<SHORT:mode><GPR:mode>2"
@@ -4110,14 +4111,52 @@
   "movgr2fcsr\t$r%0,%1")
 
 (define_insn "fclass_<fmt>"
-  [(set (match_operand:ANYF 0 "register_operand" "=f")
-       (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
-                     UNSPEC_FCLASS))]
+  [(set (match_operand:SI 0 "register_operand" "=f")
+       (unspec:SI [(match_operand:ANYF 1 "register_operand" "f")]
+                  UNSPEC_FCLASS))]
   "TARGET_HARD_FLOAT"
   "fclass.<fmt>\t%0,%1"
   [(set_attr "type" "unknown")
    (set_attr "mode" "<MODE>")])
 
+(define_int_iterator FCLASS_MASK [68 136 952])
+(define_int_attr fclass_optab
+  [(68 "isinf")
+   (136        "isnormal")
+   (952        "isfinite")])
+
+(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"
+  {
+    rtx ft0 = gen_reg_rtx (SImode);
+    rtx t0 = gen_reg_rtx (word_mode);
+    rtx mask = GEN_INT (<FCLASS_MASK>);
+
+    emit_insn (gen_fclass_<ANYF:fmt> (ft0, operands[1]));
+
+    if (TARGET_64BIT)
+      emit_insn (gen_extend_insn (t0, ft0, DImode, SImode, 0));
+    else
+      emit_move_insn (t0, ft0);
+
+    emit_move_insn (t0, gen_rtx_AND (word_mode, t0, mask));
+    emit_move_insn (t0, gen_rtx_NE (word_mode, t0, const0_rtx));
+
+    if (TARGET_64BIT)
+      {
+       t0 = lowpart_subreg (SImode, t0, DImode);
+       SUBREG_PROMOTED_VAR_P (t0) = 1;
+       SUBREG_PROMOTED_SET (t0, SRP_SIGNED);
+      }
+
+    emit_move_insn (operands[0], t0);
+
+    DONE;
+  })
+
 (define_insn "bytepick_w_<bytepick_imm>"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (ior:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
diff --git a/gcc/testsuite/gcc.target/loongarch/fclass-compile.c 
b/gcc/testsuite/gcc.target/loongarch/fclass-compile.c
new file mode 100644
index 00000000000..9c24d6e263c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/fclass-compile.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=loongarch64 -mfpu=64 -mabi=lp64d" } */
+/* { dg-final { scan-assembler-times "fclass\\.s" 1 } } */
+/* { dg-final { scan-assembler-times "fclass\\.d" 1 } } */
+
+__attribute__ ((noipa)) int
+test_fclass_f (float f)
+{
+  return __builtin_isinf (f)
+        | __builtin_isnormal (f) << 1
+        | __builtin_isfinite (f) << 2;
+}
+
+__attribute__ ((noipa)) int
+test_fclass_d (double d)
+{
+  return __builtin_isinf (d)
+        | __builtin_isnormal (d) << 1
+        | __builtin_isfinite (d) << 2;
+}
diff --git a/gcc/testsuite/gcc.target/loongarch/fclass-run.c 
b/gcc/testsuite/gcc.target/loongarch/fclass-run.c
new file mode 100644
index 00000000000..e5585f9d557
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/fclass-run.c
@@ -0,0 +1,53 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fsignaling-nans -D_GNU_SOURCE -std=c23" } */
+/* { dg-require-effective-target fenv_exceptions } */
+
+#include <fenv.h>
+#include "fclass-compile.c"
+
+#define ASSERT_EQ(x, y) (void)(x == y || (__builtin_abort (), 1))
+
+int
+main (void)
+{
+  volatile float f_inf = __builtin_inff ();
+  volatile float f_zero = 0;
+  volatile float f_normal = 114.514;
+  volatile float f_subnormal = 1e-40;
+  volatile float f_qnan = __builtin_nanf ("");
+  volatile float f_snan = __builtin_nansf ("");
+  volatile double d_inf = __builtin_inf ();
+  volatile double d_zero = 0;
+  volatile double d_normal = 1919.810;
+  volatile double d_subnormal = 1e-320;
+  volatile double d_qnan = __builtin_nan ("");
+  volatile double d_snan = __builtin_nans ("");
+
+#if __loongarch_frlen >= 64
+  /* With fclass.{s/d} we shouldn't signal, even if the input is sNaN.
+     PR 66462.  */
+  feenableexcept (FE_INVALID);
+#endif
+
+  ASSERT_EQ (test_fclass_f (f_inf), 0b001);
+  ASSERT_EQ (test_fclass_f (-f_inf), 0b001);
+  ASSERT_EQ (test_fclass_f (f_zero), 0b100);
+  ASSERT_EQ (test_fclass_f (-f_zero), 0b100);
+  ASSERT_EQ (test_fclass_f (f_normal), 0b110);
+  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_d (d_inf), 0b001);
+  ASSERT_EQ (test_fclass_d (-d_inf), 0b001);
+  ASSERT_EQ (test_fclass_d (d_zero), 0b100);
+  ASSERT_EQ (test_fclass_d (-d_zero), 0b100);
+  ASSERT_EQ (test_fclass_d (d_normal), 0b110);
+  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);
+}

Reply via email to