[PATCH] Add SSE math and C++ namespace support to i386 bits/mathinline.h
H.J. Lu
hjl.tools@gmail.com
Tue Jun 12 17:19:00 GMT 2012
On Fri, Jun 8, 2012 at 9:40 PM, H.J. Lu <hongjiu.lu@intel.com> wrote:
> Hi,
>
> I am trying to fix the last header file for BZ #14117. This
> patch adds SSE math and C++ namespace support to i386 bits/mathinline.h.
> I copied it from x86-64 bits/mathinline.h. I will post another
> patch to i386 bits/mathinline.h to disable i387 inline funtions for
> SSE math. Then i386 bits/mathinline.h can be used for both x86-64
> and i386. Tested on Linux/ia32. OK to install?
>
> Thanks.
Ping.
H.J.
>
> H.J.
> ---
> [BZ #14050]
> [BZ #14117]
> * sysdeps/i386/fpu/bits/mathinline.h (__MATH_INLINE): Check
> __extern_always_inline instead of __extern_inline.
> (__signbitf): Support __SSE2_MATH__ and C++ namespace.
> (__signbit): Likewise.
> (__signbitl): Support C++ namespace.
> (lrintf): New inline function.
> (lrint): Likewise.
> (llrintf): Likewise.
> (llrint): Likewise.
> (fmaxf): Likewise.
> (fmax): Likewise.
> (fminf): Likewise.
> (fmin): Likewise.
> (rint): Likewise.
> (rintf): Likewise.
> (ceil): Likewise.
> (ceilf): Likewise.
> (floor): Likewise.
> (floorf): Likewise.
> (nearbyint): Likewise.
> (nearbyintf): Likewise.
>
> diff --git a/sysdeps/i386/fpu/bits/mathinline.h b/sysdeps/i386/fpu/bits/mathinline.h
> index 2a7e96b..5ee40a3 100644
> --- a/sysdeps/i386/fpu/bits/mathinline.h
> +++ b/sysdeps/i386/fpu/bits/mathinline.h
> @@ -1,7 +1,6 @@
> -/* Inline math functions for i387.
> +/* Inline math functions for i387 and SSE.
> Copyright (C) 1995-2012 Free Software Foundation, Inc.
> This file is part of the GNU C Library.
> - Contributed by John C. Bowman <bowman@math.ualberta.ca>, 1995.
>
> The GNU C Library is free software; you can redistribute it and/or
> modify it under the terms of the GNU Lesser General Public
> @@ -21,10 +20,10 @@
> # error "Never use <bits/mathinline.h> directly; include <math.h> instead."
> #endif
>
> -#ifndef __extern_inline
> +#ifndef __extern_always_inline
> # define __MATH_INLINE __inline
> #else
> -# define __MATH_INLINE __extern_inline
> +# define __MATH_INLINE __extern_always_inline
> #endif
>
>
> @@ -121,18 +120,32 @@
> /* The gcc, version 2.7 or below, has problems with all this inlining
> code. So disable it for this version of the compiler. */
> # if __GNUC_PREREQ (2, 8)
> +__BEGIN_NAMESPACE_C99
> +
> /* Test for negative number. Used in the signbit() macro. */
> __MATH_INLINE int
> __NTH (__signbitf (float __x))
> {
> +# ifdef __SSE2_MATH__
> + int __m;
> + __asm ("pmovmskb %1, %0" : "=r" (__m) : "x" (__x));
> + return (__m & 0x8) != 0;
> +# else
> __extension__ union { float __f; int __i; } __u = { __f: __x };
> return __u.__i < 0;
> +# endif
> }
> __MATH_INLINE int
> __NTH (__signbit (double __x))
> {
> +# ifdef __SSE2_MATH__
> + int __m;
> + __asm ("pmovmskb %1, %0" : "=r" (__m) : "x" (__x));
> + return (__m & 0x80) != 0;
> +# else
> __extension__ union { double __d; int __i[2]; } __u = { __d: __x };
> return __u.__i[1] < 0;
> +# endif
> }
> __MATH_INLINE int
> __NTH (__signbitl (long double __x))
> @@ -140,6 +153,8 @@ __NTH (__signbitl (long double __x))
> __extension__ union { long double __l; int __i[3]; } __u = { __l: __x };
> return (__u.__i[2] & 0x8000) != 0;
> }
> +
> +__END_NAMESPACE_C99
> # endif
> #endif
>
> @@ -147,6 +162,224 @@ __NTH (__signbitl (long double __x))
> /* The gcc, version 2.7 or below, has problems with all this inlining
> code. So disable it for this version of the compiler. */
> #if __GNUC_PREREQ (2, 8)
> +# if !__GNUC_PREREQ (3, 4) && !defined __NO_MATH_INLINES \
> + && defined __OPTIMIZE__
> +/* GCC 3.4 introduced builtins for all functions below, so
> + there's no need to define any of these inline functions. */
> +
> +# ifdef __USE_ISOC99
> +__BEGIN_NAMESPACE_C99
> +
> +/* Round to nearest integer. */
> +# ifdef __SSE_MATH__
> +__MATH_INLINE long int
> +__NTH (lrintf (float __x))
> +{
> + long int __res;
> + /* Mark as volatile since the result is dependent on the state of
> + the SSE control register (the rounding mode). Otherwise GCC might
> + remove these assembler instructions since it does not know about
> + the rounding mode change and cannot currently be told. */
> + __asm __volatile__ ("cvtss2si %1, %0" : "=r" (__res) : "xm" (__x));
> + return __res;
> +}
> +# endif
> +# ifdef __SSE2_MATH__
> +__MATH_INLINE long int
> +__NTH (lrint (double __x))
> +{
> + long int __res;
> + /* Mark as volatile since the result is dependent on the state of
> + the SSE control register (the rounding mode). Otherwise GCC might
> + remove these assembler instructions since it does not know about
> + the rounding mode change and cannot currently be told. */
> + __asm __volatile__ ("cvtsd2si %1, %0" : "=r" (__res) : "xm" (__x));
> + return __res;
> +}
> +# endif
> +# ifdef __x86_64__
> +__MATH_INLINE long long int
> +__NTH (llrintf (float __x))
> +{
> + long long int __res;
> + /* Mark as volatile since the result is dependent on the state of
> + the SSE control register (the rounding mode). Otherwise GCC might
> + remove these assembler instructions since it does not know about
> + the rounding mode change and cannot currently be told. */
> + __asm __volatile__ ("cvtss2si %1, %0" : "=r" (__res) : "xm" (__x));
> + return __res;
> +}
> +__MATH_INLINE long long int
> +__NTH (llrint (double __x))
> +{
> + long long int __res;
> + /* Mark as volatile since the result is dependent on the state of
> + the SSE control register (the rounding mode). Otherwise GCC might
> + remove these assembler instructions since it does not know about
> + the rounding mode change and cannot currently be told. */
> + __asm __volatile__ ("cvtsd2si %1, %0" : "=r" (__res) : "xm" (__x));
> + return __res;
> +}
> +# endif
> +
> +# if defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ > 0 \
> + && defined __SSE2_MATH__
> +/* Determine maximum of two values. */
> +__MATH_INLINE float
> +__NTH (fmaxf (float __x, float __y))
> +{
> +# ifdef __AVX__
> + float __res;
> + __asm ("vmaxss %2, %1, %0" : "=x" (__res) : "x" (x), "xm" (__y));
> + return __res;
> +# else
> + __asm ("maxss %1, %0" : "+x" (__x) : "xm" (__y));
> + return __x;
> +# endif
> +}
> +__MATH_INLINE double
> +__NTH (fmax (double __x, double __y))
> +{
> +# ifdef __AVX__
> + float __res;
> + __asm ("vmaxsd %2, %1, %0" : "=x" (__res) : "x" (x), "xm" (__y));
> + return __res;
> +# else
> + __asm ("maxsd %1, %0" : "+x" (__x) : "xm" (__y));
> + return __x;
> +# endif
> +}
> +
> +/* Determine minimum of two values. */
> +__MATH_INLINE float
> +__NTH (fminf (float __x, float __y))
> +{
> +# ifdef __AVX__
> + float __res;
> + __asm ("vminss %2, %1, %0" : "=x" (__res) : "x" (x), "xm" (__y));
> + return __res;
> +# else
> + __asm ("minss %1, %0" : "+x" (__x) : "xm" (__y));
> + return __x;
> +# endif
> +}
> +__MATH_INLINE double
> +__NTH (fmin (double __x, double __y))
> +{
> +# ifdef __AVX__
> + float __res;
> + __asm ("vminsd %2, %1, %0" : "=x" (__res) : "x" (x), "xm" (__y));
> + return __res;
> +# else
> + __asm ("minsd %1, %0" : "+x" (__x) : "xm" (__y));
> + return __x;
> +# endif
> +}
> +# endif
> +
> +__END_NAMESPACE_C99
> +# endif
> +
> +# if defined __SSE4_1__ && defined __SSE2_MATH__
> +# if defined __USE_MISC || defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99
> +__BEGIN_NAMESPACE_C99
> +
> +/* Round to nearest integer. */
> +__MATH_INLINE double
> +__NTH (rint (double __x))
> +{
> + double __res;
> + /* Mark as volatile since the result is dependent on the state of
> + the SSE control register (the rounding mode). Otherwise GCC might
> + remove these assembler instructions since it does not know about
> + the rounding mode change and cannot currently be told. */
> + __asm __volatile__ ("roundsd $4, %1, %0" : "=x" (__res) : "xm" (__x));
> + return __res;
> +}
> +__MATH_INLINE float
> +__NTH (rintf (float __x))
> +{
> + float __res;
> + /* Mark as volatile since the result is dependent on the state of
> + the SSE control register (the rounding mode). Otherwise GCC might
> + remove these assembler instructions since it does not know about
> + the rounding mode change and cannot currently be told. */
> + __asm __volatile__ ("roundss $4, %1, %0" : "=x" (__res) : "xm" (__x));
> + return __res;
> +}
> +
> +# ifdef __USE_ISOC99
> +/* Round to nearest integer without raising inexact exception. */
> +__MATH_INLINE double
> +__NTH (nearbyint (double __x))
> +{
> + double __res;
> + /* Mark as volatile since the result is dependent on the state of
> + the SSE control register (the rounding mode). Otherwise GCC might
> + remove these assembler instructions since it does not know about
> + the rounding mode change and cannot currently be told. */
> + __asm __volatile__ ("roundsd $0xc, %1, %0" : "=x" (__res) : "xm" (__x));
> + return __res;
> +}
> +__MATH_INLINE float
> +__NTH (nearbyintf (float __x))
> +{
> + float __res;
> + /* Mark as volatile since the result is dependent on the state of
> + the SSE control register (the rounding mode). Otherwise GCC might
> + remove these assembler instructions since it does not know about
> + the rounding mode change and cannot currently be told. */
> + __asm __volatile__ ("roundss $0xc, %1, %0" : "=x" (__res) : "xm" (__x));
> + return __res;
> +}
> +# endif
> +
> +__END_NAMESPACE_C99
> +# endif
> +
> +__BEGIN_NAMESPACE_STD
> +/* Smallest integral value not less than X. */
> +__MATH_INLINE double
> +__NTH (ceil (double __x))
> +{
> + double __res;
> + __asm ("roundsd $2, %1, %0" : "=x" (__res) : "xm" (__x));
> + return __res;
> +}
> +__END_NAMESPACE_STD
> +
> +__BEGIN_NAMESPACE_C99
> +__MATH_INLINE float
> +__NTH (ceilf (float __x))
> +{
> + float __res;
> + __asm ("roundss $2, %1, %0" : "=x" (__res) : "xm" (__x));
> + return __res;
> +}
> +__END_NAMESPACE_C99
> +
> +__BEGIN_NAMESPACE_STD
> +/* Largest integer not greater than X. */
> +__MATH_INLINE double
> +__NTH (floor (double __x))
> +{
> + double __res;
> + __asm ("roundsd $1, %1, %0" : "=x" (__res) : "xm" (__x));
> + return __res;
> +}
> +__END_NAMESPACE_STD
> +
> +__BEGIN_NAMESPACE_C99
> +__MATH_INLINE float
> +__NTH (floorf (float __x))
> +{
> + float __res;
> + __asm ("roundss $1, %1, %0" : "=x" (__res) : "xm" (__x));
> + return __res;
> +}
> +__END_NAMESPACE_C99
> +# endif
> +# endif
>
> #if ((!defined __NO_MATH_INLINES || defined __LIBC_INTERNAL_MATH_INLINES) \
> && defined __OPTIMIZE__)
--
H.J.
More information about the Libc-alpha
mailing list