1/* Inline math functions for x86-64.
2   Copyright (C) 2002-2004, 2007, 2009, 2011 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4
5   The GNU C Library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   The GNU C Library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with the GNU C Library; if not, write to the Free
17   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18   02111-1307 USA.  */
19
20#ifndef _MATH_H
21# error "Never use <bits/mathinline.h> directly; include <math.h> instead."
22#endif
23
24#include <bits/wordsize.h>
25
26#ifndef __extern_always_inline
27# define __MATH_INLINE __inline
28#else
29# define __MATH_INLINE __extern_always_inline
30#endif
31
32
33/* The gcc, version 2.7 or below, has problems with all this inlining
34   code.  So disable it for this version of the compiler.  */
35#if __GNUC_PREREQ (2, 8) && defined __USE_ISOC99
36__BEGIN_NAMESPACE_C99
37
38/* Test for negative number.  Used in the signbit() macro.  */
39__MATH_INLINE int
40__NTH (__signbitf (float __x))
41{
42# if __WORDSIZE == 32
43  __extension__ union { float __f; int __i; } __u = { __f: __x };
44  return __u.__i < 0;
45# else
46  int __m;
47  __asm ("pmovmskb %1, %0" : "=r" (__m) : "x" (__x));
48  return __m & 0x8;
49# endif
50}
51__MATH_INLINE int
52__NTH (__signbit (double __x))
53{
54# if __WORDSIZE == 32
55  __extension__ union { double __d; int __i[2]; } __u = { __d: __x };
56  return __u.__i[1] < 0;
57# else
58  int __m;
59  __asm ("pmovmskb %1, %0" : "=r" (__m) : "x" (__x));
60  return __m & 0x80;
61# endif
62}
63__MATH_INLINE int
64__NTH (__signbitl (long double __x))
65{
66  __extension__ union { long double __l; int __i[3]; } __u = { __l: __x };
67  return (__u.__i[2] & 0x8000) != 0;
68}
69
70__END_NAMESPACE_C99
71#endif
72
73
74#if (__GNUC_PREREQ (2, 8) && !defined __NO_MATH_INLINES \
75     && defined __OPTIMIZE__)
76
77# ifdef __USE_ISOC99
78__BEGIN_NAMESPACE_C99
79
80/* Round to nearest integer.  */
81#  if __WORDSIZE == 64 || defined __SSE_MATH__
82__MATH_INLINE long int
83__NTH (lrintf (float __x))
84{
85  long int __res;
86  __asm ("cvtss2si %1, %0" : "=r" (__res) : "xm" (__x));
87  return __res;
88}
89#  endif
90#  if __WORDSIZE == 64 || defined __SSE2_MATH__
91__MATH_INLINE long int
92__NTH (lrint (double __x))
93{
94  long int __res;
95  __asm ("cvtsd2si %1, %0" : "=r" (__res) : "xm" (__x));
96  return __res;
97}
98#  endif
99#  if __WORDSIZE == 64
100__MATH_INLINE long long int
101__NTH (llrintf (float __x))
102{
103  long long int __res;
104  __asm ("cvtss2si %1, %0" : "=r" (__res) : "xm" (__x));
105  return __res;
106}
107__MATH_INLINE long long int
108__NTH (llrint (double __x))
109{
110  long long int __res;
111  __asm ("cvtsd2si %1, %0" : "=r" (__res) : "xm" (__x));
112  return __res;
113}
114#  endif
115
116#  if defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ > 0 \
117      && (__WORDSIZE == 64 || defined __SSE2_MATH__)
118/* Determine maximum of two values.  */
119__MATH_INLINE float
120__NTH (fmaxf (float __x, float __y))
121{
122  __asm ("maxss %1, %0" : "+x" (__x) : "xm" (__y));
123  return __x;
124}
125__MATH_INLINE double
126__NTH (fmax (double __x, double __y))
127{
128  __asm ("maxsd %1, %0" : "+x" (__x) : "xm" (__y));
129  return __x;
130}
131
132/* Determine minimum of two values.  */
133__MATH_INLINE float
134__NTH (fminf (float __x, float __y))
135{
136  __asm ("minss %1, %0" : "+x" (__x) : "xm" (__y));
137  return __x;
138}
139__MATH_INLINE double
140__NTH (fmin (double __x, double __y))
141{
142  __asm ("minsd %1, %0" : "+x" (__x) : "xm" (__y));
143  return __x;
144}
145#  endif
146
147__END_NAMESPACE_C99
148# endif
149
150# if defined __SSE4_1__ && (__WORDSIZE == 64 || defined __SSE2_MATH__)
151#  if defined __USE_MISC || defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99
152__BEGIN_NAMESPACE_C99
153
154/* Round to nearest integer.  */
155__MATH_INLINE double
156__NTH (rint (double __x))
157{
158  double __res;
159  __asm ("roundsd $4, %1, %0" : "=x" (__res) : "xm" (__x));
160  return __res;
161}
162__MATH_INLINE float
163__NTH (rintf (float __x))
164{
165  float __res;
166  __asm ("roundss $4, %1, %0" : "=x" (__res) : "xm" (__x));
167  return __res;
168}
169
170#   ifdef __USE_ISOC99
171/* Round to nearest integer without raising inexact exception.  */
172__MATH_INLINE double
173__NTH (nearbyint (double __x))
174{
175  double __res;
176  __asm ("roundsd $0xc, %1, %0" : "=x" (__res) : "xm" (__x));
177  return __res;
178}
179__MATH_INLINE float
180__NTH (nearbyintf (float __x))
181{
182  float __res;
183  __asm ("roundss $0xc, %1, %0" : "=x" (__res) : "xm" (__x));
184  return __res;
185}
186#   endif
187
188__END_NAMESPACE_C99
189#  endif
190
191__BEGIN_NAMESPACE_STD
192/* Smallest integral value not less than X.  */
193__MATH_INLINE double
194__NTH (ceil (double __x))
195{
196  double __res;
197  __asm ("roundsd $2, %1, %0" : "=x" (__res) : "xm" (__x));
198  return __res;
199}
200__END_NAMESPACE_STD
201
202__BEGIN_NAMESPACE_C99
203__MATH_INLINE float
204__NTH (ceilf (float __x))
205{
206  float __res;
207  __asm ("roundss $2, %1, %0" : "=x" (__res) : "xm" (__x));
208  return __res;
209}
210__END_NAMESPACE_C99
211
212__BEGIN_NAMESPACE_STD
213/* Largest integer not greater than X.  */
214__MATH_INLINE double
215__NTH (floor (double __x))
216{
217  double __res;
218  __asm ("roundsd $1, %1, %0" : "=x" (__res) : "xm" (__x));
219  return __res;
220}
221__END_NAMESPACE_STD
222
223__BEGIN_NAMESPACE_C99
224__MATH_INLINE float
225__NTH (floorf (float __x))
226{
227  float __res;
228  __asm ("roundss $1, %1, %0" : "=x" (__res) : "xm" (__x));
229  return __res;
230}
231__END_NAMESPACE_C99
232# endif
233
234#endif
235