Doing so can avoid loading FP constants from the memory. It also partially fixes PR 66462 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. --- Bootstrapped and regtested on loongarch64-linux-gnu. There are two regressions: range-sincos.c and vrp-float-abs-1.c but they shall be fixed by https://gcc.gnu.org/pipermail/gcc-patches/2024-July/656937.html. There is a redundant "andi" in the code generation for the test case: https://gcc.gnu.org/pipermail/gcc-patches/2024-July/656764.html. I suppose the fix of this redundant "andi" is using word_mode instead of SImode for operand 0, but it does not work as at now: https://gcc.gnu.org/pipermail/gcc-patches/2024-July/656772.html. Ok for trunk (now, or after the fix for range-sincos.c and vrp-float-abs-1.c are committed)? IMO the redundant "andi" can be fixed later. 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 e4434c3bd4e..b3cae49832e 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -1829,16 +1829,17 @@ (define_insn "*zero_extendhi_truncqi" ;; .................... (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" @@ -4162,14 +4163,52 @@ (define_insn "loongarch_movgr2fcsr" "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 (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); +} -- 2.45.2