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 <[email protected]>
---
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