1 | /* Used by sinf, cosf and sincosf functions. X86-64 version. |
2 | Copyright (C) 2018-2023 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 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | typedef double v2df_t __attribute__ ((vector_size (2 * sizeof (double)))); |
20 | |
21 | #ifdef __SSE2_MATH__ |
22 | typedef float v4sf_t __attribute__ ((vector_size (4 * sizeof (float)))); |
23 | |
24 | static inline void |
25 | v2df_to_sf (v2df_t v2df, float *f0p, float *f1p) |
26 | { |
27 | v4sf_t v4sf = __builtin_ia32_cvtpd2ps (v2df); |
28 | *f0p = v4sf[0]; |
29 | *f1p = v4sf[1]; |
30 | } |
31 | #else |
32 | static inline void |
33 | v2df_to_sf (v2df_t v2df, float *f0p, float *f1p) |
34 | { |
35 | *f0p = (float) v2df[0]; |
36 | *f1p = (float) v2df[1]; |
37 | } |
38 | #endif |
39 | |
40 | /* The constants and polynomials for sine and cosine. */ |
41 | typedef struct |
42 | { |
43 | double sign[4]; /* Sign of sine in quadrants 0..3. */ |
44 | double hpi_inv; /* 2 / PI ( * 2^24 if !TOINT_INTRINSICS). */ |
45 | double hpi; /* PI / 2. */ |
46 | /* Cosine polynomial: c0, c1, c2, c3, c4. |
47 | Sine polynomial: s1, s2, s3. */ |
48 | double c0, c1; |
49 | v2df_t s1c2, s2c3, s3c4; |
50 | } sincos_t; |
51 | |
52 | /* Compute the sine and cosine of inputs X and X2 (X squared), using the |
53 | polynomial P and store the results in SINP and COSP. N is the quadrant, |
54 | if odd the cosine and sine polynomials are swapped. */ |
55 | static inline void |
56 | sincosf_poly (double x, double x2, const sincos_t *p, int n, float *sinp, |
57 | float *cosp) |
58 | { |
59 | v2df_t vx2x2 = { x2, x2 }; |
60 | v2df_t vxx2 = { x, x2 }; |
61 | v2df_t vx3x4, vs1c2; |
62 | |
63 | vx3x4 = vx2x2 * vxx2; |
64 | vs1c2 = p->s2c3 + vx2x2 * p->s3c4; |
65 | |
66 | /* Swap sin/cos result based on quadrant. */ |
67 | if (n & 1) |
68 | { |
69 | float *tmp = cosp; |
70 | cosp = sinp; |
71 | sinp = tmp; |
72 | } |
73 | |
74 | double c1 = p->c0 + x2 * p->c1; |
75 | v2df_t vxc1 = { x, c1 }; |
76 | v2df_t vx5x6 = vx3x4 * vx2x2; |
77 | |
78 | v2df_t vsincos = vxc1 + vx3x4 * p->s1c2; |
79 | vsincos = vsincos + vx5x6 * vs1c2; |
80 | v2df_to_sf (vsincos, sinp, cosp); |
81 | } |
82 | |
83 | /* Return the sine of inputs X and X2 (X squared) using the polynomial P. |
84 | N is the quadrant, and if odd the cosine polynomial is used. */ |
85 | static inline float |
86 | sinf_poly (double x, double x2, const sincos_t *p, int n) |
87 | { |
88 | double x3, x4, x6, x7, s, c, c1, c2, s1; |
89 | |
90 | if ((n & 1) == 0) |
91 | { |
92 | x3 = x * x2; |
93 | s1 = p->s2c3[0] + x2 * p->s3c4[0]; |
94 | |
95 | x7 = x3 * x2; |
96 | s = x + x3 * p->s1c2[0]; |
97 | |
98 | return s + x7 * s1; |
99 | } |
100 | else |
101 | { |
102 | x4 = x2 * x2; |
103 | c2 = p->s2c3[1] + x2 * p->s3c4[1]; |
104 | c1 = p->c0 + x2 * p->c1; |
105 | |
106 | x6 = x4 * x2; |
107 | c = c1 + x4 * p->s1c2[1]; |
108 | |
109 | return c + x6 * c2; |
110 | } |
111 | } |
112 | |