+1 to any change that reduces the number of fflags accesses.
On Fri, Jun 28, 2024 at 5:54 PM Vineet Gupta <vine...@rivosinc.com> wrote: > > 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 >