1 | /* Inline math functions for i387 and SSE. |
---|---|

2 | Copyright (C) 1995-2017 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, see |

17 | <http://www.gnu.org/licenses/>. */ |

18 | |

19 | #ifndef _MATH_H |

20 | # error "Never use <bits/mathinline.h> directly; include <math.h> instead." |

21 | #endif |

22 | |

23 | #ifndef __extern_always_inline |

24 | # define __MATH_INLINE __inline |

25 | #else |

26 | # define __MATH_INLINE __extern_always_inline |

27 | #endif |

28 | |

29 | |

30 | #if defined __USE_ISOC99 && defined __GNUC__ && __GNUC__ >= 2 |

31 | /* GCC 2.97 and up have builtins that actually can be used. */ |

32 | # if !__GNUC_PREREQ (2,97) |

33 | /* ISO C99 defines some macros to perform unordered comparisons. The |

34 | ix87 FPU supports this with special opcodes and we should use them. |

35 | These must not be inline functions since we have to be able to handle |

36 | all floating-point types. */ |

37 | # undef isgreater |

38 | # undef isgreaterequal |

39 | # undef isless |

40 | # undef islessequal |

41 | # undef islessgreater |

42 | # undef isunordered |

43 | # ifdef __i686__ |

44 | /* For the PentiumPro and more recent processors we can provide |

45 | better code. */ |

46 | # define isgreater(x, y) \ |

