public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-264] RISC-V: Provide `fmin'/`fmax' RTL patterns
@ 2022-05-10 14:04 Maciej W. Rozycki
  0 siblings, 0 replies; only message in thread
From: Maciej W. Rozycki @ 2022-05-10 14:04 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:9ddd44b58649d1d1e932c1e95dc00d654733c1fc

commit r13-264-g9ddd44b58649d1d1e932c1e95dc00d654733c1fc
Author: Maciej W. Rozycki <macro@embecosm.com>
Date:   Tue May 10 15:02:31 2022 +0100

    RISC-V: Provide `fmin'/`fmax' RTL patterns
    
    As at r2.2 of the RISC-V ISA specification[1] (equivalent to version 2.0
    of the "F" and "D" standard architecture extensions for single-precision
    and double-precision floating-point respectively) the FMIN and FMAX
    machine instructions fully match our requirement for the `fminM3' and
    `fmaxM3' standard RTL patterns:
    
    "For FMIN and FMAX, if at least one input is a signaling NaN, or if both
    inputs are quiet NaNs, the result is the canonical NaN.  If one operand
    is a quiet NaN and the other is not a NaN, the result is the non-NaN
    operand."
    
    suitably for the IEEE 754-2008 `minNum' and `maxNum' operations.
    
    However we only define `sminM3' and `smaxM3' standard RTL patterns to
    produce the FMIN and FMAX machine instructions, which in turn causes the
    `__builtin_fmin' and `__builtin_fmax' family of intrinsics to emit the
    corresponding libcalls rather than the relevant machine instructions.
    This is according to earlier revisions of the RISC-V ISA specification,
    which we however do not support anymore, as from commit 4b81528241ca
    ("RISC-V: Support version controling for ISA standard extensions").
    
    As from r20190608 of the RISC-V ISA specification (equivalent to version
    2.2 of the "F" and "D" standard ISA extensions for single-precision and
    double-precision floating-point respectively) the definition of the FMIN
    and FMAX machine instructions has been updated[2]:
    
    "Defined the signed-zero behavior of FMIN.fmt and FMAX.fmt, and changed
    their behavior on signaling-NaN inputs to conform to the minimumNumber
    and maximumNumber operations in the proposed IEEE 754-201x
    specification."
    
    and specifically[3]:
    
    "Floating-point minimum-number and maximum-number instructions FMIN.S
    and FMAX.S write, respectively, the smaller or larger of rs1 and rs2 to
    rd.  For the purposes of these instructions only, the value -0.0 is
    considered to be less than the value +0.0.  If both inputs are NaNs, the
    result is the canonical NaN.  If only one operand is a NaN, the result
    is the non-NaN operand.  Signaling NaN inputs set the invalid operation
    exception flag, even when the result is not NaN."
    
    Consequently for forwards compatibility with r20190608+ hardware we
    cannot use the FMIN and FMAX machine instructions unconditionally even
    where the ISA level of r2.2 has been specified with the `-misa-spec=2.2'
    option where operation would be different between ISA revisions, that
    is the handling of signaling NaN inputs.
    
    Therefore provide new `fmin<mode>3' and `fmax<mode>3' patterns removing
    the need to emit libcalls with the `__builtin_fmin' and `__builtin_fmax'
    family of intrinsics, however limit them to where `-fno-signaling-nans'
    is in effect, deferring to other code generation strategies otherwise as
    applicable.  Use newly-defined UNSPECs as the operation codes so that
    the patterns are only ever used if referred to by their names, as there
    is no RTL expression defined for the IEEE 754-2008 `minNum' and `maxNum'
    operations.
    
    References:
    
    [1] "The RISC-V Instruction Set Manual, Volume I: User-Level ISA",
        Document Version 2.2, May 7, 2017, Section 8.3 "NaN Generation and
        Propagation", p. 48
    
    [1] "The RISC-V Instruction Set Manual, Volume I: Unprivileged ISA",
        Document Version 20190608-Base-Ratified, June 8, 2019, "Preface",
        p. ii
    
    [2] same, Section 11.6 "Single-Precision Floating-Point Computational
        Instructions", p. 66
    
            gcc/
            * config/riscv/riscv.md (UNSPEC_FMIN, UNSPEC_FMAX): New
            constants.
            (fmin<mode>3, fmax<mode>3): New insns.
    
            gcc/testsuite/
            * gcc.target/riscv/fmax-snan.c: New test.
            * gcc.target/riscv/fmax.c: New test.
            * gcc.target/riscv/fmaxf-snan.c: New test.
            * gcc.target/riscv/fmaxf.c: New test.
            * gcc.target/riscv/fmin-snan.c: New test.
            * gcc.target/riscv/fmin.c: New test.
            * gcc.target/riscv/fminf-snan.c: New test.
            * gcc.target/riscv/fminf.c: New test.
            * gcc.target/riscv/smax-ieee.c: New test.
            * gcc.target/riscv/smax.c: New test.
            * gcc.target/riscv/smaxf-ieee.c: New test.
            * gcc.target/riscv/smaxf.c: New test.
            * gcc.target/riscv/smin-ieee.c: New test.
            * gcc.target/riscv/smin.c: New test.
            * gcc.target/riscv/sminf-ieee.c: New test.
            * gcc.target/riscv/sminf.c: New test.

