[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