[PATCH v2] x86-64: Don't use asm statement for trunc/truncf
H.J. Lu
hjl.tools@gmail.com
Fri Sep 12 12:57:01 GMT 2025
Compiler inlines trunc and truncf with SSE4.1. But older versions of GCC
doesn't inline them with -Os:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121861
Don't use asm statement for trunc and truncf if compiler can inline them
with -Os. It removes one register move with GCC 16:
__modff_sse41: __modff_sse41:
.LFB23: .LFB23:
.cfi_startproc .cfi_startproc
endbr64 endbr64
subq $24, %rsp subq $24, %rsp
.cfi_def_cfa_offset 32 .cfi_def_cfa_offset 32
movq %fs:40, %rax movq %fs:40, %rax
movq %rax, 8(%rsp) movq %rax, 8(%rsp)
xorl %eax, %eax xorl %eax, %eax
movd %xmm0, %eax movd %xmm0, %eax
addl %eax, %eax addl %eax, %eax
cmpl $-16777216, %eax cmpl $-16777216, %eax
je .L7 je .L7
> movaps %xmm0, %xmm3
movaps %xmm0, %xmm4 movaps %xmm0, %xmm4
movss .LC0(%rip), %xmm2 | movss .LC0(%rip), %xmm1
movaps %xmm2, %xmm3 | movaps %xmm1, %xmm2
andps %xmm0, %xmm2 | roundss $11, %xmm3, %xmm3
roundss $11, %xmm0, %xmm1 | subss %xmm3, %xmm4
subss %xmm1, %xmm4 | andps %xmm0, %xmm1
andnps %xmm4, %xmm3 | andnps %xmm4, %xmm2
orps %xmm3, %xmm2 | orps %xmm2, %xmm1
.L3: .L3:
movss %xmm1, (%rdi) | movss %xmm3, (%rdi)
movq 8(%rsp), %rax movq 8(%rsp), %rax
subq %fs:40, %rax subq %fs:40, %rax
jne .L8 jne .L8
movaps %xmm2, %xmm0 | movaps %xmm1, %xmm0
addq $24, %rsp addq $24, %rsp
.cfi_remember_state .cfi_remember_state
.cfi_def_cfa_offset 8 .cfi_def_cfa_offset 8
ret ret
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
config.h.in | 3 ++
sysdeps/x86/fpu/math_private.h | 24 ++++++++++------
sysdeps/x86_64/configure | 52 ++++++++++++++++++++++++++++++++++
sysdeps/x86_64/configure.ac | 31 ++++++++++++++++++++
4 files changed, 102 insertions(+), 8 deletions(-)
diff --git a/config.h.in b/config.h.in
index 8b4077f578..af2ab31379 100644
--- a/config.h.in
+++ b/config.h.in
@@ -308,4 +308,7 @@
/* Define if -mapxf is enabled by default on x86. */
#undef HAVE_X86_APX
+/* Define if -Os inlines trunc on x86. */
+#undef HAVE_X86_OS_INLINE_TRUNC
+
#endif
diff --git a/sysdeps/x86/fpu/math_private.h b/sysdeps/x86/fpu/math_private.h
index d30d580cea..610ae364f3 100644
--- a/sysdeps/x86/fpu/math_private.h
+++ b/sysdeps/x86/fpu/math_private.h
@@ -33,27 +33,35 @@ __NTH (__ieee754_atan2l (long double y, long double x))
__extern_always_inline double
__trunc (double x)
{
-#ifdef __AVX__
+#if HAVE_X86_OS_INLINE_TRUNC
+ return trunc (x);
+#else
+# ifdef __AVX__
asm ("vroundsd $11, %1, %1, %0" : "=v" (x) : "v" (x));
-#elif defined __SSE4_1__
+# elif defined __SSE4_1__
asm ("roundsd $11, %1, %0" : "=x" (x) : "x" (x));
-#else
+# else
x = trunc (x);
-#endif
+# endif
return x;
+#endif
}
__extern_always_inline float
__truncf (float x)
{
-#ifdef __AVX__
+#if HAVE_X86_OS_INLINE_TRUNC
+ return truncf (x);
+#else
+# ifdef __AVX__
asm ("vroundss $11, %1, %1, %0" : "=v" (x) : "v" (x));
-#elif defined __SSE4_1__
+# elif defined __SSE4_1__
asm ("roundss $11, %1, %0" : "=x" (x) : "x" (x));
-#else
+# else
x = truncf (x);
-#endif
+# endif
return x;
+#endif
}
#endif
diff --git a/sysdeps/x86_64/configure b/sysdeps/x86_64/configure
index 32324f62da..9e98d020ae 100644
--- a/sysdeps/x86_64/configure
+++ b/sysdeps/x86_64/configure
@@ -289,6 +289,58 @@ fi
config_vars="$config_vars
have-x86-apx = $libc_cv_x86_have_apx"
+conftest_code="
+extern float truncf (float __x) __attribute__ ((__nothrow__,__const__));
+
+float
+tf (float x)
+{
+ return truncf (x);
+}
+"
+
+cat > conftest.c <<EOF
+$conftest_code
+EOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if -Os inlines trunc" >&5
+printf %s "checking if -Os inlines trunc... " >&6; }
+if test ${libc_cv_cc_x86_inline_trunc+y}
+then :
+ printf %s "(cached) " >&6
+else case e in #(
+ e) if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -S -Os -msse4.1 conftest.c -o conftest 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+ then
+
+libc_cv_cc_x86_inline_trunc=no
+if grep -E -q "roundss" conftest; then
+ libc_cv_cc_x86_inline_trunc=yes
+fi
+
+ else
+
+echo "failed to check if -Os inlines trunc."
+rm -f conftest*
+exit 1
+
+ fi ;;
+esac
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cc_x86_inline_trunc" >&5
+printf "%s\n" "$libc_cv_cc_x86_inline_trunc" >&6; }
+rm -f conftest*
+if test "$libc_cv_cc_x86_inline_trunc" = yes; then
+ printf "%s\n" "#define HAVE_X86_OS_INLINE_TRUNC 1" >>confdefs.h
+
+else
+ printf "%s\n" "#define HAVE_X86_OS_INLINE_TRUNC 0" >>confdefs.h
+
+fi
+
libc_cv_support_sframe=yes
test -n "$critic_missing" && as_fn_error $? "
diff --git a/sysdeps/x86_64/configure.ac b/sysdeps/x86_64/configure.ac
index a00958e219..848dc4e170 100644
--- a/sysdeps/x86_64/configure.ac
+++ b/sysdeps/x86_64/configure.ac
@@ -104,6 +104,37 @@ if test $libc_cv_x86_have_apx = yes; then
fi
LIBC_CONFIG_VAR([have-x86-apx], [$libc_cv_x86_have_apx])
+conftest_code="
+extern float truncf (float __x) __attribute__ ((__nothrow__,__const__));
+
+float
+tf (float x)
+{
+ return truncf (x);
+}
+"
+dnl Check if CC inlines trunc with -Os.
+LIBC_TRY_CC_COMMAND([if -Os inlines trunc],
+ [$conftest_code],
+ [-S -Os -msse4.1],
+ libc_cv_cc_x86_inline_trunc,
+ [
+libc_cv_cc_x86_inline_trunc=no
+if grep -E -q "roundss" conftest; then
+ libc_cv_cc_x86_inline_trunc=yes
+fi
+],
+[
+echo "failed to check if -Os inlines trunc."
+rm -f conftest*
+exit 1
+])
+if test "$libc_cv_cc_x86_inline_trunc" = yes; then
+ AC_DEFINE(HAVE_X86_OS_INLINE_TRUNC, 1)
+else
+ AC_DEFINE(HAVE_X86_OS_INLINE_TRUNC, 0)
+fi
+
libc_cv_support_sframe=yes
test -n "$critic_missing" && AC_MSG_ERROR([
--
2.51.0
More information about the Libc-alpha
mailing list