Diff:
---
 gcc/config/riscv/riscv.md                   | 22 ++++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/fmax-snan.c  | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/fmax.c       | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/fmaxf-snan.c | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/fmaxf.c      | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/fmin-snan.c  | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/fmin.c       | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/fminf-snan.c | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/fminf.c      | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/smax-ieee.c  | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/smax.c       | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/smaxf-ieee.c | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/smaxf.c      | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/smin-ieee.c  | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/smin.c       | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/sminf-ieee.c | 12 ++++++++++++
 gcc/testsuite/gcc.target/riscv/sminf.c      | 12 ++++++++++++
 17 files changed, 214 insertions(+)

diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index b3c5bce842a..d9b451be0b4 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -42,6 +42,8 @@
   UNSPEC_COPYSIGN
   UNSPEC_LRINT
   UNSPEC_LROUND
+  UNSPEC_FMIN
+  UNSPEC_FMAX
 
   ;; Stack tie
   UNSPEC_TIE
@@ -1216,6 +1218,26 @@
 ;;
 ;;  ....................
 
+(define_insn "fmin<mode>3"
+  [(set (match_operand:ANYF                    0 "register_operand" "=f")
+	(unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
+		      (use (match_operand:ANYF 2 "register_operand" " f"))]
+		     UNSPEC_FMIN))]
+  "TARGET_HARD_FLOAT && !HONOR_SNANS (<MODE>mode)"
+  "fmin.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fmove")
+   (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "fmax<mode>3"
+  [(set (match_operand:ANYF                    0 "register_operand" "=f")
+	(unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
+		      (use (match_operand:ANYF 2 "register_operand" " f"))]
+		     UNSPEC_FMAX))]
+  "TARGET_HARD_FLOAT && !HONOR_SNANS (<MODE>mode)"
+  "fmax.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fmove")
+   (set_attr "mode" "<UNITMODE>")])
+
 (define_insn "smin<mode>3"
   [(set (match_operand:ANYF            0 "register_operand" "=f")
 	(smin:ANYF (match_operand:ANYF 1 "register_operand" " f")
diff --git a/gcc/testsuite/gcc.target/riscv/fmax-snan.c b/gcc/testsuite/gcc.target/riscv/fmax-snan.c
new file mode 100644
index 00000000000..ba4823a18b3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fmax-snan.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-finite-math-only -fsigned-zeros -fsignaling-nans -dp" } */
+
+double
+fmax (double x, double y)
+{
+  return __builtin_fmax (x, y);
+}
+
+/* { dg-final { scan-assembler-not "\tfmax\\.d\t" } } */
+/* { dg-final { scan-assembler-not "\tfge\\.d\t" } } */
+/* { dg-final { scan-assembler "\t(call|tail)\tfmax\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/fmax.c b/gcc/testsuite/gcc.target/riscv/fmax.c
new file mode 100644
index 00000000000..c71d35c9f9d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fmax.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-finite-math-only -fsigned-zeros -fno-signaling-nans -dp" } */
+
+double
+fmax (double x, double y)
+{
+  return __builtin_fmax (x, y);
+}
+
+/* { dg-final { scan-assembler-not "\ttail\tfmax\t" } } */
+/* { dg-final { scan-assembler-not "\tfge\\.d\t" } } */
+/* { dg-final { scan-assembler "\tfmax\\.d\t\[^\n\]* fmaxdf3\n" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/fmaxf-snan.c b/gcc/testsuite/gcc.target/riscv/fmaxf-snan.c
new file mode 100644
index 00000000000..faada3a5723
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fmaxf-snan.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-finite-math-only -fsigned-zeros -fsignaling-nans -dp" } */
+
+float
+fmaxf (float x, float y)
+{
+  return __builtin_fmaxf (x, y);
+}
+
+/* { dg-final { scan-assembler-not "\tfmax\\.s\t" } } */
+/* { dg-final { scan-assembler-not "\tfge\\.s\t" } } */
+/* { dg-final { scan-assembler "\t(call|tail)\tfmaxf\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/fmaxf.c b/gcc/testsuite/gcc.target/riscv/fmaxf.c
new file mode 100644
index 00000000000..f9980166887
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fmaxf.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-finite-math-only -fsigned-zeros -fno-signaling-nans -dp" } */
+
+float
+fmaxf (float x, float y)
+{
+  return __builtin_fmaxf (x, y);
+}
+
+/* { dg-final { scan-assembler-not "\ttail\tfmaxf\t" } } */
+/* { dg-final { scan-assembler-not "\tfge\\.s\t" } } */
+/* { dg-final { scan-assembler "\tfmax\\.s\t\[^\n\]* fmaxsf3\n" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/fmin-snan.c b/gcc/testsuite/gcc.target/riscv/fmin-snan.c
new file mode 100644
index 00000000000..b511380c2d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fmin-snan.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-finite-math-only -fsigned-zeros -fsignaling-nans -dp" } */
+
+double
+fmin (double x, double y)
+{
+  return __builtin_fmin (x, y);
+}
+
+/* { dg-final { scan-assembler-not "\tfmin\\.d\t" } } */
+/* { dg-final { scan-assembler-not "\tfle\\.d\t" } } */
+/* { dg-final { scan-assembler "\t(call|tail)\tfmin\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/fmin.c b/gcc/testsuite/gcc.target/riscv/fmin.c
new file mode 100644
index 00000000000..9634abd19af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fmin.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-finite-math-only -fsigned-zeros -fno-signaling-nans -dp" } */
+
+double
+fmin (double x, double y)
+{
+  return __builtin_fmin (x, y);
+}
+
+/* { dg-final { scan-assembler-not "\ttail\tfmin\t" } } */
+/* { dg-final { scan-assembler-not "\tfle\\.d\t" } } */
+/* { dg-final { scan-assembler "\tfmin\\.d\t\[^\n\]* fmindf3\n" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/fminf-snan.c b/gcc/testsuite/gcc.target/riscv/fminf-snan.c
new file mode 100644
index 00000000000..39dd8fee278
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fminf-snan.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-finite-math-only -fsigned-zeros -fsignaling-nans -dp" } */
+
+float
+fminf (float x, float y)
+{
+  return __builtin_fminf (x, y);
+}
+
+/* { dg-final { scan-assembler-not "\tfmin\\.s\t" } } */
+/* { dg-final { scan-assembler-not "\tfle\\.s\t" } } */
+/* { dg-final { scan-assembler "\t(call|tail)\tfminf\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/fminf.c b/gcc/testsuite/gcc.target/riscv/fminf.c
new file mode 100644
index 00000000000..9a3687be309
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fminf.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-finite-math-only -fsigned-zeros -fno-signaling-nans -dp" } */
+
+float
+fminf (float x, float y)
+{
+  return __builtin_fminf (x, y);
+}
+
+/* { dg-final { scan-assembler-not "\ttail\tfminf\t" } } */
+/* { dg-final { scan-assembler-not "\tfle\\.s\t" } } */
+/* { dg-final { scan-assembler "\tfmin\\.s\t\[^\n\]* fminsf3\n" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/smax-ieee.c b/gcc/testsuite/gcc.target/riscv/smax-ieee.c
new file mode 100644
index 00000000000..3a98aeb45ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/smax-ieee.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-ffinite-math-only -fsigned-zeros -dp" } */
+
+double
+smax (double x, double y)
+{
+  return x >= y ? x : y;
+}
+
+/* { dg-final { scan-assembler-not "\t(call|tail)\tfmax\t" } } */
+/* { dg-final { scan-assembler-not "\tfmax\\.d\t" } } */
+/* { dg-final { scan-assembler "\tfge\\.d\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/smax.c b/gcc/testsuite/gcc.target/riscv/smax.c
new file mode 100644
index 00000000000..d806c632fae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/smax.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-ffinite-math-only -fno-signed-zeros -dp" } */
+
+double
+smax (double x, double y)
+{
+  return x >= y ? x : y;
+}
+
+/* { dg-final { scan-assembler-not "\ttail\tfmax\t" } } */
+/* { dg-final { scan-assembler-not "\tfge\\.d\t" } } */
+/* { dg-final { scan-assembler "\tfmax\\.d\t\[^\n\]* smaxdf3\n" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/smaxf-ieee.c b/gcc/testsuite/gcc.target/riscv/smaxf-ieee.c
new file mode 100644
index 00000000000..6cf23d789b6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/smaxf-ieee.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-ffinite-math-only -fsigned-zeros -dp" } */
+
+float
+smaxf (float x, float y)
+{
+  return x >= y ? x : y;
+}
+
+/* { dg-final { scan-assembler-not "\t(call|tail)\tfmaxf\t" } } */
+/* { dg-final { scan-assembler-not "\tfmax\\.s\t" } } */
+/* { dg-final { scan-assembler "\tfge\\.s\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/smaxf.c b/gcc/testsuite/gcc.target/riscv/smaxf.c
new file mode 100644
index 00000000000..d6a7a7f84cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/smaxf.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-ffinite-math-only -fno-signed-zeros -dp" } */
+
+float
+smaxf (float x, float y)
+{
+  return x >= y ? x : y;
+}
+
+/* { dg-final { scan-assembler-not "\ttail\tfmaxf\t" } } */
+/* { dg-final { scan-assembler-not "\tfge\\.s\t" } } */
+/* { dg-final { scan-assembler "\tfmax\\.s\t\[^\n\]* smaxsf3\n" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/smin-ieee.c b/gcc/testsuite/gcc.target/riscv/smin-ieee.c
new file mode 100644
index 00000000000..c0a148c37cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/smin-ieee.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-ffinite-math-only -fsigned-zeros -dp" } */
+
+double
+smin (double x, double y)
+{
+  return x <= y ? x : y;
+}
+
+/* { dg-final { scan-assembler-not "\t(call|tail)\tfmin\t" } } */
+/* { dg-final { scan-assembler-not "\tfmin\\.d\t" } } */
+/* { dg-final { scan-assembler "\tfle\\.d\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/smin.c b/gcc/testsuite/gcc.target/riscv/smin.c
new file mode 100644
index 00000000000..e325e9a1c7c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/smin.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-ffinite-math-only -fno-signed-zeros -dp" } */
+
+double
+smin (double x, double y)
+{
+  return x <= y ? x : y;
+}
+
+/* { dg-final { scan-assembler-not "\ttail\tfmin\t" } } */
+/* { dg-final { scan-assembler-not "\tfle\\.d\t" } } */
+/* { dg-final { scan-assembler "\tfmin\\.d\t\[^\n\]* smindf3\n" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sminf-ieee.c b/gcc/testsuite/gcc.target/riscv/sminf-ieee.c
new file mode 100644
index 00000000000..353e7a18704
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sminf-ieee.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-ffinite-math-only -fsigned-zeros -dp" } */
+
+float
+sminf (float x, float y)
+{
+  return x <= y ? x : y;
+}
+
+/* { dg-final { scan-assembler-not "\t(call|tail)\tfminf\t" } } */
+/* { dg-final { scan-assembler-not "\tfmin\\.s\t" } } */
+/* { dg-final { scan-assembler "\tfle\\.s\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sminf.c b/gcc/testsuite/gcc.target/riscv/sminf.c
new file mode 100644
index 00000000000..f0ba7b43bdf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sminf.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-ffinite-math-only -fno-signed-zeros -dp" } */
+
+float
+sminf (float x, float y)
+{
+  return x <= y ? x : y;
+}
+
+/* { dg-final { scan-assembler-not "\ttail\tfminf\t" } } */
+/* { dg-final { scan-assembler-not "\tfle\\.s\t" } } */
+/* { dg-final { scan-assembler "\tfmin\\.s\t\[^\n\]* sminsf3\n" } } */


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-05-10 14:04 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-10 14:04 [gcc r13-264] RISC-V: Provide `fmin'/`fmax' RTL patterns Maciej W. Rozycki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).