diff mbox series

[RESEND,committed,v4] RISC-V: Provide `fmin'/`fmax' RTL patterns

Message ID alpine.DEB.2.20.2205101419240.11552@tpp.orcam.me.uk
State New
Headers show
Series [RESEND,committed,v4] RISC-V: Provide `fmin'/`fmax' RTL patterns | expand

Commit Message

Maciej W. Rozycki May 10, 2022, 2:04 p.m. UTC
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.
---
On Mon, 28 Feb 2022, Jim Wilson wrote:

> On Tue, Feb 8, 2022 at 4:35 AM Maciej W. Rozycki <macro@embecosm.com> wrote:
> 
> >         gcc/
> >         * config/riscv/riscv.md (UNSPEC_FMIN, UNSPEC_FMAX): New
> >         constants.
> >         (fmin<mode>3, fmax<mode>3): New insns.
> > ...
> 
> 
> I tried testing on some of the hardware I have.  Both the HiFive Unleashed
> (2018) and HiFive Unmatched (2021) implement the current definition of
> fmin/fmax.  But the Allwinner Nezha (2021) implements the previous
> definition of fmin/fmax.  SiFive was involved with the fmin/fmax change, so
> it isn't surprising that they implemented the new semantics before other
> companies.  The Nezha board with the T-Head C906 is a popular one, so we do
> need to continue to support the 2017 spec, which your patch does with the
> HONORS_SNAN checks.  I agree that we don't need to worry about spec
> versions older than that.
> 
> This looks OK to me.
> 
> I've got builds running in parallel on the Unleashed and Unmatched to test
> but that will take a couple of days and I don't expect any problems since
> you already tested it.  I could do a build on the Nezha if I had to, but
> that would take at least a week as it is a much slower board and I'd rather
> not do that unless I have to.  This is hardware implementing the older spec
> that you probably haven't tested though.

 Correct, I have only verified this change with an Unmatched system.

 Since Stage 1 is now back I have rerun regression testing with the change 
included, both without and with `-fsignaling-nans' given.  There were no 
changes in results between the runs except for intermittent failures with 
gfortran.dg/ISO_Fortran_binding_17.f90 at various optimisation levels, 
clearly unrelated as this test does some DWARF information inspection.

 I have committed this change now, thank you for your review.

  Maciej

Changes from v3:

- Quote `\' characters in `scan-assembler' for literal `.' in regexp.

- Mechanically update ChangeLog to have its entries separately for the 
  testsuite.

Changes from v2:

- Use UNSPECs for the `fmin'/`fmax' patterns, so that they cannot be 
  matched by the RTL expression.

- Revert the `HONOR_SNANS (<MODE>mode)' restriction for the `smin'/`smax'
  patterns; it was wrong, because HONOR_SNANS implies HONOR_NANS, and that 
  is not true for `-ffinite-math-only' where `smin'/`smax' still have to 
  work.

- Add test cases.

- Further clarify ISA/extension revisions/versions.

Changes from v1:

- Adjust heading from "RISC-V: Replace `smin'/`smax' RTL patterns with 
  `fmin'/`fmax'".

