[PATCH 3/5] riscv: Use Zfa for fmaximum and fminimum

Julian Zhu <[email protected]> Thu, 6 Aug 2026 18:25:29 +0800
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <[email protected]>
Use the Zfa fmaxm and fminm instructions for the NaN-propagating C23 maximum and minimum operations in float and double precision.  Keep the F/D implementation as the fallback when Zfa is unavailable.

Signed-off-by: Julian Zhu <[email protected]>
---
 sysdeps/riscv/rvd/s_fmaximum.c  | 9 +++++++--
 sysdeps/riscv/rvd/s_fminimum.c  | 9 +++++++--
 sysdeps/riscv/rvf/s_fmaximumf.c | 9 +++++++--
 sysdeps/riscv/rvf/s_fminimumf.c | 9 +++++++--
 4 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/sysdeps/riscv/rvd/s_fmaximum.c b/sysdeps/riscv/rvd/s_fmaximum.c
index d514fb17a6..a9b99a0fd5 100644
--- a/sysdeps/riscv/rvd/s_fmaximum.c
+++ b/sysdeps/riscv/rvd/s_fmaximum.c
@@ -21,17 +21,22 @@
 
 /* fmaximum is the IEEE 754-2019 maximum operation: like fmaximum_num but
    NaN-propagating, so a NaN operand yields a quiet NaN result (and a
-   signaling NaN also raises the invalid exception).  RISC-V's fmax.d gives
-   the correct result whenever neither operand is NaN, so only the NaN case
+   signaling NaN also raises the invalid exception).  Zfa's fmaxm.d
+   implements it in a single instruction.  Without Zfa, fmax.d gives the
+   correct result whenever neither operand is NaN, so only the NaN case
    needs to be handled explicitly.  */
 
 double
 __fmaximum (double x, double y)
 {
   double res;
+#ifdef __riscv_zfa
+  asm ("fmaxm.d %0, %1, %2" : "=f" (res) : "f" (x), "f" (y));
+#else
   if (__glibc_unlikely (isunordered (x, y)))
     return x + y;
   asm ("fmax.d %0, %1, %2" : "=f" (res) : "f" (x), "f" (y));
+#endif
   return res;
 }
 libm_alias_double (__fmaximum, fmaximum)
diff --git a/sysdeps/riscv/rvd/s_fminimum.c b/sysdeps/riscv/rvd/s_fminimum.c
index 608b37bed5..7b37d953fe 100644
--- a/sysdeps/riscv/rvd/s_fminimum.c
+++ b/sysdeps/riscv/rvd/s_fminimum.c
@@ -21,17 +21,22 @@
 
 /* fminimum is the IEEE 754-2019 minimum operation: like fminimum_num but
    NaN-propagating, so a NaN operand yields a quiet NaN result (and a
-   signaling NaN also raises the invalid exception).  RISC-V's fmin.d gives
-   the correct result whenever neither operand is NaN, so only the NaN case
+   signaling NaN also raises the invalid exception).  Zfa's fminm.d
+   implements it in a single instruction.  Without Zfa, fmin.d gives the
+   correct result whenever neither operand is NaN, so only the NaN case
    needs to be handled explicitly.  */
 
 double
 __fminimum (double x, double y)
 {
   double res;
+#ifdef __riscv_zfa
+  asm ("fminm.d %0, %1, %2" : "=f" (res) : "f" (x), "f" (y));
+#else
   if (__glibc_unlikely (isunordered (x, y)))
     return x + y;
   asm ("fmin.d %0, %1, %2" : "=f" (res) : "f" (x), "f" (y));
+#endif
   return res;
 }
 libm_alias_double (__fminimum, fminimum)
diff --git a/sysdeps/riscv/rvf/s_fmaximumf.c b/sysdeps/riscv/rvf/s_fmaximumf.c
index daa71f0f34..6aad94d149 100644
--- a/sysdeps/riscv/rvf/s_fmaximumf.c
+++ b/sysdeps/riscv/rvf/s_fmaximumf.c
@@ -19,16 +19,21 @@
 #include <math.h>
 #include <libm-alias-float.h>
 
-/* See s_fmaximum.c for a description of the semantics.  RISC-V's fmax.s
-   handles the ordered case, so only NaNs need explicit handling.  */
+/* See s_fmaximum.c for a description of the semantics.  Zfa's fmaxm.s
+   implements maximum for single precision; otherwise fmax.s handles the
+   non-NaN case.  */
 
 float
 __fmaximumf (float x, float y)
 {
   float res;
+#ifdef __riscv_zfa
+  asm ("fmaxm.s %0, %1, %2" : "=f" (res) : "f" (x), "f" (y));
+#else
   if (__glibc_unlikely (isunordered (x, y)))
     return x + y;
   asm ("fmax.s %0, %1, %2" : "=f" (res) : "f" (x), "f" (y));
+#endif
   return res;
 }
 libm_alias_float (__fmaximum, fmaximum)
diff --git a/sysdeps/riscv/rvf/s_fminimumf.c b/sysdeps/riscv/rvf/s_fminimumf.c
index 2dba5412f8..6be5cb81d0 100644
--- a/sysdeps/riscv/rvf/s_fminimumf.c
+++ b/sysdeps/riscv/rvf/s_fminimumf.c
@@ -19,16 +19,21 @@
 #include <math.h>
 #include <libm-alias-float.h>
 
-/* See s_fminimum.c for a description of the semantics.  RISC-V's fmin.s
-   handles the ordered case, so only NaNs need explicit handling.  */
+/* See s_fminimum.c for a description of the semantics.  Zfa's fminm.s
+   implements minimum for single precision; otherwise fmin.s handles the
+   non-NaN case.  */
 
 float
 __fminimumf (float x, float y)
 {
   float res;
+#ifdef __riscv_zfa
+  asm ("fminm.s %0, %1, %2" : "=f" (res) : "f" (x), "f" (y));
+#else
   if (__glibc_unlikely (isunordered (x, y)))
     return x + y;
   asm ("fmin.s %0, %1, %2" : "=f" (res) : "f" (x), "f" (y));
+#endif
   return res;
 }
 libm_alias_float (__fminimum, fminimum)
-- 
2.53.0