204 lines
6.7 KiB
Diff
204 lines
6.7 KiB
Diff
From 1d08e8d3041c102154001b1813ca13e4886048eb Mon Sep 17 00:00:00 2001
|
|
From: Xi Ruoyao <xry111@xry111.site>
|
|
Date: Thu, 4 Jul 2024 02:49:28 +0800
|
|
Subject: [PATCH 18/20] 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.
|
|
---
|
|
gcc/config/loongarch/loongarch.md | 53 ++++++++++++++++---
|
|
.../gcc.target/loongarch/fclass-compile.c | 20 +++++++
|
|
.../gcc.target/loongarch/fclass-run.c | 53 +++++++++++++++++++
|
|
3 files changed, 119 insertions(+), 7 deletions(-)
|
|
create mode 100644 gcc/testsuite/gcc.target/loongarch/fclass-compile.c
|
|
create mode 100644 gcc/testsuite/gcc.target/loongarch/fclass-run.c
|
|
|
|
diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
|
|
index 73cdb38a4..f70ca85bf 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 000000000..9c24d6e26
|
|
--- /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 000000000..e5585f9d5
|
|
--- /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);
|
|
+}
|
|
--
|
|
2.43.0
|
|
|