Changes since v1: - Removed UNSPEC_{INFINITE,ISNORMAL} - Don't hardcode SI in patterns, try to keep X to avoid potential sign extension pitfalls. Implementation wise requires skipping :MODE specifier in match_operand which is flagged as missing mode warning.
--- Currently isfinite and isnormal use float compare instructions with fp flags save/restored around them. Our perf team complained this could be costly in uarch. RV Base ISA already has FCLASS.{d,s,h} instruction to do FP compares w/o disturbing FP exception flags. Coincidently, upstream very recently got support for the corresponding optabs. So this just requires wiring up in the backend. gcc/ChangeLog: * config/riscv/riscv.md: Add UNSPEC_FCLASS. define_insn for fclass. define_expand for isfinite and isnormal. gcc/testsuite/ChangeLog: * gcc.target/riscv/fclass.c: New test. Signed-off-by: Vineet Gupta <vine...@rivosinc.com> --- gcc/config/riscv/riscv.md | 50 +++++++++++++++++++++++++ gcc/testsuite/gcc.target/riscv/fclass.c | 18 +++++++++ 2 files changed, 68 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/fclass.c diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index ff37125e3f28..0b4a5f02713c 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -68,6 +68,7 @@ UNSPEC_FMAX UNSPEC_FMINM UNSPEC_FMAXM + UNSPEC_FCLASS ;; Stack tie UNSPEC_TIE @@ -3436,6 +3437,55 @@ (set_attr "mode" "<UNITMODE>") (set (attr "length") (const_int 16))]) +;; fclass instruction output bitmap +;; 0 negative infinity +;; 1 negative normal number. +;; 2 negative subnormal number. +;; 3 -0 +;; 4 +0 +;; 5 positive subnormal number. +;; 6 positive normal number. +;; 7 positive infinity +;; 8 signaling NaN. +;; 9 quiet NaN + +(define_insn "fclass<ANYF:mode>" + [(set (match_operand 0 "register_operand" "=r") + (unspec [(match_operand:ANYF 1 "register_operand" " f")] + UNSPEC_FCLASS))] + "TARGET_HARD_FLOAT" + "fclass.<fmt>\t%0,%1"; + [(set_attr "type" "fcmp") + (set_attr "mode" "<UNITMODE>")]) + +(define_expand "isfinite<ANYF:mode>2" + [(set (match_operand 0 "register_operand" "=r") + (match_operand:ANYF 1 "register_operand" " f"))] + "TARGET_HARD_FLOAT" +{ + rtx tmp = gen_reg_rtx (word_mode); + emit_insn (gen_fclass<ANYF:mode> (tmp, operands[1])); + riscv_emit_binary (AND, tmp, tmp, GEN_INT (0x7e)); + rtx cmp = gen_rtx_NE (word_mode, tmp, const0_rtx); + emit_insn (gen_cstore<mode>4 (operands[0], cmp, tmp, const0_rtx)); + + DONE; +}) + +(define_expand "isnormal<ANYF:mode>2" + [(set (match_operand 0 "register_operand" "=r") + (match_operand:ANYF 1 "register_operand" " f"))] + "TARGET_HARD_FLOAT" +{ + rtx tmp = gen_reg_rtx (word_mode); + emit_insn (gen_fclass<ANYF:mode> (tmp, operands[1])); + riscv_emit_binary (AND, tmp, tmp, GEN_INT (0x42)); + rtx cmp = gen_rtx_NE (word_mode, tmp, const0_rtx); + emit_insn (gen_cstore<mode>4 (operands[0], cmp, tmp, const0_rtx)); + + DONE; +}) + (define_insn "*seq_zero_<X:mode><GPR:mode>" [(set (match_operand:GPR 0 "register_operand" "=r") (eq:GPR (match_operand:X 1 "register_operand" " r") diff --git a/gcc/testsuite/gcc.target/riscv/fclass.c b/gcc/testsuite/gcc.target/riscv/fclass.c new file mode 100644 index 000000000000..0dfac982ebeb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fclass.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-march=rv64gc -mabi=lp64d -ftrapping-math { target { rv64 } } } */ +/* { dg-options "-march=rv32gc -mabi=ilp32d -ftrapping-math { target { rv32 } } } */ + +int t_isfinite(double a) +{ + return __builtin_isfinite(a); +} + +int t_isnormal(double a) +{ + return __builtin_isnormal(a); +} + +/* { dg-final { scan-assembler-not {\mfrflags} } } */ +/* { dg-final { scan-assembler-not {\mfsflags} } } */ +/* { dg-final { scan-assembler-times {\tfclass} 2 } } */ -- 2.34.1