[v2,GCC13] RISC-V: Provide `fmin'/`fmax' RTL patterns

Message ID alpine.DEB.2.20.2201260449020.11348@tpp.orcam.me.uk
State Deferred, archived
Headers
Series [v2,GCC13] RISC-V: Provide `fmin'/`fmax' RTL patterns |

Commit Message

Maciej W. Rozycki Jan. 26, 2022, 8:22 p.m. UTC
  As at r2.2 of the RISC-V ISA specification[1] 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 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 the existing `smin<mode>3' and `smax<mode>3' 
patterns otherwise.  For clarity and maintenance error resistance add an 
explicit condition to the latter patterns rather than relying on source 
code ordering for where the respective RTL insns are matched by their 
operation rather than being explicitly referred to by their names.

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 (fmin<mode>3, fmax<mode>3): New insns.
	(smin<mode>3, smax<mode>3): Only enable if `HONOR_SNANS'.
---
Hi,

 This updated version has passed full GCC regression testing (including 
the D frontend this time) with the `riscv64-linux-gnu' target using the 
HiFive Unmatched (U74 CPU) target board.

 Any further questions or comments?  Otherwise OK once GCC 13 has opened?

  Maciej

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 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

gcc-riscv-fmin-fmax.diff
  

Patch

Index: gcc/gcc/config/riscv/riscv.md
===================================================================
--- gcc.orig/gcc/config/riscv/riscv.md
+++ gcc/gcc/config/riscv/riscv.md
@@ -1214,11 +1214,29 @@ 
 ;;
 ;;  ....................
 
+(define_insn "fmin<mode>3"
+  [(set (match_operand:ANYF            0 "register_operand" "=f")
+	(smin:ANYF (match_operand:ANYF 1 "register_operand" " f")
+		   (match_operand:ANYF 2 "register_operand" " f")))]
+  "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")
+	(smax:ANYF (match_operand:ANYF 1 "register_operand" " f")
+		   (match_operand:ANYF 2 "register_operand" " f")))]
+  "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")
 		   (match_operand:ANYF 2 "register_operand" " f")))]
-  "TARGET_HARD_FLOAT"
+  "TARGET_HARD_FLOAT && HONOR_SNANS (<MODE>mode)"
   "fmin.<fmt>\t%0,%1,%2"
   [(set_attr "type" "fmove")
    (set_attr "mode" "<UNITMODE>")])
@@ -1227,7 +1245,7 @@ 
   [(set (match_operand:ANYF            0 "register_operand" "=f")
 	(smax:ANYF (match_operand:ANYF 1 "register_operand" " f")
 		   (match_operand:ANYF 2 "register_operand" " f")))]
-  "TARGET_HARD_FLOAT"
+  "TARGET_HARD_FLOAT && HONOR_SNANS (<MODE>mode)"
   "fmax.<fmt>\t%0,%1,%2"
   [(set_attr "type" "fmove")
    (set_attr "mode" "<UNITMODE>")])