[PATCH 1/4] LoongArch: Optimize f{max,min}imum{,f}

Xi Ruoyao xry111@xry111.site
Mon Feb 24 09:50:52 GMT 2025


The code now looks like:

	fclass.s        $fa2, $fa0
	movfr2gr.s      $t0, $fa2
	slli.w          $t0, $t0, 0x0
	fclass.s        $fa2, $fa1
	movfr2gr.s      $t1, $fa2
	or              $t0, $t0, $t1
	andi            $t0, $t0, 0x3
	bnez            $t0, 1f
	fmin.s          $fa0, $fa0, $fa1
	ret
	1:
	fmul.s		$fa0, $fa0, $fa1
	ret

This looks really bad, with expensive movfr2gr instructions, redundant
sign-extensions and masking (arguably it's a compiler
missed-optimzation), and a branch.  Improve it so the code now looks
like:

	fcmp.cor.s      $fcc1, $fa1, $fa1
	fcmp.cor.s      $fcc0, $fa0, $fa0
	fsel            $fa2, $fa1, $fa0, $fcc1
	fsel            $fa0, $fa0, $fa1, $fcc0
	fmin.s          $fa0, $fa2, $fa0
	ret

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 sysdeps/loongarch/fpu/s_fmaximum.c  | 15 ++++-----------
 sysdeps/loongarch/fpu/s_fmaximumf.c | 15 ++++-----------
 sysdeps/loongarch/fpu/s_fminimum.c  | 15 ++++-----------
 sysdeps/loongarch/fpu/s_fminimumf.c | 15 ++++-----------
 4 files changed, 16 insertions(+), 44 deletions(-)

diff --git a/sysdeps/loongarch/fpu/s_fmaximum.c b/sysdeps/loongarch/fpu/s_fmaximum.c
index 07fc7214a1..b66360a948 100644
--- a/sysdeps/loongarch/fpu/s_fmaximum.c
+++ b/sysdeps/loongarch/fpu/s_fmaximum.c
@@ -24,17 +24,10 @@
 double
 __fmaximum (double x, double y)
 {
-  int x_cond;
-  int y_cond;
-  asm volatile ("fclass.d \t%0, %1" : "=f" (x_cond) : "f" (x));
-  asm volatile ("fclass.d \t%0, %1" : "=f" (y_cond) : "f" (y));
+  double a = __builtin_isnan (y) ? y : x;
+  double b = __builtin_isnan (x) ? x : y;
 
-  if (__glibc_unlikely((x_cond | y_cond) & _FCLASS_NAN))
-      return x * y;
-  else
-    {
-      asm volatile ("fmax.d \t%0, %1, %2" : "=f" (x) : "f" (x), "f" (y));
-      return x;
-    }
+  asm ("fmax.d \t%0, %1, %2" : "=f" (a) : "f" (a), "f" (b));
+  return a;
 }
 libm_alias_double (__fmaximum, fmaximum)
diff --git a/sysdeps/loongarch/fpu/s_fmaximumf.c b/sysdeps/loongarch/fpu/s_fmaximumf.c
index a518ccf348..adac184cbf 100644
--- a/sysdeps/loongarch/fpu/s_fmaximumf.c
+++ b/sysdeps/loongarch/fpu/s_fmaximumf.c
@@ -24,17 +24,10 @@
 float
 __fmaximumf (float x, float y)
 {
-  int x_cond;
-  int y_cond;
-  asm volatile ("fclass.s \t%0, %1" : "=f" (x_cond) : "f" (x));
-  asm volatile ("fclass.s \t%0, %1" : "=f" (y_cond) : "f" (y));
+  float a = __builtin_isnanf (y) ? y : x;
+  float b = __builtin_isnanf (x) ? x : y;
 
-  if (__glibc_unlikely((x_cond | y_cond) & _FCLASS_NAN))
-      return x * y;
-  else
-    {
-      asm volatile ("fmax.s \t%0, %1, %2" : "=f" (x) : "f" (x), "f" (y));
-      return x;
-    }
+  asm ("fmax.s \t%0, %1, %2" : "=f" (a) : "f" (a), "f" (b));
+  return a;
 }
 libm_alias_float (__fmaximum, fmaximum)
diff --git a/sysdeps/loongarch/fpu/s_fminimum.c b/sysdeps/loongarch/fpu/s_fminimum.c
index a63c357957..c8f77cd26b 100644
--- a/sysdeps/loongarch/fpu/s_fminimum.c
+++ b/sysdeps/loongarch/fpu/s_fminimum.c
@@ -24,17 +24,10 @@
 double
 __fminimum (double x, double y)
 {
-  int x_cond;
-  int y_cond;
-  asm volatile ("fclass.d \t%0, %1" : "=f" (x_cond) : "f" (x));
-  asm volatile ("fclass.d \t%0, %1" : "=f" (y_cond) : "f" (y));
+  double a = __builtin_isnan (y) ? y : x;
+  double b = __builtin_isnan (x) ? x : y;
 
-  if (__glibc_unlikely((x_cond | y_cond) & _FCLASS_NAN))
-      return x * y;
-  else
-    {
-      asm volatile ("fmin.d \t%0, %1, %2" : "=f" (x) : "f" (x), "f" (y));
-      return x;
-    }
+  asm ("fmin.d \t%0, %1, %2" : "=f" (a) : "f" (a), "f" (b));
+  return a;
 }
 libm_alias_double (__fminimum, fminimum)
diff --git a/sysdeps/loongarch/fpu/s_fminimumf.c b/sysdeps/loongarch/fpu/s_fminimumf.c
index 973a9f75d1..bbde1224ac 100644
--- a/sysdeps/loongarch/fpu/s_fminimumf.c
+++ b/sysdeps/loongarch/fpu/s_fminimumf.c
@@ -24,17 +24,10 @@
 float
 __fminimumf (float x, float y)
 {
-  int x_cond;
-  int y_cond;
-  asm volatile ("fclass.s \t%0, %1" : "=f" (x_cond) : "f" (x));
-  asm volatile ("fclass.s \t%0, %1" : "=f" (y_cond) : "f" (y));
+  float a = __builtin_isnanf (y) ? y : x;
+  float b = __builtin_isnanf (x) ? x : y;
 
-  if (__glibc_unlikely((x_cond | y_cond) & _FCLASS_NAN))
-      return x * y;
-  else
-    {
-      asm volatile ("fmin.s \t%0, %1, %2" : "=f" (x) : "f" (x), "f" (y));
-      return x;
-    }
+  asm ("fmin.s \t%0, %1, %2" : "=f" (a) : "f" (a), "f" (b));
+  return a;
 }
 libm_alias_float (__fminimum, fminimum)
-- 
2.48.1



More information about the Libc-alpha mailing list