[PATCH v3] x86: Don't use asm statement for trunc/truncf
Uros Bizjak
ubizjak@gmail.com
Wed Sep 17 06:43:59 GMT 2025
On Tue, Sep 16, 2025 at 3:52 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> 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>
LGTM.
Reviewed-by: Uros Bizjak <ubizjak@gmail.com>
> ---
> config.h.in | 3 ++
> sysdeps/x86/configure | 52 ++++++++++++++++++++++++++++++++++
> sysdeps/x86/configure.ac | 31 ++++++++++++++++++++
> sysdeps/x86/fpu/math_private.h | 20 ++++++-------
> 4 files changed, 94 insertions(+), 12 deletions(-)
>
> diff --git a/config.h.in b/config.h.in
> index 8b4077f578..9fb369c640 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 trunc is inlined on x86. */
> +#undef HAVE_X86_INLINE_TRUNC
> +
> #endif
> diff --git a/sysdeps/x86/configure b/sysdeps/x86/configure
> index a021cdbcf5..2e95277f29 100644
> --- a/sysdeps/x86/configure
> +++ b/sysdeps/x86/configure
> @@ -340,6 +340,58 @@ fi
> config_vars="$config_vars
> test-cc-cflags-no-direct-extern-access = $libc_cv_test_cc_cflags_no_direct_extern_access"
>
> +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_INLINE_TRUNC 1" >>confdefs.h
> +
> +else
> + printf "%s\n" "#define HAVE_X86_INLINE_TRUNC 0" >>confdefs.h
> +
> +fi
> +
> if test "${libc_cv_cc_no_direct_extern_access}${libc_cv_test_cc_cflags_no_direct_extern_access}" = yes; then
> libc_cv_protected_data=no
> fi
> diff --git a/sysdeps/x86/configure.ac b/sysdeps/x86/configure.ac
> index a87e2f6c41..f3888e6618 100644
> --- a/sysdeps/x86/configure.ac
> +++ b/sysdeps/x86/configure.ac
> @@ -192,6 +192,37 @@ fi
> LIBC_CONFIG_VAR(test-cc-cflags-no-direct-extern-access,
> $libc_cv_test_cc_cflags_no_direct_extern_access)
>
> +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_INLINE_TRUNC, 1)
> +else
> + AC_DEFINE(HAVE_X86_INLINE_TRUNC, 0)
> +fi
> +
> dnl If the building compiler enables no direct external data access by
> dnl default, access to protected data in shared libraries from executables
> dnl must be compiled with no direct external data access. If the testing
> diff --git a/sysdeps/x86/fpu/math_private.h b/sysdeps/x86/fpu/math_private.h
> index d30d580cea..bba085a578 100644
> --- a/sysdeps/x86/fpu/math_private.h
> +++ b/sysdeps/x86/fpu/math_private.h
> @@ -33,27 +33,23 @@ __NTH (__ieee754_atan2l (long double y, long double x))
> __extern_always_inline double
> __trunc (double x)
> {
> -#ifdef __AVX__
> - asm ("vroundsd $11, %1, %1, %0" : "=v" (x) : "v" (x));
> -#elif defined __SSE4_1__
> - asm ("roundsd $11, %1, %0" : "=x" (x) : "x" (x));
> +#if HAVE_X86_INLINE_TRUNC || !defined __SSE4_1__
> + return trunc (x);
> #else
> - x = trunc (x);
> -#endif
> + asm ("%vroundsd $11, %d1, %0" : "=v" (x) : "v" (x));
> return x;
> +#endif
> }
>
> __extern_always_inline float
> __truncf (float x)
> {
> -#ifdef __AVX__
> - asm ("vroundss $11, %1, %1, %0" : "=v" (x) : "v" (x));
> -#elif defined __SSE4_1__
> - asm ("roundss $11, %1, %0" : "=x" (x) : "x" (x));
> +#if HAVE_X86_INLINE_TRUNC || !defined __SSE4_1__
> + return truncf (x);
> #else
> - x = truncf (x);
> -#endif
> + asm ("%vroundss $11, %d1, %0" : "=v" (x) : "v" (x));
> return x;
> +#endif
> }
>
> #endif
> --
> 2.51.0
>
More information about the Libc-alpha
mailing list