On 6/30/24 6:47 PM, Vineet Gupta wrote:
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.
Hmm, I'm wondering if I gave you a slightly bad steer. The fclass insn
is unlikely to ever be used as-is since the result is target specific.
So we probably don't need to worry too much about optimizing it the
fclass insn itself for extension removal... But we probably do want to
improve the expansion side a bit....
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>")])
So I think just make operand0 :X here so that only word_mode is allowed.
+
+(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;
+})
Leave the modes in the RTL template of the expander as you've got them
above. That looks good.
In the C fragment I think you'll want to reject all the undesirable
output modes. The expander is allowed to FAIL, so you can do something
like this:
if (GET_MODE (operands[0]) != SImode
&& GET_MODE (operands[0]) != word_mode)
FAIL;
Which should allow SI for rv32/rv64 and DI for rv64.
> +> +(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));
So I would use tmp (or another word_mode pseudo register) for the
destination of that emit_insn. Then something like:
t = gen_lowpart (SImode, tmp);
SUBREG_PROMOTED_VAR_P (tmp) = 1;
SUBREG_PROMOTED_SET (tmp, SRP_SIGNED);
emit_move_insn (operands[0], tmp);
To the output into operands[0] with enough magic to allow us to
potentially remove a subsequent sign extension.
Jeff