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 ijust few days back got support for the
corresponding optabs. All that is needed is to wire these up in the
backend.

I was also hoping to get __builtin_inf() done but unforutnately it
requires little more rtl foo/bar to implement a tri-modal return.

Currently going thru CI testing.

gcc/ChangeLog:
        * config/riscv/riscv.md: Add UNSPEC_FCLASS, UNSPEC_ISFINITE,
        USPEC_ISNORMAL.
        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               | 56 +++++++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/fclass.c | 18 ++++++++
 2 files changed, 74 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..fc4441916137 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -68,6 +68,9 @@
   UNSPEC_FMAX
   UNSPEC_FMINM
   UNSPEC_FMAXM
+  UNSPEC_FCLASS
+  UNSPEC_ISFINITE
+  UNSPEC_ISNORMAL
 
   ;; Stack tie
   UNSPEC_TIE
@@ -3436,6 +3439,59 @@
    (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:SI              0 "register_operand" "=r")
+       (unspec:SI [(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:SI              0 "register_operand" "=r")
+       (unspec:SI [(match_operand:ANYF 1 "register_operand" " f")]
+                  UNSPEC_ISFINITE))]
+  "TARGET_HARD_FLOAT"
+{
+  rtx tmp = gen_reg_rtx (SImode);
+  emit_insn (gen_fclass<ANYF:mode> (tmp, operands[1]));
+  riscv_emit_binary (AND, tmp, tmp, GEN_INT (0x7e));
+  rtx cmp = gen_rtx_NE (SImode, tmp, const0_rtx);
+  emit_insn (gen_cstoresi4 (operands[0], cmp, tmp, const0_rtx));
+
+  DONE;
+})
+
+;; TODO: isinf is a bit tricky as it require trimodal return
+;;  1 if 0x80, -1 if 0x1, 0 otherwise
+
+(define_expand "isnormal<ANYF:mode>2"
+  [(set (match_operand:SI              0 "register_operand" "=r")
+       (unspec:SI [(match_operand:ANYF 1 "register_operand" " f")]
+                  UNSPEC_ISNORMAL))]
+  "TARGET_HARD_FLOAT"
+{
+  rtx tmp = gen_reg_rtx (SImode);
+  emit_insn (gen_fclass<ANYF:mode> (tmp, operands[1]));
+  riscv_emit_binary (AND, tmp, tmp, GEN_INT (0x42));
+  rtx cmp = gen_rtx_NE (SImode, tmp, const0_rtx);
+  emit_insn (gen_cstoresi4 (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

Reply via email to