47 | ({ register char __result; \ |

48 | __asm__ ("fucomip %%st(1), %%st; seta %%al" \ |

49 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |

50 | __result; }) |

51 | # define isgreaterequal(x, y) \ |

52 | ({ register char __result; \ |

53 | __asm__ ("fucomip %%st(1), %%st; setae %%al" \ |

54 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |

55 | __result; }) |

56 | |

57 | # define isless(x, y) \ |

58 | ({ register char __result; \ |

59 | __asm__ ("fucomip %%st(1), %%st; seta %%al" \ |

60 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st"); \ |

61 | __result; }) |

62 | |

63 | # define islessequal(x, y) \ |

64 | ({ register char __result; \ |

65 | __asm__ ("fucomip %%st(1), %%st; setae %%al" \ |

66 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st"); \ |

67 | __result; }) |

68 | |

69 | # define islessgreater(x, y) \ |

70 | ({ register char __result; \ |

71 | __asm__ ("fucomip %%st(1), %%st; setne %%al" \ |

72 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |

73 | __result; }) |

74 | |

75 | # define isunordered(x, y) \ |

76 | ({ register char __result; \ |

77 | __asm__ ("fucomip %%st(1), %%st; setp %%al" \ |

78 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st"); \ |

79 | __result; }) |

80 | # else |

81 | /* This is the dumb, portable code for i386 and above. */ |

82 | # define isgreater(x, y) \ |

83 | ({ register char __result; \ |

84 | __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al" \ |

85 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |

86 | __result; }) |

87 | |

88 | # define isgreaterequal(x, y) \ |

89 | ({ register char __result; \ |

90 | __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al" \ |

91 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |

92 | __result; }) |

93 | |

94 | # define isless(x, y) \ |

95 | ({ register char __result; \ |

96 | __asm__ ("fucompp; fnstsw; testb $0x45, %%ah; setz %%al" \ |

97 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st", "st(1)"); \ |

98 | __result; }) |

99 | |

100 | # define islessequal(x, y) \ |

101 | ({ register char __result; \ |

102 | __asm__ ("fucompp; fnstsw; testb $0x05, %%ah; setz %%al" \ |

103 | : "=a" (__result) : "u" (x), "t" (y) : "cc", "st", "st(1)"); \ |

104 | __result; }) |

105 | |

106 | # define islessgreater(x, y) \ |

107 | ({ register char __result; \ |

108 | __asm__ ("fucompp; fnstsw; testb $0x44, %%ah; setz %%al" \ |

109 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |

110 | __result; }) |

111 | |

112 | # define isunordered(x, y) \ |

113 | ({ register char __result; \ |

114 | __asm__ ("fucompp; fnstsw; sahf; setp %%al" \ |

115 | : "=a" (__result) : "u" (y), "t" (x) : "cc", "st", "st(1)"); \ |

116 | __result; }) |

117 | # endif /* __i686__ */ |

118 | # endif /* GCC 2.97 */ |

119 | |

120 | /* The gcc, version 2.7 or below, has problems with all this inlining |

121 | code. So disable it for this version of the compiler. */ |

122 | # if __GNUC_PREREQ (2, 8) |

123 | |

124 | /* Test for negative number. Used in the signbit() macro. */ |

125 | __MATH_INLINE int |

126 | __NTH (__signbitf (float __x)) |

127 | { |

128 | # ifdef __SSE2_MATH__ |

129 | int __m; |

130 | __asm ("pmovmskb %1, %0": "=r"(__m) : "x"(__x)); |

131 | return (__m & 0x8) != 0; |

132 | # else |

133 | __extension__ union { float __f; int __i; } __u = { __f: __x }; |

134 | return __u.__i < 0; |

135 | # endif |

136 | } |

137 | __MATH_INLINE int |

138 | __NTH (__signbit (double __x)) |

139 | { |

140 | # ifdef __SSE2_MATH__ |

141 | int __m; |

142 | __asm ("pmovmskb %1, %0": "=r"(__m) : "x"(__x)); |

143 | return (__m & 0x80) != 0; |

144 | # else |

145 | __extension__ union { double __d; int __i[2]; } __u = { __d: __x }; |

146 | return __u.__i[1] < 0; |

147 | # endif |

148 | } |

149 | __MATH_INLINE int |

150 | __NTH (__signbitl (long double __x)) |

151 | { |

152 | __extension__ union { long double __l; int __i[3]; } __u = { __l: __x }; |

153 | return (__u.__i[2] & 0x8000) != 0; |

154 | } |

155 | |

156 | # endif |

157 | #endif |

158 | |

159 | |

160 | /* The gcc, version 2.7 or below, has problems with all this inlining |

161 | code. So disable it for this version of the compiler. */ |

162 | #if __GNUC_PREREQ (2, 8) |

163 | # if !__GNUC_PREREQ (3, 4) && !defined __NO_MATH_INLINES \ |

164 | && defined __OPTIMIZE__ |

165 | /* GCC 3.4 introduced builtins for all functions below, so |

166 | there's no need to define any of these inline functions. */ |

167 | |

168 | # ifdef __USE_ISOC99 |

169 | |

170 | /* Round to nearest integer. */ |

171 | # ifdef __SSE_MATH__ |

172 | __MATH_INLINE long int |

173 | __NTH (lrintf (float __x)) |

174 | { |

175 | long int __res; |

176 | /* Mark as volatile since the result is dependent on the state of |

177 | the SSE control register (the rounding mode). Otherwise GCC might |

178 | remove these assembler instructions since it does not know about |

179 | the rounding mode change and cannot currently be told. */ |

180 | __asm __volatile__ ("cvtss2si %1, %0": "=r"(__res) : "xm"(__x)); |

181 | return __res; |

182 | } |

183 | # endif |

184 | # ifdef __SSE2_MATH__ |

185 | __MATH_INLINE long int |

186 | __NTH (lrint (double __x)) |

187 | { |

188 | long int __res; |

189 | /* Mark as volatile since the result is dependent on the state of |

190 | the SSE control register (the rounding mode). Otherwise GCC might |

191 | remove these assembler instructions since it does not know about |

192 | the rounding mode change and cannot currently be told. */ |

193 | __asm __volatile__ ("cvtsd2si %1, %0": "=r"(__res) : "xm"(__x)); |

194 | return __res; |

195 | } |

196 | # endif |

197 | # ifdef __x86_64__ |

198 | __extension__ |

199 | __MATH_INLINE long long int |

200 | __NTH (llrintf (float __x)) |

201 | { |

202 | long long int __res; |

203 | /* Mark as volatile since the result is dependent on the state of |

204 | the SSE control register (the rounding mode). Otherwise GCC might |

205 | remove these assembler instructions since it does not know about |

206 | the rounding mode change and cannot currently be told. */ |

207 | __asm __volatile__ ("cvtss2si %1, %0": "=r"(__res) : "xm"(__x)); |

208 | return __res; |

209 | } |

210 | __extension__ |

211 | __MATH_INLINE long long int |

212 | __NTH (llrint (double __x)) |

213 | { |

214 | long long int __res; |

215 | /* Mark as volatile since the result is dependent on the state of |

216 | the SSE control register (the rounding mode). Otherwise GCC might |

217 | remove these assembler instructions since it does not know about |

218 | the rounding mode change and cannot currently be told. */ |

219 | __asm __volatile__ ("cvtsd2si %1, %0": "=r"(__res) : "xm"(__x)); |

220 | return __res; |

221 | } |

222 | # endif |

223 | |

224 | # if defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ > 0 \ |

225 | && defined __SSE2_MATH__ |

226 | /* Determine maximum of two values. */ |

227 | __MATH_INLINE float |

228 | __NTH (fmaxf (float __x, float __y)) |

229 | { |

230 | # ifdef __AVX__ |

231 | float __res; |

232 | __asm ("vmaxss %2, %1, %0": "=x"(__res) : "x"(x), "xm"(__y)); |

233 | return __res; |

234 | # else |

235 | __asm ("maxss %1, %0": "+x"(__x) : "xm"(__y)); |

236 | return __x; |

237 | # endif |

238 | } |

239 | __MATH_INLINE double |

240 | __NTH (fmax (double __x, double __y)) |

241 | { |

242 | # ifdef __AVX__ |

243 | float __res; |

244 | __asm ("vmaxsd %2, %1, %0": "=x"(__res) : "x"(x), "xm"(__y)); |

245 | return __res; |

246 | # else |

247 | __asm ("maxsd %1, %0": "+x"(__x) : "xm"(__y)); |

248 | return __x; |

249 | # endif |

250 | } |

251 | |

252 | /* Determine minimum of two values. */ |

253 | __MATH_INLINE float |

254 | __NTH (fminf (float __x, float __y)) |

255 | { |

256 | # ifdef __AVX__ |

257 | float __res; |

258 | __asm ("vminss %2, %1, %0": "=x"(__res) : "x"(x), "xm"(__y)); |

259 | return __res; |

260 | # else |

261 | __asm ("minss %1, %0": "+x"(__x) : "xm"(__y)); |

262 | return __x; |

263 | # endif |

264 | } |

265 | __MATH_INLINE double |

266 | __NTH (fmin (double __x, double __y)) |

267 | { |

268 | # ifdef __AVX__ |

269 | float __res; |

270 | __asm ("vminsd %2, %1, %0": "=x"(__res) : "x"(x), "xm"(__y)); |

271 | return __res; |

272 | # else |

273 | __asm ("minsd %1, %0": "+x"(__x) : "xm"(__y)); |

274 | return __x; |

275 | # endif |

276 | } |

277 | # endif |

278 | |

279 | # endif |

280 | |

281 | # if defined __SSE4_1__ && defined __SSE2_MATH__ |

282 | # if defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99 |

283 | |

284 | /* Round to nearest integer. */ |

285 | __MATH_INLINE double |

286 | __NTH (rint (double __x)) |

287 | { |

288 | double __res; |

289 | /* Mark as volatile since the result is dependent on the state of |

290 | the SSE control register (the rounding mode). Otherwise GCC might |

291 | remove these assembler instructions since it does not know about |

292 | the rounding mode change and cannot currently be told. */ |

293 | __asm __volatile__ ("roundsd $4, %1, %0": "=x"(__res) : "xm"(__x)); |

294 | return __res; |

295 | } |

296 | __MATH_INLINE float |

297 | __NTH (rintf (float __x)) |

298 | { |

299 | float __res; |

300 | /* Mark as volatile since the result is dependent on the state of |

301 | the SSE control register (the rounding mode). Otherwise GCC might |

302 | remove these assembler instructions since it does not know about |

303 | the rounding mode change and cannot currently be told. */ |

304 | __asm __volatile__ ("roundss $4, %1, %0": "=x"(__res) : "xm"(__x)); |

305 | return __res; |

306 | } |

307 | |

308 | # ifdef __USE_ISOC99 |

309 | /* Round to nearest integer without raising inexact exception. */ |

310 | __MATH_INLINE double |

311 | __NTH (nearbyint (double __x)) |

312 | { |

313 | double __res; |

314 | /* Mark as volatile since the result is dependent on the state of |

315 | the SSE control register (the rounding mode). Otherwise GCC might |

316 | remove these assembler instructions since it does not know about |

317 | the rounding mode change and cannot currently be told. */ |

318 | __asm __volatile__ ("roundsd $0xc, %1, %0": "=x"(__res) : "xm"(__x)); |

319 | return __res; |

320 | } |

321 | __MATH_INLINE float |

322 | __NTH (nearbyintf (float __x)) |

323 | { |

324 | float __res; |

325 | /* Mark as volatile since the result is dependent on the state of |

326 | the SSE control register (the rounding mode). Otherwise GCC might |

327 | remove these assembler instructions since it does not know about |

328 | the rounding mode change and cannot currently be told. */ |

329 | __asm __volatile__ ("roundss $0xc, %1, %0": "=x"(__res) : "xm"(__x)); |

330 | return __res; |

331 | } |

332 | # endif |

333 | |

334 | # endif |

335 | |

336 | /* Smallest integral value not less than X. */ |

337 | __MATH_INLINE double |

338 | __NTH (ceil (double __x)) |

339 | { |

340 | double __res; |

341 | __asm ("roundsd $2, %1, %0": "=x"(__res) : "xm"(__x)); |

342 | return __res; |

343 | } |

344 | |

345 | __MATH_INLINE float |

346 | __NTH (ceilf (float __x)) |

347 | { |

348 | float __res; |

349 | __asm ("roundss $2, %1, %0": "=x"(__res) : "xm"(__x)); |

350 | return __res; |

351 | } |

352 | |

353 | /* Largest integer not greater than X. */ |

354 | __MATH_INLINE double |

355 | __NTH (floor (double __x)) |

356 | { |

357 | double __res; |

358 | __asm ("roundsd $1, %1, %0": "=x"(__res) : "xm"(__x)); |

359 | return __res; |

360 | } |

361 | |

362 | __MATH_INLINE float |

363 | __NTH (floorf (float __x)) |

364 | { |

365 | float __res; |

366 | __asm ("roundss $1, %1, %0": "=x"(__res) : "xm"(__x)); |

367 | return __res; |

368 | } |

369 | # endif |

370 | # endif |

371 | #endif |

372 | |

373 | /* Disable x87 inlines when -fpmath=sse is passed and also when we're building |

374 | on x86_64. Older gcc (gcc-3.2 for example) does not define __SSE2_MATH__ |

375 | for x86_64. */ |

376 | #if !defined __SSE2_MATH__ && !defined __x86_64__ |

377 | # if ((!defined __NO_MATH_INLINES || defined __LIBC_INTERNAL_MATH_INLINES) \ |

378 | && defined __OPTIMIZE__) |

379 | |

380 | /* The inline functions do not set errno or raise necessarily the |

381 | correct exceptions. */ |

382 | # undef math_errhandling |

383 | |

384 | /* A macro to define float, double, and long double versions of various |

385 | math functions for the ix87 FPU. FUNC is the function name (which will |

386 | be suffixed with f and l for the float and long double version, |

387 | respectively). OP is the name of the FPU operation. |

388 | We define two sets of macros. The set with the additional NP |

389 | doesn't add a prototype declaration. */ |

390 | |

391 | # ifdef __USE_ISOC99 |

392 | # define __inline_mathop(func, op) \ |

393 | __inline_mathop_ (double, func, op) \ |

394 | __inline_mathop_ (float, __CONCAT(func,f), op) \ |

395 | __inline_mathop_ (long double, __CONCAT(func,l), op) |

396 | # define __inline_mathopNP(func, op) \ |

397 | __inline_mathopNP_ (double, func, op) \ |

398 | __inline_mathopNP_ (float, __CONCAT(func,f), op) \ |

399 | __inline_mathopNP_ (long double, __CONCAT(func,l), op) |

400 | # else |

401 | # define __inline_mathop(func, op) \ |

402 | __inline_mathop_ (double, func, op) |

403 | # define __inline_mathopNP(func, op) \ |

404 | __inline_mathopNP_ (double, func, op) |

405 | # endif |

406 | |

407 | # define __inline_mathop_(float_type, func, op) \ |

408 | __inline_mathop_decl_ (float_type, func, op, "0" (__x)) |

409 | # define __inline_mathopNP_(float_type, func, op) \ |

410 | __inline_mathop_declNP_ (float_type, func, op, "0" (__x)) |

411 | |

412 | |

413 | # ifdef __USE_ISOC99 |

414 | # define __inline_mathop_decl(func, op, params...) \ |

415 | __inline_mathop_decl_ (double, func, op, params) \ |

416 | __inline_mathop_decl_ (float, __CONCAT(func,f), op, params) \ |

417 | __inline_mathop_decl_ (long double, __CONCAT(func,l), op, params) |

418 | # define __inline_mathop_declNP(func, op, params...) \ |

419 | __inline_mathop_declNP_ (double, func, op, params) \ |

420 | __inline_mathop_declNP_ (float, __CONCAT(func,f), op, params) \ |

421 | __inline_mathop_declNP_ (long double, __CONCAT(func,l), op, params) |

422 | # else |

423 | # define __inline_mathop_decl(func, op, params...) \ |

424 | __inline_mathop_decl_ (double, func, op, params) |

425 | # define __inline_mathop_declNP(func, op, params...) \ |

426 | __inline_mathop_declNP_ (double, func, op, params) |

427 | # endif |

428 | |

429 | # define __inline_mathop_decl_(float_type, func, op, params...) \ |

430 | __MATH_INLINE float_type func (float_type) __THROW; \ |

431 | __inline_mathop_declNP_ (float_type, func, op, params) |

432 | |

433 | # define __inline_mathop_declNP_(float_type, func, op, params...) \ |

434 | __MATH_INLINE float_type __NTH (func (float_type __x)) \ |

435 | { \ |

436 | register float_type __result; \ |

437 | __asm __volatile__ (op : "=t" (__result) : params); \ |

438 | return __result; \ |

439 | } |

440 | |

441 | |

442 | # ifdef __USE_ISOC99 |

443 | # define __inline_mathcode(func, arg, code) \ |

444 | __inline_mathcode_ (double, func, arg, code) \ |

445 | __inline_mathcode_ (float, __CONCAT(func,f), arg, code) \ |

446 | __inline_mathcode_ (long double, __CONCAT(func,l), arg, code) |

447 | # define __inline_mathcodeNP(func, arg, code) \ |

448 | __inline_mathcodeNP_ (double, func, arg, code) \ |

449 | __inline_mathcodeNP_ (float, __CONCAT(func,f), arg, code) \ |

450 | __inline_mathcodeNP_ (long double, __CONCAT(func,l), arg, code) |

451 | # define __inline_mathcode2(func, arg1, arg2, code) \ |

452 | __inline_mathcode2_ (double, func, arg1, arg2, code) \ |

453 | __inline_mathcode2_ (float, __CONCAT(func,f), arg1, arg2, code) \ |

454 | __inline_mathcode2_ (long double, __CONCAT(func,l), arg1, arg2, code) |

455 | # define __inline_mathcodeNP2(func, arg1, arg2, code) \ |

456 | __inline_mathcodeNP2_ (double, func, arg1, arg2, code) \ |

457 | __inline_mathcodeNP2_ (float, __CONCAT(func,f), arg1, arg2, code) \ |

458 | __inline_mathcodeNP2_ (long double, __CONCAT(func,l), arg1, arg2, code) |

459 | # define __inline_mathcode3(func, arg1, arg2, arg3, code) \ |

460 | __inline_mathcode3_ (double, func, arg1, arg2, arg3, code) \ |

461 | __inline_mathcode3_ (float, __CONCAT(func,f), arg1, arg2, arg3, code) \ |

462 | __inline_mathcode3_ (long double, __CONCAT(func,l), arg1, arg2, arg3, code) |

463 | # define __inline_mathcodeNP3(func, arg1, arg2, arg3, code) \ |

464 | __inline_mathcodeNP3_ (double, func, arg1, arg2, arg3, code) \ |

465 | __inline_mathcodeNP3_ (float, __CONCAT(func,f), arg1, arg2, arg3, code) \ |

466 | __inline_mathcodeNP3_ (long double, __CONCAT(func,l), arg1, arg2, arg3, code) |

467 | # else |

468 | # define __inline_mathcode(func, arg, code) \ |

469 | __inline_mathcode_ (double, func, (arg), code) |

470 | # define __inline_mathcodeNP(func, arg, code) \ |

471 | __inline_mathcodeNP_ (double, func, (arg), code) |

472 | # define __inline_mathcode2(func, arg1, arg2, code) \ |

473 | __inline_mathcode2_ (double, func, arg1, arg2, code) |

474 | # define __inline_mathcodeNP2(func, arg1, arg2, code) \ |

475 | __inline_mathcodeNP2_ (double, func, arg1, arg2, code) |

476 | # define __inline_mathcode3(func, arg1, arg2, arg3, code) \ |

477 | __inline_mathcode3_ (double, func, arg1, arg2, arg3, code) |

478 | # define __inline_mathcodeNP3(func, arg1, arg2, arg3, code) \ |

479 | __inline_mathcodeNP3_ (double, func, arg1, arg2, arg3, code) |

480 | # endif |

481 | |

482 | # define __inline_mathcode_(float_type, func, arg, code) \ |

483 | __MATH_INLINE float_type func (float_type) __THROW; \ |

484 | __inline_mathcodeNP_(float_type, func, arg, code) |

485 | |

486 | # define __inline_mathcodeNP_(float_type, func, arg, code) \ |

487 | __MATH_INLINE float_type __NTH (func (float_type arg)) \ |

488 | { \ |

489 | code; \ |

490 | } |

491 | |

492 | |

493 | # define __inline_mathcode2_(float_type, func, arg1, arg2, code) \ |

494 | __MATH_INLINE float_type func (float_type, float_type) __THROW; \ |

495 | __inline_mathcodeNP2_ (float_type, func, arg1, arg2, code) |

496 | |

497 | # define __inline_mathcodeNP2_(float_type, func, arg1, arg2, code) \ |

498 | __MATH_INLINE float_type __NTH (func (float_type arg1, float_type arg2)) \ |

499 | { \ |

500 | code; \ |

501 | } |

502 | |

503 | # define __inline_mathcode3_(float_type, func, arg1, arg2, arg3, code) \ |

504 | __MATH_INLINE float_type func (float_type, float_type, float_type) __THROW; \ |

505 | __inline_mathcodeNP3_(float_type, func, arg1, arg2, arg3, code) |

506 | |

507 | # define __inline_mathcodeNP3_(float_type, func, arg1, arg2, arg3, code) \ |

508 | __MATH_INLINE float_type __NTH (func (float_type arg1, float_type arg2, \ |

509 | float_type arg3)) \ |

510 | { \ |

511 | code; \ |

512 | } |

513 | # endif |

514 | |

515 | |

516 | # if !defined __NO_MATH_INLINES && defined __OPTIMIZE__ |

517 | /* Miscellaneous functions */ |

518 | |

519 | /* __FAST_MATH__ is defined by gcc -ffast-math. */ |

520 | # ifdef __FAST_MATH__ |

521 | # ifdef __USE_GNU |

522 | # define __sincos_code \ |

523 | register long double __cosr; \ |

524 | register long double __sinr; \ |

525 | register unsigned int __swtmp; \ |

526 | __asm __volatile__ \ |

527 | ("fsincos\n\t" \ |

528 | "fnstsw %w2\n\t" \ |

529 | "testl $0x400, %2\n\t" \ |

530 | "jz 1f\n\t" \ |

531 | "fldpi\n\t" \ |

532 | "fadd %%st(0)\n\t" \ |

533 | "fxch %%st(1)\n\t" \ |

534 | "2: fprem1\n\t" \ |

535 | "fnstsw %w2\n\t" \ |

536 | "testl $0x400, %2\n\t" \ |

537 | "jnz 2b\n\t" \ |

538 | "fstp %%st(1)\n\t" \ |

539 | "fsincos\n\t" \ |

540 | "1:" \ |

541 | : "=t" (__cosr), "=u" (__sinr), "=a" (__swtmp) : "0" (__x)); \ |

542 | *__sinx = __sinr; \ |

543 | *__cosx = __cosr |

544 | |

545 | __MATH_INLINE void |

546 | __NTH (__sincos (double __x, double *__sinx, double *__cosx)) |

547 | { |

548 | __sincos_code; |

549 | } |

550 | |

551 | __MATH_INLINE void |

552 | __NTH (__sincosf (float __x, float *__sinx, float *__cosx)) |

553 | { |

554 | __sincos_code; |

555 | } |

556 | |

557 | __MATH_INLINE void |

558 | __NTH (__sincosl (long double __x, long double *__sinx, long double *__cosx)) |

559 | { |

560 | __sincos_code; |

561 | } |

562 | # endif |

563 | |

564 | |

565 | /* Optimized inline implementation, sometimes with reduced precision |

566 | and/or argument range. */ |

567 | |

568 | # if __GNUC_PREREQ (3, 5) |

569 | # define __expm1_code \ |

570 | register long double __temp; \ |

571 | __temp = __builtin_expm1l (__x); \ |

572 | return __temp ? __temp : __x |

573 | # else |

574 | # define __expm1_code \ |

575 | register long double __value; \ |

576 | register long double __exponent; \ |

577 | register long double __temp; \ |

578 | __asm __volatile__ \ |

579 | ("fldl2e # e^x - 1 = 2^(x * log2(e)) - 1\n\t" \ |

580 | "fmul %%st(1) # x * log2(e)\n\t" \ |

581 | "fst %%st(1)\n\t" \ |

582 | "frndint # int(x * log2(e))\n\t" \ |

583 | "fxch\n\t" \ |

584 | "fsub %%st(1) # fract(x * log2(e))\n\t" \ |

585 | "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \ |

586 | "fscale # 2^(x * log2(e)) - 2^(int(x * log2(e)))\n\t" \ |

587 | : "=t" (__value), "=u" (__exponent) : "0" (__x)); \ |

588 | __asm __volatile__ \ |

589 | ("fscale # 2^int(x * log2(e))\n\t" \ |

590 | : "=t" (__temp) : "0" (1.0), "u" (__exponent)); \ |

591 | __temp -= 1.0; \ |

592 | __temp += __value; \ |

593 | return __temp ? __temp : __x |

594 | # endif |

595 | __inline_mathcodeNP_ (long double, __expm1l, __x, __expm1_code) |

596 | |

597 | # if __GNUC_PREREQ (3, 4) |

598 | __inline_mathcodeNP_ (long double, __expl, __x, return __builtin_expl (__x)) |

599 | # else |

600 | # define __exp_code \ |

601 | register long double __value; \ |

602 | register long double __exponent; \ |

603 | __asm __volatile__ \ |

604 | ("fldl2e # e^x = 2^(x * log2(e))\n\t" \ |

605 | "fmul %%st(1) # x * log2(e)\n\t" \ |

606 | "fst %%st(1)\n\t" \ |

607 | "frndint # int(x * log2(e))\n\t" \ |

608 | "fxch\n\t" \ |

609 | "fsub %%st(1) # fract(x * log2(e))\n\t" \ |

610 | "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" \ |

611 | : "=t" (__value), "=u" (__exponent) : "0" (__x)); \ |

612 | __value += 1.0; \ |

613 | __asm __volatile__ \ |

614 | ("fscale" \ |

615 | : "=t" (__value) : "0" (__value), "u" (__exponent)); \ |

616 | return __value |

617 | __inline_mathcodeNP (exp, __x, __exp_code) |

618 | __inline_mathcodeNP_ (long double, __expl, __x, __exp_code) |

619 | # endif |

620 | |

621 | |

622 | # if !__GNUC_PREREQ (3, 5) |

623 | __inline_mathcodeNP (tan, __x, \ |

624 | register long double __value; \ |

625 | register long double __value2 __attribute__ ((__unused__)); \ |

626 | __asm __volatile__ \ |

627 | ("fptan"\ |

628 | : "=t"(__value2), "=u"(__value) : "0"(__x)); \ |

629 | return __value) |

630 | # endif |

631 | # endif /* __FAST_MATH__ */ |

632 | |

633 | |

634 | # if __GNUC_PREREQ (3, 4) |

635 | __inline_mathcodeNP2_ (long double, __atan2l, __y, __x, |

636 | return __builtin_atan2l (__y, __x)) |

637 | # else |

638 | # define __atan2_code \ |

639 | register long double __value; \ |

640 | __asm __volatile__ \ |

641 | ("fpatan" \ |

642 | : "=t" (__value) : "0" (__x), "u" (__y) : "st(1)"); \ |

643 | return __value |

644 | # ifdef __FAST_MATH__ |

645 | __inline_mathcodeNP2 (atan2, __y, __x, __atan2_code) |

646 | # endif |

647 | __inline_mathcodeNP2_ (long double, __atan2l, __y, __x, __atan2_code) |

648 | # endif |

649 | |

650 | |

651 | # if defined __FAST_MATH__ && !__GNUC_PREREQ (3, 5) |

652 | __inline_mathcodeNP2 (fmod, __x, __y, \ |

653 | register long double __value; \ |

654 | __asm __volatile__ \ |

655 | ("1: fprem\n\t"\ |

656 | "fnstsw %%ax\n\t"\ |

657 | "sahf\n\t"\ |

658 | "jp 1b"\ |

659 | : "=t"(__value) : "0"(__x), "u"(__y) : "ax", "cc"); \ |

660 | return __value) |

661 | # endif |

662 | |

663 | |

664 | # ifdef __FAST_MATH__ |

665 | # if !__GNUC_PREREQ (3,3) |

666 | __inline_mathopNP (sqrt, "fsqrt") |

667 | __inline_mathopNP_ (long double, __sqrtl, "fsqrt") |

668 | # define __libc_sqrtl(n) __sqrtl (n) |

669 | # else |

670 | # define __libc_sqrtl(n) __builtin_sqrtl (n) |

671 | # endif |

672 | # endif |

673 | |

674 | # if __GNUC_PREREQ (2, 8) |

675 | __inline_mathcodeNP_ (double, fabs, __x, return __builtin_fabs (__x)) |

676 | # ifdef __USE_ISOC99 |

677 | __inline_mathcodeNP_ (float, fabsf, __x, return __builtin_fabsf (__x)) |

678 | __inline_mathcodeNP_ (long double, fabsl, __x, return __builtin_fabsl (__x)) |

679 | # endif |

680 | __inline_mathcodeNP_ (long double, __fabsl, __x, return __builtin_fabsl (__x)) |

681 | # else |

682 | __inline_mathop (fabs, "fabs") |

683 | __inline_mathop_ (long double, __fabsl, "fabs") |

684 | # endif |

685 | |

686 | # ifdef __FAST_MATH__ |

687 | # if !__GNUC_PREREQ (3, 4) |

688 | /* The argument range of this inline version is reduced. */ |

689 | __inline_mathopNP (sin, "fsin") |

690 | /* The argument range of this inline version is reduced. */ |

691 | __inline_mathopNP (cos, "fcos") |

692 | |

693 | __inline_mathop_declNP (log, "fldln2; fxch; fyl2x", "0"(__x) : "st(1)") |

694 | # endif |

695 | |

696 | # if !__GNUC_PREREQ (3, 5) |

697 | __inline_mathop_declNP (log10, "fldlg2; fxch; fyl2x", "0"(__x) : "st(1)") |

698 | |

699 | __inline_mathcodeNP (asin, __x, return __atan2l (__x, __libc_sqrtl (1.0 - __x * __x))) |

700 | __inline_mathcodeNP (acos, __x, return __atan2l (__libc_sqrtl (1.0 - __x * __x), __x)) |

701 | # endif |

702 | |

703 | # if !__GNUC_PREREQ (3, 4) |

704 | __inline_mathop_declNP (atan, "fld1; fpatan", "0"(__x) : "st(1)") |

705 | # endif |

706 | # endif /* __FAST_MATH__ */ |

707 | |

708 | __inline_mathcode_ (long double, __sgn1l, __x, \ |

709 | __extension__ union { long double __xld; unsigned int __xi[3]; } __n = \ |

710 | { __xld: __x }; \ |

711 | __n.__xi[2] = (__n.__xi[2] & 0x8000) | 0x3fff; \ |

712 | __n.__xi[1] = 0x80000000; \ |

713 | __n.__xi[0] = 0; \ |

714 | return __n.__xld) |

715 | |

716 | |

717 | # ifdef __FAST_MATH__ |

718 | /* The argument range of the inline version of sinhl is slightly reduced. */ |

719 | __inline_mathcodeNP (sinh, __x, \ |

720 | register long double __exm1 = __expm1l (__fabsl (__x)); \ |

721 | return 0.5 * (__exm1 / (__exm1 + 1.0) + __exm1) * __sgn1l (__x)) |

722 | |

723 | __inline_mathcodeNP (cosh, __x, \ |

724 | register long double __ex = __expl (__x); \ |

725 | return 0.5 * (__ex + 1.0 / __ex)) |

726 | |

727 | __inline_mathcodeNP (tanh, __x, \ |

728 | register long double __exm1 = __expm1l (-__fabsl (__x + __x)); \ |

729 | return __exm1 / (__exm1 + 2.0) * __sgn1l (-__x)) |

730 | # endif |

731 | |

732 | __inline_mathcodeNP (floor, __x, \ |

733 | register long double __value; \ |

734 | register int __ignore; \ |

735 | unsigned short int __cw; \ |

736 | unsigned short int __cwtmp; \ |

737 | __asm __volatile ("fnstcw %3\n\t"\ |

738 | "movzwl %3, %1\n\t"\ |

739 | "andl $0xf3ff, %1\n\t"\ |

740 | "orl $0x0400, %1\n\t" /* rounding down */ \ |

741 | "movw %w1, %2\n\t"\ |

742 | "fldcw %2\n\t"\ |

743 | "frndint\n\t"\ |

744 | "fldcw %3"\ |

745 | : "=t"(__value), "=&q"(__ignore), "=m"(__cwtmp), \ |

746 | "=m"(__cw) \ |

747 | : "0"(__x)); \ |

748 | return __value) |

749 | |

750 | __inline_mathcodeNP (ceil, __x, \ |

751 | register long double __value; \ |

752 | register int __ignore; \ |

753 | unsigned short int __cw; \ |

754 | unsigned short int __cwtmp; \ |

755 | __asm __volatile ("fnstcw %3\n\t"\ |

756 | "movzwl %3, %1\n\t"\ |

757 | "andl $0xf3ff, %1\n\t"\ |

758 | "orl $0x0800, %1\n\t" /* rounding up */ \ |

759 | "movw %w1, %2\n\t"\ |

760 | "fldcw %2\n\t"\ |

761 | "frndint\n\t"\ |

762 | "fldcw %3"\ |

763 | : "=t"(__value), "=&q"(__ignore), "=m"(__cwtmp), \ |

764 | "=m"(__cw) \ |

765 | : "0"(__x)); \ |

766 | return __value) |

767 | |

768 | # ifdef __FAST_MATH__ |

769 | # define __ldexp_code \ |

770 | register long double __value; \ |

771 | __asm __volatile__ \ |

772 | ("fscale" \ |

773 | : "=t" (__value) : "0" (__x), "u" ((long double) __y)); \ |

774 | return __value |

775 | |

776 | __MATH_INLINE double |

777 | __NTH (ldexp (double __x, int __y)) |

778 | { |

779 | __ldexp_code; |

780 | } |

781 | # endif |

782 | |

783 | |

784 | /* Optimized versions for some non-standardized functions. */ |

785 | # ifdef __USE_ISOC99 |

786 | |

787 | # ifdef __FAST_MATH__ |

788 | __inline_mathcodeNP (expm1, __x, __expm1_code) |

789 | |

790 | /* We cannot rely on M_SQRT being defined. So we do it for ourself |

791 | here. */ |

792 | # define __M_SQRT2 1.41421356237309504880L /* sqrt(2) */ |

793 | |

794 | # if !__GNUC_PREREQ (3, 5) |

795 | __inline_mathcodeNP (log1p, __x, \ |

796 | register long double __value; \ |

797 | if (__fabsl (__x) >= 1.0 - 0.5 * __M_SQRT2) \ |

798 | __value = logl (1.0 + __x); \ |

799 | else \ |

800 | __asm __volatile__ \ |

801 | ("fldln2\n\t"\ |

802 | "fxch\n\t"\ |

803 | "fyl2xp1"\ |

804 | : "=t"(__value) : "0"(__x) : "st(1)"); \ |

805 | return __value) |

806 | # endif |

807 | |

808 | |

809 | /* The argument range of the inline version of asinhl is slightly reduced. */ |

810 | __inline_mathcodeNP (asinh, __x, \ |

811 | register long double __y = __fabsl (__x); \ |

812 | return (log1pl (__y * __y / (__libc_sqrtl (__y * __y + 1.0) + 1.0) + __y) \ |

813 | * __sgn1l (__x))) |

814 | |

815 | __inline_mathcodeNP (acosh, __x, \ |

816 | return logl (__x + __libc_sqrtl (__x - 1.0) * __libc_sqrtl (__x + 1.0))) |

817 | |

818 | __inline_mathcodeNP (atanh, __x, \ |

819 | register long double __y = __fabsl (__x); \ |

820 | return -0.5 * log1pl (-(__y + __y) / (1.0 + __y)) * __sgn1l (__x)) |

821 | |

822 | /* The argument range of the inline version of hypotl is slightly reduced. */ |

823 | __inline_mathcodeNP2 (hypot, __x, __y, |

824 | return __libc_sqrtl (__x * __x + __y * __y)) |

825 | |

826 | # if !__GNUC_PREREQ (3, 5) |

827 | __inline_mathcodeNP(logb, __x, \ |

828 | register long double __value; \ |

829 | register long double __junk; \ |

830 | __asm __volatile__ \ |

831 | ("fxtract\n\t"\ |

832 | : "=t"(__junk), "=u"(__value) : "0"(__x)); \ |

833 | return __value) |

834 | # endif |

835 | |

836 | # endif |

837 | # endif |

838 | |

839 | # ifdef __USE_ISOC99 |

840 | # ifdef __FAST_MATH__ |

841 | |

842 | # if !__GNUC_PREREQ (3, 5) |

843 | __inline_mathop_declNP (log2, "fld1; fxch; fyl2x", "0"(__x) : "st(1)") |

844 | # endif |

845 | |

846 | __MATH_INLINE float |

847 | __NTH (ldexpf (float __x, int __y)) |

848 | { |

849 | __ldexp_code; |

850 | } |

851 | |

852 | __MATH_INLINE long double |

853 | __NTH (ldexpl (long double __x, int __y)) |

854 | { |

855 | __ldexp_code; |

856 | } |

857 | |

858 | __inline_mathopNP (rint, "frndint") |

859 | # endif /* __FAST_MATH__ */ |

860 | |

861 | # define __lrint_code \ |

862 | long int __lrintres; \ |

863 | __asm__ __volatile__ \ |

864 | ("fistpl %0" \ |

865 | : "=m" (__lrintres) : "t" (__x) : "st"); \ |

866 | return __lrintres |

867 | __MATH_INLINE long int |

868 | __NTH (lrintf (float __x)) |

869 | { |

870 | __lrint_code; |

871 | } |

872 | __MATH_INLINE long int |

873 | __NTH (lrint (double __x)) |

874 | { |

875 | __lrint_code; |

876 | } |

877 | __MATH_INLINE long int |

878 | __NTH (lrintl (long double __x)) |

879 | { |

880 | __lrint_code; |

881 | } |

882 | # undef __lrint_code |

883 | |

884 | # define __llrint_code \ |

885 | long long int __llrintres; \ |

886 | __asm__ __volatile__ \ |

887 | ("fistpll %0" \ |

888 | : "=m" (__llrintres) : "t" (__x) : "st"); \ |

889 | return __llrintres |

890 | __extension__ |

891 | __MATH_INLINE long long int |

892 | __NTH (llrintf (float __x)) |

893 | { |

894 | __llrint_code; |

895 | } |

896 | __extension__ |

897 | __MATH_INLINE long long int |

898 | __NTH (llrint (double __x)) |

899 | { |

900 | __llrint_code; |

901 | } |

902 | __extension__ |

903 | __MATH_INLINE long long int |

904 | __NTH (llrintl (long double __x)) |

905 | { |

906 | __llrint_code; |

907 | } |

908 | # undef __llrint_code |

909 | |

910 | # endif |

911 | |

912 | |

913 | # ifdef __USE_MISC |

914 | |

915 | # if defined __FAST_MATH__ && !__GNUC_PREREQ (3, 5) |

916 | __inline_mathcodeNP2 (drem, __x, __y, \ |

917 | register double __value; \ |

918 | register int __clobbered; \ |

919 | __asm __volatile__ \ |

920 | ("1: fprem1\n\t"\ |

921 | "fstsw %%ax\n\t"\ |

922 | "sahf\n\t"\ |

923 | "jp 1b"\ |

924 | : "=t"(__value), "=&a"(__clobbered) : "0"(__x), "u"(__y) : "cc"); \ |

925 | return __value) |

926 | # endif |

927 | |

928 | |

929 | /* This function is used in the `isfinite' macro. */ |

930 | __MATH_INLINE int |

931 | __NTH (__finite (double __x)) |

932 | { |

933 | return (__extension__ |

934 | (((((union { double __d; int __i[2]; }) {__d: __x}).__i[1] |

935 | | 0x800fffffu) + 1) >> 31)); |

936 | } |

937 | |

938 | # endif /* __USE_MISC */ |

939 | |

940 | /* Undefine some of the large macros which are not used anymore. */ |

941 | # undef __atan2_code |

942 | # ifdef __FAST_MATH__ |

943 | # undef __expm1_code |

944 | # undef __exp_code |

945 | # undef __sincos_code |

946 | # endif /* __FAST_MATH__ */ |

947 | |

948 | # endif /* __NO_MATH_INLINES */ |

949 | |

950 | |

951 | /* This code is used internally in the GNU libc. */ |

952 | # ifdef __LIBC_INTERNAL_MATH_INLINES |

953 | __inline_mathop (__ieee754_sqrt, "fsqrt") |

954 | __inline_mathcode2_ (long double, __ieee754_atan2l, __y, __x, |

955 | register long double __value; |

956 | __asm __volatile__ ("fpatan\n\t" |

957 | : "=t"(__value) |

958 | : "0"(__x), "u"(__y) : "st(1)"); |

959 | return __value;) |

960 | # endif |

961 | |

962 | #endif /* !__SSE2_MATH__ && !__x86_64__ */ |

963 |