aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/loongarch/loongarch.md53
-rw-r--r--gcc/testsuite/gcc.target/loongarch/fclass-compile.c20
-rw-r--r--gcc/testsuite/gcc.target/loongarch/fclass-run.c53
3 files changed, 119 insertions, 7 deletions
diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
index 73cdb38..f70ca85 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 0000000..9c24d6e
--- /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 0000000..e5585f9
--- /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);
+}