- Do not remove `smin'/`smax' patterns; instead make them available if
  `HONOR_SNANS (<MODE>mode)'.

- Make `fmin'/`fmax' patterns available if `!HONOR_SNANS (<MODE>mode)' 
  only.

- Update description accordingly; refer r2.2 and r20190608 ISA specs.
---
 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(+)

gcc-riscv-fmin-fmax.diff

Comments

Kito Cheng May 10, 2022, 3:48 p.m. UTC | #1
Thanks Maciej!

On Tue, May 10, 2022 at 10:05 PM Maciej W. Rozycki <macro@embecosm.com> wrote:
>
> 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.
> ---
> On Mon, 28 Feb 2022, Jim Wilson wrote:
>
> > On Tue, Feb 8, 2022 at 4:35 AM Maciej W. Rozycki <macro@embecosm.com> wrote:
> >
> > >         gcc/
> > >         * config/riscv/riscv.md (UNSPEC_FMIN, UNSPEC_FMAX): New
> > >         constants.
> > >         (fmin<mode>3, fmax<mode>3): New insns.
> > > ...
> >
> >
> > I tried testing on some of the hardware I have.  Both the HiFive Unleashed
> > (2018) and HiFive Unmatched (2021) implement the current definition of
> > fmin/fmax.  But the Allwinner Nezha (2021) implements the previous
> > definition of fmin/fmax.  SiFive was involved with the fmin/fmax change, so
> > it isn't surprising that they implemented the new semantics before other
> > companies.  The Nezha board with the T-Head C906 is a popular one, so we do
> > need to continue to support the 2017 spec, which your patch does with the
> > HONORS_SNAN checks.  I agree that we don't need to worry about spec
> > versions older than that.
> >
> > This looks OK to me.
> >
> > I've got builds running in parallel on the Unleashed and Unmatched to test
> > but that will take a couple of days and I don't expect any problems since
> > you already tested it.  I could do a build on the Nezha if I had to, but
> > that would take at least a week as it is a much slower board and I'd rather
> > not do that unless I have to.  This is hardware implementing the older spec
> > that you probably haven't tested though.
>
>  Correct, I have only verified this change with an Unmatched system.
>
>  Since Stage 1 is now back I have rerun regression testing with the change
> included, both without and with `-fsignaling-nans' given.  There were no
> changes in results between the runs except for intermittent failures with
> gfortran.dg/ISO_Fortran_binding_17.f90 at various optimisation levels,
> clearly unrelated as this test does some DWARF information inspection.
>
>  I have committed this change now, thank you for your review.
>
>   Maciej
>
> Changes from v3:
>
> - Quote `\' characters in `scan-assembler' for literal `.' in regexp.
>
> - Mechanically update ChangeLog to have its entries separately for the
>   testsuite.
>
> Changes from v2:
>
> - Use UNSPECs for the `fmin'/`fmax' patterns, so that they cannot be
>   matched by the RTL expression.
>
> - Revert the `HONOR_SNANS (<MODE>mode)' restriction for the `smin'/`smax'
>   patterns; it was wrong, because HONOR_SNANS implies HONOR_NANS, and that
>   is not true for `-ffinite-math-only' where `smin'/`smax' still have to
>   work.
>
> - Add test cases.
>
> - Further clarify ISA/extension revisions/versions.
>
> Changes from v1:
>
> - Adjust heading from "RISC-V: Replace `smin'/`smax' RTL patterns with
>   `fmin'/`fmax'".
>
> - Do not remove `smin'/`smax' patterns; instead make them available if
>   `HONOR_SNANS (<MODE>mode)'.
>
> - Make `fmin'/`fmax' patterns available if `!HONOR_SNANS (<MODE>mode)'
>   only.
>
> - Update description accordingly; refer r2.2 and r20190608 ISA specs.
> ---
>  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(+)
>
> gcc-riscv-fmin-fmax.diff
> Index: gcc/gcc/config/riscv/riscv.md
> ===================================================================
> --- gcc.orig/gcc/config/riscv/riscv.md
> +++ gcc/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")
> Index: gcc/gcc/testsuite/gcc.target/riscv/fmax-snan.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/fmax.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/fmaxf-snan.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/fmaxf.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/fmin-snan.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/fmin.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/fminf-snan.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/fminf.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/smax-ieee.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/smax.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/smaxf-ieee.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/smaxf.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/smin-ieee.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/smin.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/sminf-ieee.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
> Index: gcc/gcc/testsuite/gcc.target/riscv/sminf.c
> ===================================================================
> --- /dev/null
> +++ gcc/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" } } */
Palmer Dabbelt May 13, 2022, 4:51 p.m. UTC | #2
On Tue, 10 May 2022 08:48:33 PDT (-0700), gcc-patches@gcc.gnu.org wrote:
> Thanks Maciej!

Yep.  We should have a NEWS entry, though, as this one is user-visible 
and may be tricky to sort out if it turns out there is some HW lurking 
around that has the old behavior.

> On Tue, May 10, 2022 at 10:05 PM Maciej W. Rozycki <macro@embecosm.com> wrote:
>>
>> 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.
>> ---
>> On Mon, 28 Feb 2022, Jim Wilson wrote:
>>
>> > On Tue, Feb 8, 2022 at 4:35 AM Maciej W. Rozycki <macro@embecosm.com> wrote:
>> >
>> > >         gcc/
>> > >         * config/riscv/riscv.md (UNSPEC_FMIN, UNSPEC_FMAX): New
>> > >         constants.
>> > >         (fmin<mode>3, fmax<mode>3): New insns.
>> > > ...
>> >
>> >
>> > I tried testing on some of the hardware I have.  Both the HiFive Unleashed
>> > (2018) and HiFive Unmatched (2021) implement the current definition of
>> > fmin/fmax.  But the Allwinner Nezha (2021) implements the previous
>> > definition of fmin/fmax.  SiFive was involved with the fmin/fmax change, so
>> > it isn't surprising that they implemented the new semantics before other
>> > companies.  The Nezha board with the T-Head C906 is a popular one, so we do
>> > need to continue to support the 2017 spec, which your patch does with the
>> > HONORS_SNAN checks.  I agree that we don't need to worry about spec
>> > versions older than that.
>> >
>> > This looks OK to me.
>> >
>> > I've got builds running in parallel on the Unleashed and Unmatched to test
>> > but that will take a couple of days and I don't expect any problems since
>> > you already tested it.  I could do a build on the Nezha if I had to, but
>> > that would take at least a week as it is a much slower board and I'd rather
>> > not do that unless I have to.  This is hardware implementing the older spec
>> > that you probably haven't tested though.
>>
>>  Correct, I have only verified this change with an Unmatched system.
>>
>>  Since Stage 1 is now back I have rerun regression testing with the change
>> included, both without and with `-fsignaling-nans' given.  There were no
>> changes in results between the runs except for intermittent failures with
>> gfortran.dg/ISO_Fortran_binding_17.f90 at various optimisation levels,
>> clearly unrelated as this test does some DWARF information inspection.
>>
>>  I have committed this change now, thank you for your review.
>>
>>   Maciej
>>
>> Changes from v3:
>>
>> - Quote `\' characters in `scan-assembler' for literal `.' in regexp.
>>
>> - Mechanically update ChangeLog to have its entries separately for the
>>   testsuite.
>>
>> Changes from v2:
>>
>> - Use UNSPECs for the `fmin'/`fmax' patterns, so that they cannot be
>>   matched by the RTL expression.
>>
>> - Revert the `HONOR_SNANS (<MODE>mode)' restriction for the `smin'/`smax'
>>   patterns; it was wrong, because HONOR_SNANS implies HONOR_NANS, and that
>>   is not true for `-ffinite-math-only' where `smin'/`smax' still have to
>>   work.
>>
>> - Add test cases.
>>
>> - Further clarify ISA/extension revisions/versions.
>>
>> Changes from v1:
>>
>> - Adjust heading from "RISC-V: Replace `smin'/`smax' RTL patterns with
>>   `fmin'/`fmax'".
>>
>> - Do not remove `smin'/`smax' patterns; instead make them available if
>>   `HONOR_SNANS (<MODE>mode)'.
>>
>> - Make `fmin'/`fmax' patterns available if `!HONOR_SNANS (<MODE>mode)'
>>   only.
>>
>> - Update description accordingly; refer r2.2 and r20190608 ISA specs.
>> ---
>>  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(+)
>>
>> gcc-riscv-fmin-fmax.diff
>> Index: gcc/gcc/config/riscv/riscv.md
>> ===================================================================
>> --- gcc.orig/gcc/config/riscv/riscv.md
>> +++ gcc/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")
>> Index: gcc/gcc/testsuite/gcc.target/riscv/fmax-snan.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/fmax.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/fmaxf-snan.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/fmaxf.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/fmin-snan.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/fmin.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/fminf-snan.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/fminf.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/smax-ieee.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/smax.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/smaxf-ieee.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/smaxf.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/smin-ieee.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/smin.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/sminf-ieee.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
>> Index: gcc/gcc/testsuite/gcc.target/riscv/sminf.c
>> ===================================================================
>> --- /dev/null
>> +++ gcc/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" } } */
Maciej W. Rozycki May 13, 2022, 7:57 p.m. UTC | #3
On Fri, 13 May 2022, Palmer Dabbelt wrote:

> Yep.  We should have a NEWS entry, though, as this one is user-visible and may
> be tricky to sort out if it turns out there is some HW lurking around that has
> the old behavior.

 Hmm, should we?  We only support `-misa-spec=<2.2|20190608|20191213>' 
