From 94f5a8f0d4910be2d861f7a9699e93efd609d042 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 28 Jul 2022 14:04:33 +0100 Subject: RISC-V: Split unordered FP comparisons into individual RTL insns We have unordered FP comparisons implemented as RTL insns that produce multiple machine instructions. Such RTL insns are hard to match with a processor pipeline description and additionally there is a redundant SNEZ instruction produced on the result of these comparisons even though the FLT.fmt and FLE.fmt machine instructions already produce either 0 or 1, e.g.: long flt (double x, double y) { return __builtin_isless (x, y); } with `-O2 -fno-finite-math-only -ftrapping-math -fno-signaling-nans' gets compiled to: .globl flt .type flt, @function flt: frflags a5 flt.d a0,fa0,fa1 fsflags a5 snez a0,a0 ret .size flt, .-flt because the middle end can't see through the UNSPEC operation unordered FP comparisons have been defined in terms of. These instructions are only produced via an expander already, so change the expander to emit individual RTL insns for each machine instruction in the ultimate ultimate sequence produced rather than deferring to a single RTL insn producing the whole sequence at once. gcc/ * config/riscv/riscv.md (UNSPECV_FSNVSNAN): New constant. (QUIET_PATTERN): New int attribute. (f_quiet4): Emit the intended RTL insns entirely within the preparation statements. (*f_quiet4_default) (*f_quiet4_snan): Remove insns. (*riscv_fsnvsnan2): New insn. gcc/testsuite/ * gcc.target/riscv/fle-ieee.c: New test. * gcc.target/riscv/fle-snan.c: New test. * gcc.target/riscv/fle.c: New test. * gcc.target/riscv/flef-ieee.c: New test. * gcc.target/riscv/flef-snan.c: New test. * gcc.target/riscv/flef.c: New test. * gcc.target/riscv/flt-ieee.c: New test. * gcc.target/riscv/flt-snan.c: New test. * gcc.target/riscv/flt.c: New test. * gcc.target/riscv/fltf-ieee.c: New test. * gcc.target/riscv/fltf-snan.c: New test. * gcc.target/riscv/fltf.c: New test. --- gcc/config/riscv/riscv.md | 69 ++++++++++++++++-------------- gcc/testsuite/gcc.target/riscv/fle-ieee.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/fle-snan.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/fle.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/flef-ieee.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/flef-snan.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/flef.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/flt-ieee.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/flt-snan.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/flt.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/fltf-ieee.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/fltf-snan.c | 12 ++++++ gcc/testsuite/gcc.target/riscv/fltf.c | 12 ++++++ 13 files changed, 180 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/fle-ieee.c create mode 100644 gcc/testsuite/gcc.target/riscv/fle-snan.c create mode 100644 gcc/testsuite/gcc.target/riscv/fle.c create mode 100644 gcc/testsuite/gcc.target/riscv/flef-ieee.c create mode 100644 gcc/testsuite/gcc.target/riscv/flef-snan.c create mode 100644 gcc/testsuite/gcc.target/riscv/flef.c create mode 100644 gcc/testsuite/gcc.target/riscv/flt-ieee.c create mode 100644 gcc/testsuite/gcc.target/riscv/flt-snan.c create mode 100644 gcc/testsuite/gcc.target/riscv/flt.c create mode 100644 gcc/testsuite/gcc.target/riscv/fltf-ieee.c create mode 100644 gcc/testsuite/gcc.target/riscv/fltf-snan.c create mode 100644 gcc/testsuite/gcc.target/riscv/fltf.c (limited to 'gcc') diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index aa43d5f..0796f91 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -57,6 +57,7 @@ ;; Floating-point unspecs. UNSPECV_FRFLAGS UNSPECV_FSFLAGS + UNSPECV_FSNVSNAN ;; Interrupt handler instructions. UNSPECV_MRET @@ -360,6 +361,7 @@ ;; Iterator and attributes for quiet comparisons. (define_int_iterator QUIET_COMPARISON [UNSPEC_FLT_QUIET UNSPEC_FLE_QUIET]) (define_int_attr quiet_pattern [(UNSPEC_FLT_QUIET "lt") (UNSPEC_FLE_QUIET "le")]) +(define_int_attr QUIET_PATTERN [(UNSPEC_FLT_QUIET "LT") (UNSPEC_FLE_QUIET "LE")]) ;; This code iterator allows signed and unsigned widening multiplications ;; to use the same template. @@ -2326,39 +2328,31 @@ (set_attr "mode" "")]) (define_expand "f_quiet4" - [(parallel [(set (match_operand:X 0 "register_operand") - (unspec:X - [(match_operand:ANYF 1 "register_operand") - (match_operand:ANYF 2 "register_operand")] - QUIET_COMPARISON)) - (clobber (match_scratch:X 3))])] - "TARGET_HARD_FLOAT") - -(define_insn "*f_quiet4_default" - [(set (match_operand:X 0 "register_operand" "=r") - (unspec:X - [(match_operand:ANYF 1 "register_operand" " f") - (match_operand:ANYF 2 "register_operand" " f")] - QUIET_COMPARISON)) - (clobber (match_scratch:X 3 "=&r"))] - "TARGET_HARD_FLOAT && ! HONOR_SNANS (mode)" - "frflags\t%3\n\tf.\t%0,%1,%2\n\tfsflags\t%3" - [(set_attr "type" "fcmp") - (set_attr "mode" "") - (set (attr "length") (const_int 12))]) - -(define_insn "*f_quiet4_snan" - [(set (match_operand:X 0 "register_operand" "=r") - (unspec:X - [(match_operand:ANYF 1 "register_operand" " f") - (match_operand:ANYF 2 "register_operand" " f")] - QUIET_COMPARISON)) - (clobber (match_scratch:X 3 "=&r"))] - "TARGET_HARD_FLOAT && HONOR_SNANS (mode)" - "frflags\t%3\n\tf.\t%0,%1,%2\n\tfsflags\t%3\n\tfeq.\tzero,%1,%2" - [(set_attr "type" "fcmp") - (set_attr "mode" "") - (set (attr "length") (const_int 16))]) + [(set (match_operand:X 0 "register_operand") + (unspec:X [(match_operand:ANYF 1 "register_operand") + (match_operand:ANYF 2 "register_operand")] + QUIET_COMPARISON))] + "TARGET_HARD_FLOAT" +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + rtx op2 = operands[2]; + rtx tmp = gen_reg_rtx (SImode); + rtx cmp = gen_rtx_ (mode, op1, op2); + rtx frflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, const0_rtx), + UNSPECV_FRFLAGS); + rtx fsflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, tmp), + UNSPECV_FSFLAGS); + + emit_insn (gen_rtx_SET (tmp, frflags)); + emit_insn (gen_rtx_SET (op0, cmp)); + emit_insn (fsflags); + if (HONOR_SNANS (mode)) + emit_insn (gen_rtx_UNSPEC_VOLATILE (mode, + gen_rtvec (2, op1, op2), + UNSPECV_FSNVSNAN)); + DONE; +}) (define_insn "*seq_zero_" [(set (match_operand:GPR 0 "register_operand" "=r") @@ -2766,6 +2760,15 @@ "TARGET_HARD_FLOAT" "fsflags\t%0") +(define_insn "*riscv_fsnvsnan2" + [(unspec_volatile [(match_operand:ANYF 0 "register_operand" "f") + (match_operand:ANYF 1 "register_operand" "f")] + UNSPECV_FSNVSNAN)] + "TARGET_HARD_FLOAT" + "feq.\tzero,%0,%1" + [(set_attr "type" "fcmp") + (set_attr "mode" "")]) + (define_insn "riscv_mret" [(return) (unspec_volatile [(const_int 0)] UNSPECV_MRET)] diff --git a/gcc/testsuite/gcc.target/riscv/fle-ieee.c b/gcc/testsuite/gcc.target/riscv/fle-ieee.c new file mode 100644 index 0000000..af9d503 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fle-ieee.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -ftrapping-math -fno-signaling-nans" } */ + +long +fle (double x, double y) +{ + return __builtin_islessequal (x, y); +} + +/* { dg-final { scan-assembler "\tfrflags\t(\[^\n\]*)\n\tfle\\.d\t\[^\n\]*\n\tfsflags\t\\1\n" } } */ +/* { dg-final { scan-assembler-not "snez" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fle-snan.c b/gcc/testsuite/gcc.target/riscv/fle-snan.c new file mode 100644 index 0000000..0579d93 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fle-snan.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -ftrapping-math -fsignaling-nans" } */ + +long +fle (double x, double y) +{ + return __builtin_islessequal (x, y); +} + +/* { dg-final { scan-assembler "\tfrflags\t(\[^\n\]*)\n\tfle\\.d\t\[^,\]*,(\[^,\]*),(\[^,\]*)\n\tfsflags\t\\1\n\tfeq\\.d\tzero,\\2,\\3\n" } } */ +/* { dg-final { scan-assembler-not "snez" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fle.c b/gcc/testsuite/gcc.target/riscv/fle.c new file mode 100644 index 0000000..97c8ab9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fle.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -fno-trapping-math -fno-signaling-nans" } */ + +long +fle (double x, double y) +{ + return __builtin_islessequal (x, y); +} + +/* { dg-final { scan-assembler "\tf(?:gt|le)\\.d\t\[^\n\]*\n" } } */ +/* { dg-final { scan-assembler-not "f\[rs\]flags" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/flef-ieee.c b/gcc/testsuite/gcc.target/riscv/flef-ieee.c new file mode 100644 index 0000000..e2d6b0d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/flef-ieee.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -ftrapping-math -fno-signaling-nans" } */ + +long +flef (float x, float y) +{ + return __builtin_islessequal (x, y); +} + +/* { dg-final { scan-assembler "\tfrflags\t(\[^\n\]*)\n\tfle\\.s\t\[^\n\]*\n\tfsflags\t\\1\n" } } */ +/* { dg-final { scan-assembler-not "snez" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/flef-snan.c b/gcc/testsuite/gcc.target/riscv/flef-snan.c new file mode 100644 index 0000000..2d2c5b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/flef-snan.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -ftrapping-math -fsignaling-nans" } */ + +long +flef (float x, float y) +{ + return __builtin_islessequal (x, y); +} + +/* { dg-final { scan-assembler "\tfrflags\t(\[^\n\]*)\n\tfle\\.s\t\[^,\]*,(\[^,\]*),(\[^,\]*)\n\tfsflags\t\\1\n\tfeq\\.s\tzero,\\2,\\3\n" } } */ +/* { dg-final { scan-assembler-not "snez" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/flef.c b/gcc/testsuite/gcc.target/riscv/flef.c new file mode 100644 index 0000000..379f511 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/flef.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -fno-trapping-math -fno-signaling-nans" } */ + +long +flef (float x, float y) +{ + return __builtin_islessequal (x, y); +} + +/* { dg-final { scan-assembler "\tf(?:gt|le)\\.s\t\[^\n\]*\n" } } */ +/* { dg-final { scan-assembler-not "f\[rs\]flags" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/flt-ieee.c b/gcc/testsuite/gcc.target/riscv/flt-ieee.c new file mode 100644 index 0000000..7d7aae3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/flt-ieee.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -ftrapping-math -fno-signaling-nans" } */ + +long +flt (double x, double y) +{ + return __builtin_isless (x, y); +} + +/* { dg-final { scan-assembler "\tfrflags\t(\[^\n\]*)\n\tflt\\.d\t\[^\n\]*\n\tfsflags\t\\1\n" } } */ +/* { dg-final { scan-assembler-not "snez" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/flt-snan.c b/gcc/testsuite/gcc.target/riscv/flt-snan.c new file mode 100644 index 0000000..ff4c4e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/flt-snan.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -ftrapping-math -fsignaling-nans" } */ + +long +flt (double x, double y) +{ + return __builtin_isless (x, y); +} + +/* { dg-final { scan-assembler "\tfrflags\t(\[^\n\]*)\n\tflt\\.d\t\[^,\]*,(\[^,\]*),(\[^,\]*)\n\tfsflags\t\\1\n\tfeq\\.d\tzero,\\2,\\3\n" } } */ +/* { dg-final { scan-assembler-not "snez" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/flt.c b/gcc/testsuite/gcc.target/riscv/flt.c new file mode 100644 index 0000000..4f5ef1d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/flt.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -fno-trapping-math -fno-signaling-nans" } */ + +long +flt (double x, double y) +{ + return __builtin_isless (x, y); +} + +/* { dg-final { scan-assembler "\tf(?:ge|lt)\\.d\t\[^\n\]*\n" } } */ +/* { dg-final { scan-assembler-not "f\[rs\]flags" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fltf-ieee.c b/gcc/testsuite/gcc.target/riscv/fltf-ieee.c new file mode 100644 index 0000000..ede076e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fltf-ieee.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -ftrapping-math -fno-signaling-nans" } */ + +long +fltf (float x, float y) +{ + return __builtin_isless (x, y); +} + +/* { dg-final { scan-assembler "\tfrflags\t(\[^\n\]*)\n\tflt\\.s\t\[^\n\]*\n\tfsflags\t\\1\n" } } */ +/* { dg-final { scan-assembler-not "snez" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fltf-snan.c b/gcc/testsuite/gcc.target/riscv/fltf-snan.c new file mode 100644 index 0000000..d29d786 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fltf-snan.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -ftrapping-math -fsignaling-nans" } */ + +long +fltf (float x, float y) +{ + return __builtin_isless (x, y); +} + +/* { dg-final { scan-assembler "\tfrflags\t(\[^\n\]*)\n\tflt\\.s\t\[^,\]*,(\[^,\]*),(\[^,\]*)\n\tfsflags\t\\1\n\tfeq\\.s\tzero,\\2,\\3\n" } } */ +/* { dg-final { scan-assembler-not "snez" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fltf.c b/gcc/testsuite/gcc.target/riscv/fltf.c new file mode 100644 index 0000000..c9e6a2b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fltf.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-fno-finite-math-only -fno-trapping-math -fno-signaling-nans" } */ + +long +fltf (float x, float y) +{ + return __builtin_isless (x, y); +} + +/* { dg-final { scan-assembler "\tf(?:ge|lt)\\.s\t\[^\n\]*\n" } } */ +/* { dg-final { scan-assembler-not "f\[rs\]flags" } } */ -- cgit v1.1