already and this update is fine for r.2.2+.  If someone has pre-r.2.2 hw, 
then it's been already unsupported even before this change (as from GCC 11 
AFAICS).  Have I missed anything?

  Maciej
Palmer Dabbelt May 14, 2022, 2:30 p.m. UTC | #4
On Fri, 13 May 2022 12:57:35 PDT (-0700), macro@embecosm.com wrote:
> On Fri, 13 May 2022, Palmer Dabbelt wrote:
>
>> Yep.  We should have a NEWS entry, though, as this one is user-visible and may
>> be tricky to sort out if it turns out there is some HW lurking around that has
>> the old behavior.
>
>  Hmm, should we?  We only support `-misa-spec=<2.2|20190608|20191213>'
> already and this update is fine for r.2.2+.  If someone has pre-r.2.2 hw,
> then it's been already unsupported even before this change (as from GCC 11
> AFAICS).  Have I missed anything?

I have no idea, but either you did or I did...

IIUC this actually changed for version 2.2 of the F extension, which 
happened well after version 2.2 of the ISA manual.  I see eb78171 ("F/D 
extensions to v2.2") both changing the version and noting the change, 
with cd20cee ("FMIN/FMAX now implement minimumNumber/maximumNumber, not 
minNum/maxNum") actually making the change and also adding some notation 
about this being a draft of version 2.3 of the ISA manual (which was 
presumably never released as 2.3 but instead one of those other tags).  
It also calls this out as F 2.0, but I'm assuming that's non-canonical 
because this is a draft.

Complicating this is that there's some HW that predates that next spec 
but implements some of the post-2.2 behavior like this -- IIUC that's 
how the SiFive FE510-G000 (on the HiFive Unleashed) works and that's the 
only hardware any of us know about from that timeframe, but in practice 
there's a lot of HW floating around that we don't know of and it's going 
to be all but impossible to tell what ended up implemented in that 
two-year gap between releases.

I do now remember having some discussions on this and things getting so 
complicated I gave up, not sure if I just care enough to chase it down 
this time or if it was something else -- it's first thing on Saturday 
morning so it could go either way :)
Maciej W. Rozycki May 16, 2022, 10:28 a.m. UTC | #5
On Sat, 14 May 2022, Palmer Dabbelt wrote:

> >  Hmm, should we?  We only support `-misa-spec=<2.2|20190608|20191213>'
> > already and this update is fine for r.2.2+.  If someone has pre-r.2.2 hw,
> > then it's been already unsupported even before this change (as from GCC 11
> > AFAICS).  Have I missed anything?
> 
> I have no idea, but either you did or I did...
> 
> IIUC this actually changed for version 2.2 of the F extension, which happened
> well after version 2.2 of the ISA manual.  I see eb78171 ("F/D extensions to
> v2.2") both changing the version and noting the change, with cd20cee
> ("FMIN/FMAX now implement minimumNumber/maximumNumber, not minNum/maxNum")
> actually making the change and also adding some notation about this being a
> draft of version 2.3 of the ISA manual (which was presumably never released as
> 2.3 but instead one of those other tags).  It also calls this out as F 2.0,
> but I'm assuming that's non-canonical because this is a draft.

 So the only actual concern with F/D 2.0 vs F/D 2.2 is the change of the 
treatment of signalling NaNs, which is why the new `fmin'/`fmax' patterns 
are keyed with !HONOR_SNANS so that code produces the same results from 
ISA r.2.2 onwards.  I am sorry if that got buried in the elaborate change 
description.

 Once we've got the generic bits available for minimumNumber/maximumNumber 
we can add suitable `*min'/`*max' patterns that implement these operations 
and key them with (riscv_isa_spec >= ISA_SPEC_CLASS_20190608).

 Does this explanation clear your concern?

  Maciej
diff mbox series

Patch

Index: gcc/gcc/config/riscv/riscv.md
===================================================================
--- gcc.orig/gcc/config/riscv/riscv.md
+++ gcc/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")
Index: gcc/gcc/testsuite/gcc.target/riscv/fmax-snan.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/fmax.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/fmaxf-snan.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/fmaxf.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/fmin-snan.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/fmin.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/fminf-snan.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/fminf.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/smax-ieee.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/smax.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/smaxf-ieee.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/smaxf.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/smin-ieee.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/smin.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/sminf-ieee.c
===================================================================
--- /dev/null
+++ gcc/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" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/sminf.c
===================================================================
--- /dev/null
+++ gcc/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" } } */