1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 17 дек. 2018 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #ifndef DSP_ARCH_X86_AVX2_PMATH_EXP_H_
23 #define DSP_ARCH_X86_AVX2_PMATH_EXP_H_
24 
25 #ifndef DSP_ARCH_X86_AVX2_IMPL
26     #error "This header should not be included directly"
27 #endif /* DSP_ARCH_X86_AVX2_IMPL */
28 
29 #ifdef ARCH_X86_64
30 
31 namespace avx2
32 {
33 #define X8VEC(x)    x, x, x, x, x, x, x, x
34 
35 IF_ARCH_X86(
36     static const uint32_t EXP2_CONST[] __lsp_aligned32 =
37     {
38         X8VEC(0x7fffffff), // sign
39         X8VEC(0x7f),       // 0x7f
40         X8VEC(0x3f317218), // ln(2)
41         X8VEC(0x40e00000), // C5 = 7!/6! = 7.0000000000000000
42         X8VEC(0x42280000), // C4 = 7!/5! = 42.0000000000000000
43         X8VEC(0x43520000), // C3 = 7!/4! = 210.0000000000000000
44         X8VEC(0x44520000), // C2 = 7!/3! = 840.0000000000000000
45         X8VEC(0x451d8000), // C1 = 7!/2! = 2520.0000000000000000
46         X8VEC(0x459d8000), // C0 = 7!/1! = 5040.0000000000000000
47         X8VEC(0x39500d01), // 1/7! = 0.0001984127011383
48         X8VEC(0x3f800000), // 1.0
49     };
50 
51     static const float EXP_LOG2E[] __lsp_aligned32 =
52     {
53         X8VEC(M_LOG2E)
54     };
55 )
56 
57 #undef X8VEC
58 
59 #define POW2_CORE_X32 \
60     /* ymm0 = x */ \
61     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm0, %%ymm2")        /* ymm2 = XP = fabs(x) */ \
62     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm4, %%ymm6")        \
63     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm8, %%ymm10")       \
64     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm12, %%ymm14")      \
65     __ASM_EMIT("vcvttps2dq      %%ymm2, %%ymm1")                        /* ymm1 = R = int(XP) */ \
66     __ASM_EMIT("vcvttps2dq      %%ymm6, %%ymm5")                        \
67     __ASM_EMIT("vcvttps2dq      %%ymm10, %%ymm9")                       \
68     __ASM_EMIT("vcvttps2dq      %%ymm14, %%ymm13")                      \
69     __ASM_EMIT("vcvtdq2ps       %%ymm1, %%ymm3")                        /* ymm3 = float(R) */ \
70     __ASM_EMIT("vcvtdq2ps       %%ymm5, %%ymm7")                        \
71     __ASM_EMIT("vcvtdq2ps       %%ymm9, %%ymm11")                       \
72     __ASM_EMIT("vcvtdq2ps       %%ymm13, %%ymm15")                      \
73     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm1, %%ymm1")        /* ymm1 = R + 127 */ \
74     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm5, %%ymm5")        \
75     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm9, %%ymm9")        \
76     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm13, %%ymm13")      \
77     __ASM_EMIT("vsubps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = XP - float(R) */ \
78     __ASM_EMIT("vsubps          %%ymm7, %%ymm6, %%ymm6")                \
79     __ASM_EMIT("vsubps          %%ymm11, %%ymm10, %%ymm10")             \
80     __ASM_EMIT("vsubps          %%ymm15, %%ymm14, %%ymm14")             \
81     __ASM_EMIT("vpslld          $23, %%ymm1, %%ymm1")                   /* ymm1 = 1 << (R+127) */ \
82     __ASM_EMIT("vpslld          $23, %%ymm5, %%ymm5")                   \
83     __ASM_EMIT("vpslld          $23, %%ymm9, %%ymm9")                   \
84     __ASM_EMIT("vpslld          $23, %%ymm13, %%ymm13")                 \
85     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm2, %%ymm2")        /* ymm2 = X = ln(2) * (XP - float(R)) */ \
86     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm6, %%ymm6")        \
87     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm10, %%ymm10")      \
88     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm14, %%ymm14")      \
89     /* ymm0 = [x<0], ymm1 = 1 << R, ymm2 = X */ \
90     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C5+X */ \
91     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm6, %%ymm7")        \
92     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm10, %%ymm11")      \
93     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm14, %%ymm15")      \
94     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C5+X) */ \
95     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
96     __ASM_EMIT("vmulps          %%ymm10, %%ymm11, %%ymm11")             \
97     __ASM_EMIT("vmulps          %%ymm14, %%ymm15, %%ymm15")             \
98     __ASM_EMIT("vaddps          0x080 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C4+X*(C5+X) */ \
99     __ASM_EMIT("vaddps          0x080 + %[E2C], %%ymm7, %%ymm7")        \
100     __ASM_EMIT("vaddps          0x080 + %[E2C], %%ymm11, %%ymm11")      \
101     __ASM_EMIT("vaddps          0x080 + %[E2C], %%ymm15, %%ymm15")      \
102     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C4+X*(C5+X)) */ \
103     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
104     __ASM_EMIT("vmulps          %%ymm10, %%ymm11, %%ymm11")             \
105     __ASM_EMIT("vmulps          %%ymm14, %%ymm15, %%ymm15")             \
106     __ASM_EMIT("vaddps          0x0a0 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C3+X*(C4+X*(C5+X)) */ \
107     __ASM_EMIT("vaddps          0x0a0 + %[E2C], %%ymm7, %%ymm7")        \
108     __ASM_EMIT("vaddps          0x0a0 + %[E2C], %%ymm11, %%ymm11")      \
109     __ASM_EMIT("vaddps          0x0a0 + %[E2C], %%ymm15, %%ymm15")      \
110     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C3+X*(C4+X*(C5+X))) */ \
111     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
112     __ASM_EMIT("vmulps          %%ymm10, %%ymm11, %%ymm11")             \
113     __ASM_EMIT("vmulps          %%ymm14, %%ymm15, %%ymm15")             \
114     __ASM_EMIT("vaddps          0x0c0 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C2+X*(C3+X*(C4+X*(C5+X))) */ \
115     __ASM_EMIT("vaddps          0x0c0 + %[E2C], %%ymm7, %%ymm7")        \
116     __ASM_EMIT("vaddps          0x0c0 + %[E2C], %%ymm11, %%ymm11")      \
117     __ASM_EMIT("vaddps          0x0c0 + %[E2C], %%ymm15, %%ymm15")      \
118     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
119     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
120     __ASM_EMIT("vmulps          %%ymm10, %%ymm11, %%ymm11")             \
121     __ASM_EMIT("vmulps          %%ymm14, %%ymm15, %%ymm15")             \
122     __ASM_EMIT("vaddps          0x0e0 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
123     __ASM_EMIT("vaddps          0x0e0 + %[E2C], %%ymm7, %%ymm7")        \
124     __ASM_EMIT("vaddps          0x0e0 + %[E2C], %%ymm11, %%ymm11")      \
125     __ASM_EMIT("vaddps          0x0e0 + %[E2C], %%ymm15, %%ymm15")      \
126     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
127     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
128     __ASM_EMIT("vmulps          %%ymm10, %%ymm11, %%ymm11")             \
129     __ASM_EMIT("vmulps          %%ymm14, %%ymm15, %%ymm15")             \
130     __ASM_EMIT("vaddps          0x100 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
131     __ASM_EMIT("vaddps          0x100 + %[E2C], %%ymm7, %%ymm7")        \
132     __ASM_EMIT("vaddps          0x100 + %[E2C], %%ymm11, %%ymm11")      \
133     __ASM_EMIT("vaddps          0x100 + %[E2C], %%ymm15, %%ymm15")      \
134     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
135     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
136     __ASM_EMIT("vmulps          %%ymm10, %%ymm11, %%ymm11")             \
137     __ASM_EMIT("vmulps          %%ymm14, %%ymm15, %%ymm15")             \
138     __ASM_EMIT("vmulps          0x120 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
139     __ASM_EMIT("vmulps          0x120 + %[E2C], %%ymm7, %%ymm7")        \
140     __ASM_EMIT("vmulps          0x120 + %[E2C], %%ymm11, %%ymm11")      \
141     __ASM_EMIT("vmulps          0x120 + %[E2C], %%ymm15, %%ymm15")      \
142     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm2")                /* ymm2 = 1 */ \
143     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm6")                \
144     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm10")               \
145     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm14")               \
146     __ASM_EMIT("vaddps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = 1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
147     __ASM_EMIT("vaddps          %%ymm6, %%ymm7, %%ymm7")                \
148     __ASM_EMIT("vaddps          %%ymm10, %%ymm11, %%ymm11")             \
149     __ASM_EMIT("vaddps          %%ymm14, %%ymm15, %%ymm15")             \
150     __ASM_EMIT("vmulps          %%ymm1, %%ymm3, %%ymm3")                /* ymm3 = p = (1<<R)*(1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))))) */ \
151     __ASM_EMIT("vmulps          %%ymm5, %%ymm7, %%ymm7")                \
152     __ASM_EMIT("vmulps          %%ymm9, %%ymm11, %%ymm11")              \
153     __ASM_EMIT("vmulps          %%ymm13, %%ymm15, %%ymm15")             \
154     __ASM_EMIT("vdivps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = 1/p */ \
155     __ASM_EMIT("vdivps          %%ymm7, %%ymm6, %%ymm6")                \
156     __ASM_EMIT("vdivps          %%ymm11, %%ymm10, %%ymm10")             \
157     __ASM_EMIT("vdivps          %%ymm15, %%ymm14, %%ymm14")             \
158     /* ymm0 = x, ymm2 = 1/p, ymm3 = p */ \
159     __ASM_EMIT("vblendvps       %%ymm0, %%ymm2, %%ymm3, %%ymm0")        /* ymm0 = ([x<0]&(1/p)) | ([x>=0]&p) */ \
160     __ASM_EMIT("vblendvps       %%ymm4, %%ymm6, %%ymm7, %%ymm4")        \
161     __ASM_EMIT("vblendvps       %%ymm8, %%ymm10, %%ymm11, %%ymm8")      \
162     __ASM_EMIT("vblendvps       %%ymm12, %%ymm14, %%ymm15, %%ymm12")
163 
164 #define POW2_CORE_X16 \
165     /* ymm0 = x */ \
166     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm0, %%ymm2")        /* ymm2 = XP = fabs(x) */ \
167     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm4, %%ymm6")        \
168     __ASM_EMIT("vcvttps2dq      %%ymm2, %%ymm1")                        /* ymm1 = R = int(XP) */ \
169     __ASM_EMIT("vcvttps2dq      %%ymm6, %%ymm5")                        \
170     __ASM_EMIT("vcvtdq2ps       %%ymm1, %%ymm3")                        /* ymm3 = float(R) */ \
171     __ASM_EMIT("vcvtdq2ps       %%ymm5, %%ymm7")                        \
172     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm1, %%ymm1")        /* ymm1 = R + 127 */ \
173     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm5, %%ymm5")        \
174     __ASM_EMIT("vsubps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = XP - float(R) */ \
175     __ASM_EMIT("vsubps          %%ymm7, %%ymm6, %%ymm6")                \
176     __ASM_EMIT("vpslld          $23, %%ymm1, %%ymm1")                   /* ymm1 = 1 << (R+127) */ \
177     __ASM_EMIT("vpslld          $23, %%ymm5, %%ymm5")                   \
178     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm2, %%ymm2")        /* ymm2 = X = ln(2) * (XP - float(R)) */ \
179     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm6, %%ymm6")        \
180     /* ymm0 = [x<0], ymm1 = 1 << R, ymm2 = X */ \
181     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C5+X */ \
182     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm6, %%ymm7")        \
183     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C5+X) */ \
184     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
185     __ASM_EMIT("vaddps          0x080 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C4+X*(C5+X) */ \
186     __ASM_EMIT("vaddps          0x080 + %[E2C], %%ymm7, %%ymm7")        \
187     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C4+X*(C5+X)) */ \
188     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
189     __ASM_EMIT("vaddps          0x0a0 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C3+X*(C4+X*(C5+X)) */ \
190     __ASM_EMIT("vaddps          0x0a0 + %[E2C], %%ymm7, %%ymm7")        \
191     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C3+X*(C4+X*(C5+X))) */ \
192     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
193     __ASM_EMIT("vaddps          0x0c0 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C2+X*(C3+X*(C4+X*(C5+X))) */ \
194     __ASM_EMIT("vaddps          0x0c0 + %[E2C], %%ymm7, %%ymm7")        \
195     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
196     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
197     __ASM_EMIT("vaddps          0x0e0 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
198     __ASM_EMIT("vaddps          0x0e0 + %[E2C], %%ymm7, %%ymm7")        \
199     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
200     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
201     __ASM_EMIT("vaddps          0x100 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
202     __ASM_EMIT("vaddps          0x100 + %[E2C], %%ymm7, %%ymm7")        \
203     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
204     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
205     __ASM_EMIT("vmulps          0x120 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
206     __ASM_EMIT("vmulps          0x120 + %[E2C], %%ymm7, %%ymm7")        \
207     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm2")                /* ymm2 = 1 */ \
208     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm6")                \
209     __ASM_EMIT("vaddps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = 1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
210     __ASM_EMIT("vaddps          %%ymm6, %%ymm7, %%ymm7")                \
211     __ASM_EMIT("vmulps          %%ymm1, %%ymm3, %%ymm3")                /* ymm3 = p = (1<<R)*(1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))))) */ \
212     __ASM_EMIT("vmulps          %%ymm5, %%ymm7, %%ymm7")                \
213     __ASM_EMIT("vdivps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = 1/p */ \
214     __ASM_EMIT("vdivps          %%ymm7, %%ymm6, %%ymm6")                \
215     /* ymm0 = x, ymm2 = 1/p, ymm3 = p */ \
216     __ASM_EMIT("vblendvps       %%ymm0, %%ymm2, %%ymm3, %%ymm0")        /* ymm0 = ([x<0]&(1/p)) | ([x>=0]&p) */ \
217     __ASM_EMIT("vblendvps       %%ymm4, %%ymm6, %%ymm7, %%ymm4")
218 
219 
220 #define POW2_CORE_X8 \
221     /* ymm0 = x */ \
222     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm0, %%ymm2")        /* ymm2 = XP = fabs(x) */ \
223     __ASM_EMIT("vcvttps2dq      %%ymm2, %%ymm1")                        /* ymm1 = R = int(XP) */ \
224     __ASM_EMIT("vcvtdq2ps       %%ymm1, %%ymm3")                        /* ymm3 = float(R) */ \
225     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm1, %%ymm1")        /* ymm1 = R + 127 */ \
226     __ASM_EMIT("vsubps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = XP - float(R) */ \
227     __ASM_EMIT("vpslld          $23, %%ymm1, %%ymm1")                   /* ymm1 = 1 << (R+127) */ \
228     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm2, %%ymm2")        /* ymm2 = X = ln(2) * (XP - float(R)) */ \
229     /* ymm0 = [x<0], ymm1 = 1 << R, ymm2 = X */ \
230     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C5+X */ \
231     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C5+X) */ \
232     __ASM_EMIT("vaddps          0x080 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C4+X*(C5+X) */ \
233     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C4+X*(C5+X)) */ \
234     __ASM_EMIT("vaddps          0x0a0 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C3+X*(C4+X*(C5+X)) */ \
235     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C3+X*(C4+X*(C5+X))) */ \
236     __ASM_EMIT("vaddps          0x0c0 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C2+X*(C3+X*(C4+X*(C5+X))) */ \
237     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
238     __ASM_EMIT("vaddps          0x0e0 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
239     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
240     __ASM_EMIT("vaddps          0x100 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
241     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
242     __ASM_EMIT("vmulps          0x120 + %[E2C], %%ymm3, %%ymm3")        /* ymm3 = 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
243     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm2")                /* ymm2 = 1 */ \
244     __ASM_EMIT("vaddps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = 1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
245     __ASM_EMIT("vmulps          %%ymm1, %%ymm3, %%ymm3")                /* ymm3 = p = (1<<R)*(1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))))) */ \
246     __ASM_EMIT("vdivps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = 1/p */ \
247     /* ymm0 = x, ymm2 = 1/p, ymm3 = p */ \
248     __ASM_EMIT("vblendvps       %%ymm0, %%ymm2, %%ymm3, %%ymm0")        /* ymm0 = ([x<0]&(1/p)) | ([x>=0]&p) */
249 
250 #define POW2_CORE_X4 \
251     /* xmm0 = x */ \
252     __ASM_EMIT("vandps          0x000 + %[E2C], %%xmm0, %%xmm2")        /* xmm2 = XP = fabs(x) */ \
253     __ASM_EMIT("vcvttps2dq      %%xmm2, %%xmm1")                        /* xmm1 = R = int(XP) */ \
254     __ASM_EMIT("vcvtdq2ps       %%xmm1, %%xmm3")                        /* xmm3 = float(R) */ \
255     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%xmm1, %%xmm1")        /* xmm1 = R + 127 */ \
256     __ASM_EMIT("vsubps          %%xmm3, %%xmm2, %%xmm2")                /* xmm2 = XP - float(R) */ \
257     __ASM_EMIT("vpslld          $23, %%xmm1, %%xmm1")                   /* xmm1 = 1 << (R+127) */ \
258     __ASM_EMIT("vmulps          0x040 + %[E2C], %%xmm2, %%xmm2")        /* xmm2 = X = ln(2) * (XP - float(R)) */ \
259     /* xmm0 = [x<0], xmm1 = 1 << R, xmm2 = X */ \
260     __ASM_EMIT("vaddps          0x060 + %[E2C], %%xmm2, %%xmm3")        /* xmm3 = C5+X */ \
261     __ASM_EMIT("vmulps          %%xmm2, %%xmm3, %%xmm3")                /* xmm3 = X*(C5+X) */ \
262     __ASM_EMIT("vaddps          0x080 + %[E2C], %%xmm3, %%xmm3")        /* xmm3 = C4+X*(C5+X) */ \
263     __ASM_EMIT("vmulps          %%xmm2, %%xmm3, %%xmm3")                /* xmm3 = X*(C4+X*(C5+X)) */ \
264     __ASM_EMIT("vaddps          0x0a0 + %[E2C], %%xmm3, %%xmm3")        /* xmm3 = C3+X*(C4+X*(C5+X)) */ \
265     __ASM_EMIT("vmulps          %%xmm2, %%xmm3, %%xmm3")                /* xmm3 = X*(C3+X*(C4+X*(C5+X))) */ \
266     __ASM_EMIT("vaddps          0x0c0 + %[E2C], %%xmm3, %%xmm3")        /* xmm3 = C2+X*(C3+X*(C4+X*(C5+X))) */ \
267     __ASM_EMIT("vmulps          %%xmm2, %%xmm3, %%xmm3")                /* xmm3 = X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
268     __ASM_EMIT("vaddps          0x0e0 + %[E2C], %%xmm3, %%xmm3")        /* xmm3 = C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
269     __ASM_EMIT("vmulps          %%xmm2, %%xmm3, %%xmm3")                /* xmm3 = X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
270     __ASM_EMIT("vaddps          0x100 + %[E2C], %%xmm3, %%xmm3")        /* xmm3 = C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
271     __ASM_EMIT("vmulps          %%xmm2, %%xmm3, %%xmm3")                /* xmm3 = X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
272     __ASM_EMIT("vmulps          0x120 + %[E2C], %%xmm3, %%xmm3")        /* xmm3 = 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
273     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%xmm2")                /* xmm2 = 1 */ \
274     __ASM_EMIT("vaddps          %%xmm2, %%xmm3, %%xmm3")                /* xmm3 = 1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
275     __ASM_EMIT("vmulps          %%xmm1, %%xmm3, %%xmm3")                /* xmm3 = p = (1<<R)*(1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))))) */ \
276     __ASM_EMIT("vdivps          %%xmm3, %%xmm2, %%xmm2")                /* xmm2 = 1/p */ \
277     /* xmm0 = x, xmm2 = 1/p, xmm3 = p */ \
278     __ASM_EMIT("vblendvps       %%xmm0, %%xmm2, %%xmm3, %%xmm0")        /* xmm0 = ([x<0]&(1/p)) | ([x>=0]&p) */
279 
x64_exp1(float * dst,size_t count)280     void x64_exp1(float *dst, size_t count)
281     {
282         IF_ARCH_X86(float *src);
283 
284         ARCH_X86_ASM(
285             // x32 blocks
286             __ASM_EMIT("sub             $32, %[count]")
287             __ASM_EMIT("jb              2f")
288             __ASM_EMIT("1:")
289             __ASM_EMIT("vmovups         0x00(%[dst]), %%ymm0")
290             __ASM_EMIT("vmovups         0x20(%[dst]), %%ymm4")
291             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
292             __ASM_EMIT("vmovups         0x40(%[dst]), %%ymm8")
293             __ASM_EMIT("vmulps          %[LOG2E], %%ymm4, %%ymm4")
294             __ASM_EMIT("vmovups         0x60(%[dst]), %%ymm12")
295             __ASM_EMIT("vmulps          %[LOG2E], %%ymm8, %%ymm8")
296             __ASM_EMIT("vmulps          %[LOG2E], %%ymm12, %%ymm12")
297             POW2_CORE_X32
298             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
299             __ASM_EMIT("vmovups         %%ymm4, 0x20(%[dst])")
300             __ASM_EMIT("vmovups         %%ymm8, 0x40(%[dst])")
301             __ASM_EMIT("vmovups         %%ymm12, 0x60(%[dst])")
302             __ASM_EMIT("add             $0x80, %[dst]")
303             __ASM_EMIT("sub             $32, %[count]")
304             __ASM_EMIT("jae             1b")
305 
306             // x16 block
307             __ASM_EMIT("2:")
308             __ASM_EMIT("add             $16, %[count]")
309             __ASM_EMIT("jl              4f")
310             __ASM_EMIT("vmovups         0x00(%[dst]), %%ymm0")
311             __ASM_EMIT("vmovups         0x20(%[dst]), %%ymm4")
312             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
313             __ASM_EMIT("vmulps          %[LOG2E], %%ymm4, %%ymm4")
314             POW2_CORE_X16
315             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
316             __ASM_EMIT("vmovups         %%ymm4, 0x20(%[dst])")
317             __ASM_EMIT("sub             $16, %[count]")
318             __ASM_EMIT("add             $0x40, %[dst]")
319 
320             // x8 block
321             __ASM_EMIT("4:")
322             __ASM_EMIT("add             $8, %[count]")
323             __ASM_EMIT("jl              6f")
324             __ASM_EMIT("vmovups         0x00(%[dst]), %%ymm0")
325             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
326             POW2_CORE_X8
327             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
328             __ASM_EMIT("sub             $8, %[count]")
329             __ASM_EMIT("add             $0x20, %[dst]")
330 
331             // x4 block
332             __ASM_EMIT("6:")
333             __ASM_EMIT("add             $4, %[count]")
334             __ASM_EMIT("jl              8f")
335             __ASM_EMIT("vmovups         0x00(%[dst]), %%xmm0")
336             __ASM_EMIT("vmulps          %[LOG2E], %%xmm0, %%xmm0")
337             POW2_CORE_X4
338             __ASM_EMIT("vmovups         %%xmm0, 0x00(%[dst])")
339             __ASM_EMIT("sub             $4, %[count]")
340             __ASM_EMIT("add             $0x10, %[dst]")
341 
342             // Tail: 1x-3x block
343             __ASM_EMIT("8:")
344             __ASM_EMIT("add             $4, %[count]")
345             __ASM_EMIT("jle             16f")
346             __ASM_EMIT("mov             %[dst], %[src]")
347             __ASM_EMIT("test            $1, %[count]")
348             __ASM_EMIT("jz              10f")
349             __ASM_EMIT("vmovss          0x00(%[src]), %%xmm0")
350             __ASM_EMIT("add             $4, %[src]")
351             __ASM_EMIT("10:")
352             __ASM_EMIT("test            $2, %[count]")
353             __ASM_EMIT("jz              12f")
354             __ASM_EMIT("vmovhps         0x00(%[src]), %%xmm0, %%xmm0")
355             __ASM_EMIT("12:")
356 
357             __ASM_EMIT("vmulps          %[LOG2E], %%xmm0, %%xmm0")
358             POW2_CORE_X4
359 
360             __ASM_EMIT("test            $1, %[count]")
361             __ASM_EMIT("jz              14f")
362             __ASM_EMIT("vmovss          %%xmm0, 0x00(%[dst])")
363             __ASM_EMIT("add             $4, %[dst]")
364             __ASM_EMIT("14:")
365             __ASM_EMIT("test            $2, %[count]")
366             __ASM_EMIT("jz              16f")
367             __ASM_EMIT("vmovhps         %%xmm0, 0x00(%[dst])")
368 
369             // End
370             __ASM_EMIT("16:")
371             __ASM_EMIT("vzeroupper")
372 
373             : [dst] "+r" (dst), [src] "=&r" (src), [count] "+r" (count)
374             : [E2C] "o" (EXP2_CONST),
375               [LOG2E] "m" (EXP_LOG2E)
376             : "cc", "memory",
377               "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",
378               "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14", "%xmm15"
379         );
380     }
381 
x64_exp2(float * dst,const float * src,size_t count)382     void x64_exp2(float *dst, const float *src, size_t count)
383     {
384         ARCH_X86_ASM(
385             // x32 blocks
386             __ASM_EMIT("sub             $32, %[count]")
387             __ASM_EMIT("jb              2f")
388             __ASM_EMIT("1:")
389             __ASM_EMIT("vmovups         0x00(%[src]), %%ymm0")
390             __ASM_EMIT("vmovups         0x20(%[src]), %%ymm4")
391             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
392             __ASM_EMIT("vmovups         0x40(%[src]), %%ymm8")
393             __ASM_EMIT("vmulps          %[LOG2E], %%ymm4, %%ymm4")
394             __ASM_EMIT("vmovups         0x60(%[src]), %%ymm12")
395             __ASM_EMIT("vmulps          %[LOG2E], %%ymm8, %%ymm8")
396             __ASM_EMIT("vmulps          %[LOG2E], %%ymm12, %%ymm12")
397             POW2_CORE_X32
398             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
399             __ASM_EMIT("vmovups         %%ymm4, 0x20(%[dst])")
400             __ASM_EMIT("vmovups         %%ymm8, 0x40(%[dst])")
401             __ASM_EMIT("vmovups         %%ymm12, 0x60(%[dst])")
402             __ASM_EMIT("add             $0x80, %[src]")
403             __ASM_EMIT("add             $0x80, %[dst]")
404             __ASM_EMIT("sub             $32, %[count]")
405             __ASM_EMIT("jae             1b")
406 
407             // x16 block
408             __ASM_EMIT("2:")
409             __ASM_EMIT("add             $16, %[count]")
410             __ASM_EMIT("jl              4f")
411             __ASM_EMIT("vmovups         0x00(%[src]), %%ymm0")
412             __ASM_EMIT("vmovups         0x20(%[src]), %%ymm4")
413             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
414             __ASM_EMIT("vmulps          %[LOG2E], %%ymm4, %%ymm4")
415             POW2_CORE_X16
416             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
417             __ASM_EMIT("vmovups         %%ymm4, 0x20(%[dst])")
418             __ASM_EMIT("sub             $16, %[count]")
419             __ASM_EMIT("add             $0x40, %[src]")
420             __ASM_EMIT("add             $0x40, %[dst]")
421 
422             // x8 block
423             __ASM_EMIT("4:")
424             __ASM_EMIT("add             $8, %[count]")
425             __ASM_EMIT("jl              6f")
426             __ASM_EMIT("vmovups         0x00(%[src]), %%ymm0")
427             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
428             POW2_CORE_X8
429             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
430             __ASM_EMIT("sub             $8, %[count]")
431             __ASM_EMIT("add             $0x20, %[src]")
432             __ASM_EMIT("add             $0x20, %[dst]")
433 
434             // x4 block
435             __ASM_EMIT("6:")
436             __ASM_EMIT("add             $4, %[count]")
437             __ASM_EMIT("jl              8f")
438             __ASM_EMIT("vmovups         0x00(%[src]), %%xmm0")
439             __ASM_EMIT("vmulps          %[LOG2E], %%xmm0, %%xmm0")
440             POW2_CORE_X4
441             __ASM_EMIT("vmovups         %%xmm0, 0x00(%[dst])")
442             __ASM_EMIT("sub             $4, %[count]")
443             __ASM_EMIT("add             $0x10, %[src]")
444             __ASM_EMIT("add             $0x10, %[dst]")
445 
446             // Tail: 1x-3x block
447             __ASM_EMIT("8:")
448             __ASM_EMIT("add             $4, %[count]")
449             __ASM_EMIT("jle             16f")
450             __ASM_EMIT("test            $1, %[count]")
451             __ASM_EMIT("jz              10f")
452             __ASM_EMIT("vmovss          0x00(%[src]), %%xmm0")
453             __ASM_EMIT("add             $4, %[src]")
454             __ASM_EMIT("10:")
455             __ASM_EMIT("test            $2, %[count]")
456             __ASM_EMIT("jz              12f")
457             __ASM_EMIT("vmovhps         0x00(%[src]), %%xmm0, %%xmm0")
458             __ASM_EMIT("12:")
459 
460             __ASM_EMIT("vmulps          %[LOG2E], %%xmm0, %%xmm0")
461             POW2_CORE_X4
462 
463             __ASM_EMIT("test            $1, %[count]")
464             __ASM_EMIT("jz              14f")
465             __ASM_EMIT("vmovss          %%xmm0, 0x00(%[dst])")
466             __ASM_EMIT("add             $4, %[dst]")
467             __ASM_EMIT("14:")
468             __ASM_EMIT("test            $2, %[count]")
469             __ASM_EMIT("jz              16f")
470             __ASM_EMIT("vmovhps         %%xmm0, 0x00(%[dst])")
471 
472             // End
473             __ASM_EMIT("16:")
474             __ASM_EMIT("vzeroupper")
475 
476             : [dst] "+r" (dst), [src] "+r" (src), [count] "+r" (count)
477             : [E2C] "o" (EXP2_CONST),
478               [LOG2E] "m" (EXP_LOG2E)
479             : "cc", "memory",
480               "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",
481               "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14", "%xmm15"
482         );
483     }
484 
485 
486 #define POW2_FMA3_CORE_X32 \
487     /* ymm0 = x */ \
488     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm0, %%ymm2")        /* ymm2 = XP = fabs(x) */ \
489     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm4, %%ymm6")        \
490     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm8, %%ymm10")       \
491     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm12, %%ymm14")      \
492     __ASM_EMIT("vcvttps2dq      %%ymm2, %%ymm1")                        /* ymm1 = R = int(XP) */ \
493     __ASM_EMIT("vcvttps2dq      %%ymm6, %%ymm5")                        \
494     __ASM_EMIT("vcvttps2dq      %%ymm10, %%ymm9")                       \
495     __ASM_EMIT("vcvttps2dq      %%ymm14, %%ymm13")                      \
496     __ASM_EMIT("vcvtdq2ps       %%ymm1, %%ymm3")                        /* ymm3 = float(R) */ \
497     __ASM_EMIT("vcvtdq2ps       %%ymm5, %%ymm7")                        \
498     __ASM_EMIT("vcvtdq2ps       %%ymm9, %%ymm11")                       \
499     __ASM_EMIT("vcvtdq2ps       %%ymm13, %%ymm15")                      \
500     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm1, %%ymm1")        /* ymm1 = R + 127 */ \
501     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm5, %%ymm5")        \
502     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm9, %%ymm9")        \
503     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm13, %%ymm13")      \
504     __ASM_EMIT("vsubps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = XP - float(R) */ \
505     __ASM_EMIT("vsubps          %%ymm7, %%ymm6, %%ymm6")                \
506     __ASM_EMIT("vsubps          %%ymm11, %%ymm10, %%ymm10")             \
507     __ASM_EMIT("vsubps          %%ymm15, %%ymm14, %%ymm14")             \
508     __ASM_EMIT("vpslld          $23, %%ymm1, %%ymm1")                   /* ymm1 = 1 << (R+127) */ \
509     __ASM_EMIT("vpslld          $23, %%ymm5, %%ymm5")                   \
510     __ASM_EMIT("vpslld          $23, %%ymm9, %%ymm9")                   \
511     __ASM_EMIT("vpslld          $23, %%ymm13, %%ymm13")                 \
512     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm2, %%ymm2")        /* ymm2 = X = ln(2) * (XP - float(R)) */ \
513     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm6, %%ymm6")        \
514     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm10, %%ymm10")      \
515     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm14, %%ymm14")      \
516     /* ymm0 = [x<0], ymm1 = 1 << R, ymm2 = X */ \
517     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C5+X */ \
518     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm6, %%ymm7")        \
519     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm10, %%ymm11")      \
520     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm14, %%ymm15")      \
521     __ASM_EMIT("vfmadd213ps     0x080 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C4+X*(C5+X) */ \
522     __ASM_EMIT("vfmadd213ps     0x080 + %[E2C], %%ymm6, %%ymm7")        \
523     __ASM_EMIT("vfmadd213ps     0x080 + %[E2C], %%ymm10, %%ymm11")      \
524     __ASM_EMIT("vfmadd213ps     0x080 + %[E2C], %%ymm14, %%ymm15")      \
525     __ASM_EMIT("vfmadd213ps     0x0a0 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C3+X*(C4+X*(C5+X)) */ \
526     __ASM_EMIT("vfmadd213ps     0x0a0 + %[E2C], %%ymm6, %%ymm7")        \
527     __ASM_EMIT("vfmadd213ps     0x0a0 + %[E2C], %%ymm10, %%ymm11")      \
528     __ASM_EMIT("vfmadd213ps     0x0a0 + %[E2C], %%ymm14, %%ymm15")      \
529     __ASM_EMIT("vfmadd213ps     0x0c0 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C2+X*(C3+X*(C4+X*(C5+X))) */ \
530     __ASM_EMIT("vfmadd213ps     0x0c0 + %[E2C], %%ymm6, %%ymm7")        \
531     __ASM_EMIT("vfmadd213ps     0x0c0 + %[E2C], %%ymm10, %%ymm11")      \
532     __ASM_EMIT("vfmadd213ps     0x0c0 + %[E2C], %%ymm14, %%ymm15")      \
533     __ASM_EMIT("vfmadd213ps     0x0e0 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
534     __ASM_EMIT("vfmadd213ps     0x0e0 + %[E2C], %%ymm6, %%ymm7")        \
535     __ASM_EMIT("vfmadd213ps     0x0e0 + %[E2C], %%ymm10, %%ymm11")      \
536     __ASM_EMIT("vfmadd213ps     0x0e0 + %[E2C], %%ymm14, %%ymm15")      \
537     __ASM_EMIT("vfmadd213ps     0x100 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
538     __ASM_EMIT("vfmadd213ps     0x100 + %[E2C], %%ymm6, %%ymm7")        \
539     __ASM_EMIT("vfmadd213ps     0x100 + %[E2C], %%ymm10, %%ymm11")      \
540     __ASM_EMIT("vfmadd213ps     0x100 + %[E2C], %%ymm14, %%ymm15")      \
541     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
542     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
543     __ASM_EMIT("vmulps          %%ymm10, %%ymm11, %%ymm11")             \
544     __ASM_EMIT("vmulps          %%ymm14, %%ymm15, %%ymm15")             \
545     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm2")                /* ymm2 = 1 */ \
546     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm6")                \
547     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm10")               \
548     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm14")               \
549     __ASM_EMIT("vfmadd132ps     0x120 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = 1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
550     __ASM_EMIT("vfmadd132ps     0x120 + %[E2C], %%ymm6, %%ymm7")        \
551     __ASM_EMIT("vfmadd132ps     0x120 + %[E2C], %%ymm10, %%ymm11")      \
552     __ASM_EMIT("vfmadd132ps     0x120 + %[E2C], %%ymm14, %%ymm15")      \
553     __ASM_EMIT("vmulps          %%ymm1, %%ymm3, %%ymm3")                /* ymm3 = p = (1<<R)*(1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))))) */ \
554     __ASM_EMIT("vmulps          %%ymm5, %%ymm7, %%ymm7")                \
555     __ASM_EMIT("vmulps          %%ymm9, %%ymm11, %%ymm11")              \
556     __ASM_EMIT("vmulps          %%ymm13, %%ymm15, %%ymm15")             \
557     __ASM_EMIT("vdivps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = 1/p */ \
558     __ASM_EMIT("vdivps          %%ymm7, %%ymm6, %%ymm6")                \
559     __ASM_EMIT("vdivps          %%ymm11, %%ymm10, %%ymm10")             \
560     __ASM_EMIT("vdivps          %%ymm15, %%ymm14, %%ymm14")             \
561     /* ymm0 = x, ymm2 = 1/p, ymm3 = p */ \
562     __ASM_EMIT("vblendvps       %%ymm0, %%ymm2, %%ymm3, %%ymm0")        /* ymm0 = ([x<0]&(1/p)) | ([x>=0]&p) */ \
563     __ASM_EMIT("vblendvps       %%ymm4, %%ymm6, %%ymm7, %%ymm4")        \
564     __ASM_EMIT("vblendvps       %%ymm8, %%ymm10, %%ymm11, %%ymm8")      \
565     __ASM_EMIT("vblendvps       %%ymm12, %%ymm14, %%ymm15, %%ymm12")
566 
567 
568 #define POW2_FMA3_CORE_X16 \
569     /* ymm0 = x */ \
570     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm0, %%ymm2")        /* ymm2 = XP = fabs(x) */ \
571     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm4, %%ymm6")        \
572     __ASM_EMIT("vcvttps2dq      %%ymm2, %%ymm1")                        /* ymm1 = R = int(XP) */ \
573     __ASM_EMIT("vcvttps2dq      %%ymm6, %%ymm5")                        \
574     __ASM_EMIT("vcvtdq2ps       %%ymm1, %%ymm3")                        /* ymm3 = float(R) */ \
575     __ASM_EMIT("vcvtdq2ps       %%ymm5, %%ymm7")                        \
576     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm1, %%ymm1")        /* ymm1 = R + 127 */ \
577     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm5, %%ymm5")        \
578     __ASM_EMIT("vsubps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = XP - float(R) */ \
579     __ASM_EMIT("vsubps          %%ymm7, %%ymm6, %%ymm6")                \
580     __ASM_EMIT("vpslld          $23, %%ymm1, %%ymm1")                   /* ymm1 = 1 << (R+127) */ \
581     __ASM_EMIT("vpslld          $23, %%ymm5, %%ymm5")                   \
582     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm2, %%ymm2")        /* ymm2 = X = ln(2) * (XP - float(R)) */ \
583     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm6, %%ymm6")        \
584     /* ymm0 = [x<0], ymm1 = 1 << R, ymm2 = X */ \
585     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C5+X */ \
586     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm6, %%ymm7")        \
587     __ASM_EMIT("vfmadd213ps     0x080 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C4+X*(C5+X) */ \
588     __ASM_EMIT("vfmadd213ps     0x080 + %[E2C], %%ymm6, %%ymm7")        \
589     __ASM_EMIT("vfmadd213ps     0x0a0 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C3+X*(C4+X*(C5+X)) */ \
590     __ASM_EMIT("vfmadd213ps     0x0a0 + %[E2C], %%ymm6, %%ymm7")        \
591     __ASM_EMIT("vfmadd213ps     0x0c0 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C2+X*(C3+X*(C4+X*(C5+X))) */ \
592     __ASM_EMIT("vfmadd213ps     0x0c0 + %[E2C], %%ymm6, %%ymm7")        \
593     __ASM_EMIT("vfmadd213ps     0x0e0 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
594     __ASM_EMIT("vfmadd213ps     0x0e0 + %[E2C], %%ymm6, %%ymm7")        \
595     __ASM_EMIT("vfmadd213ps     0x100 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
596     __ASM_EMIT("vfmadd213ps     0x100 + %[E2C], %%ymm6, %%ymm7")        \
597     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
598     __ASM_EMIT("vmulps          %%ymm6, %%ymm7, %%ymm7")                \
599     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm2")                /* ymm2 = 1 */ \
600     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm6")                \
601     __ASM_EMIT("vfmadd132ps     0x120 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = 1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
602     __ASM_EMIT("vfmadd132ps     0x120 + %[E2C], %%ymm6, %%ymm7")        \
603     __ASM_EMIT("vmulps          %%ymm1, %%ymm3, %%ymm3")                /* ymm3 = p = (1<<R)*(1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))))) */ \
604     __ASM_EMIT("vmulps          %%ymm5, %%ymm7, %%ymm7")                \
605     __ASM_EMIT("vdivps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = 1/p */ \
606     __ASM_EMIT("vdivps          %%ymm7, %%ymm6, %%ymm6")                \
607     /* ymm0 = x, ymm2 = 1/p, ymm3 = p */ \
608     __ASM_EMIT("vblendvps       %%ymm0, %%ymm2, %%ymm3, %%ymm0")        /* ymm0 = ([x<0]&(1/p)) | ([x>=0]&p) */ \
609     __ASM_EMIT("vblendvps       %%ymm4, %%ymm6, %%ymm7, %%ymm4")
610 
611 #define POW2_FMA3_CORE_X8 \
612     /* ymm0 = x */ \
613     __ASM_EMIT("vandps          0x000 + %[E2C], %%ymm0, %%ymm2")        /* ymm2 = XP = fabs(x) */ \
614     __ASM_EMIT("vcvttps2dq      %%ymm2, %%ymm1")                        /* ymm1 = R = int(XP) */ \
615     __ASM_EMIT("vcvtdq2ps       %%ymm1, %%ymm3")                        /* ymm3 = float(R) */ \
616     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%ymm1, %%ymm1")        /* ymm1 = R + 127 */ \
617     __ASM_EMIT("vsubps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = XP - float(R) */ \
618     __ASM_EMIT("vpslld          $23, %%ymm1, %%ymm1")                   /* ymm1 = 1 << (R+127) */ \
619     __ASM_EMIT("vmulps          0x040 + %[E2C], %%ymm2, %%ymm2")        /* ymm2 = X = ln(2) * (XP - float(R)) */ \
620     /* ymm0 = [x<0], ymm1 = 1 << R, ymm2 = X */ \
621     __ASM_EMIT("vaddps          0x060 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C5+X */ \
622     __ASM_EMIT("vfmadd213ps     0x080 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C4+X*(C5+X) */ \
623     __ASM_EMIT("vfmadd213ps     0x0a0 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C3+X*(C4+X*(C5+X)) */ \
624     __ASM_EMIT("vfmadd213ps     0x0c0 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C2+X*(C3+X*(C4+X*(C5+X))) */ \
625     __ASM_EMIT("vfmadd213ps     0x0e0 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
626     __ASM_EMIT("vfmadd213ps     0x100 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
627     __ASM_EMIT("vmulps          %%ymm2, %%ymm3, %%ymm3")                /* ymm3 = X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
628     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%ymm2")                /* ymm2 = 1 */ \
629     __ASM_EMIT("vfmadd132ps     0x120 + %[E2C], %%ymm2, %%ymm3")        /* ymm3 = 1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
630     __ASM_EMIT("vmulps          %%ymm1, %%ymm3, %%ymm3")                /* ymm3 = p = (1<<R)*(1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))))) */ \
631     __ASM_EMIT("vdivps          %%ymm3, %%ymm2, %%ymm2")                /* ymm2 = 1/p */ \
632     /* ymm0 = x, ymm2 = 1/p, ymm3 = p */ \
633     __ASM_EMIT("vblendvps       %%ymm0, %%ymm2, %%ymm3, %%ymm0")        /* ymm0 = ([x<0]&(1/p)) | ([x>=0]&p) */
634 
635 #define POW2_FMA3_CORE_X4 \
636     /* xmm0 = x */ \
637     __ASM_EMIT("vandps          0x000 + %[E2C], %%xmm0, %%xmm2")        /* xmm2 = XP = fabs(x) */ \
638     __ASM_EMIT("vcvttps2dq      %%xmm2, %%xmm1")                        /* xmm1 = R = int(XP) */ \
639     __ASM_EMIT("vcvtdq2ps       %%xmm1, %%xmm3")                        /* xmm3 = float(R) */ \
640     __ASM_EMIT("vpaddd          0x020 + %[E2C], %%xmm1, %%xmm1")        /* xmm1 = R + 127 */ \
641     __ASM_EMIT("vsubps          %%xmm3, %%xmm2, %%xmm2")                /* xmm2 = XP - float(R) */ \
642     __ASM_EMIT("vpslld          $23, %%xmm1, %%xmm1")                   /* xmm1 = 1 << (R+127) */ \
643     __ASM_EMIT("vmulps          0x040 + %[E2C], %%xmm2, %%xmm2")        /* xmm2 = X = ln(2) * (XP - float(R)) */ \
644     /* xmm0 = [x<0], xmm1 = 1 << R, xmm2 = X */ \
645     __ASM_EMIT("vaddps          0x060 + %[E2C], %%xmm2, %%xmm3")        /* xmm3 = C5+X */ \
646     __ASM_EMIT("vfmadd213ps     0x080 + %[E2C], %%xmm2, %%xmm3")        /* xmm3 = C4+X*(C5+X) */ \
647     __ASM_EMIT("vfmadd213ps     0x0a0 + %[E2C], %%xmm2, %%xmm3")        /* xmm3 = C3+X*(C4+X*(C5+X)) */ \
648     __ASM_EMIT("vfmadd213ps     0x0c0 + %[E2C], %%xmm2, %%xmm3")        /* xmm3 = C2+X*(C3+X*(C4+X*(C5+X))) */ \
649     __ASM_EMIT("vfmadd213ps     0x0e0 + %[E2C], %%xmm2, %%xmm3")        /* xmm3 = C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))) */ \
650     __ASM_EMIT("vfmadd213ps     0x100 + %[E2C], %%xmm2, %%xmm3")        /* xmm3 = C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))) */ \
651     __ASM_EMIT("vmulps          %%xmm2, %%xmm3, %%xmm3")                /* xmm3 = X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
652     __ASM_EMIT("vmovaps         0x140 + %[E2C], %%xmm2")                /* xmm2 = 1 */ \
653     __ASM_EMIT("vfmadd132ps     0x120 + %[E2C], %%xmm2, %%xmm3")        /* xmm3 = 1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X)))))) */ \
654     __ASM_EMIT("vmulps          %%xmm1, %%xmm3, %%xmm3")                /* xmm3 = p = (1<<R)*(1 + 1/7!*X*(C0+X*(C1+X*(C2+X*(C3+X*(C4+X*(C5+X))))))) */ \
655     __ASM_EMIT("vdivps          %%xmm3, %%xmm2, %%xmm2")                /* xmm2 = 1/p */ \
656     /* xmm0 = x, xmm2 = 1/p, xmm3 = p */ \
657     __ASM_EMIT("vblendvps       %%xmm0, %%xmm2, %%xmm3, %%xmm0")        /* xmm0 = ([x<0]&(1/p)) | ([x>=0]&p) */
658 
x64_exp1_fma3(float * dst,size_t count)659     void x64_exp1_fma3(float *dst, size_t count)
660     {
661         IF_ARCH_X86(float *src);
662 
663         ARCH_X86_ASM(
664             // x32 blocks
665             __ASM_EMIT("sub             $32, %[count]")
666             __ASM_EMIT("jb              2f")
667             __ASM_EMIT("1:")
668             __ASM_EMIT("vmovups         0x00(%[dst]), %%ymm0")
669             __ASM_EMIT("vmovups         0x20(%[dst]), %%ymm4")
670             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
671             __ASM_EMIT("vmovups         0x40(%[dst]), %%ymm8")
672             __ASM_EMIT("vmulps          %[LOG2E], %%ymm4, %%ymm4")
673             __ASM_EMIT("vmovups         0x60(%[dst]), %%ymm12")
674             __ASM_EMIT("vmulps          %[LOG2E], %%ymm8, %%ymm8")
675             __ASM_EMIT("vmulps          %[LOG2E], %%ymm12, %%ymm12")
676             POW2_FMA3_CORE_X32
677             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
678             __ASM_EMIT("vmovups         %%ymm4, 0x20(%[dst])")
679             __ASM_EMIT("vmovups         %%ymm8, 0x40(%[dst])")
680             __ASM_EMIT("vmovups         %%ymm12, 0x60(%[dst])")
681             __ASM_EMIT("add             $0x80, %[dst]")
682             __ASM_EMIT("sub             $32, %[count]")
683             __ASM_EMIT("jae             1b")
684 
685             // x16 block
686             __ASM_EMIT("2:")
687             __ASM_EMIT("add             $16, %[count]")
688             __ASM_EMIT("jl              4f")
689             __ASM_EMIT("vmovups         0x00(%[dst]), %%ymm0")
690             __ASM_EMIT("vmovups         0x20(%[dst]), %%ymm4")
691             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
692             __ASM_EMIT("vmulps          %[LOG2E], %%ymm4, %%ymm4")
693             POW2_FMA3_CORE_X16
694             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
695             __ASM_EMIT("vmovups         %%ymm4, 0x20(%[dst])")
696             __ASM_EMIT("sub             $16, %[count]")
697             __ASM_EMIT("add             $0x40, %[dst]")
698 
699             // x8 block
700             __ASM_EMIT("4:")
701             __ASM_EMIT("add             $8, %[count]")
702             __ASM_EMIT("jl              6f")
703             __ASM_EMIT("vmovups         0x00(%[dst]), %%ymm0")
704             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
705             POW2_FMA3_CORE_X8
706             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
707             __ASM_EMIT("sub             $8, %[count]")
708             __ASM_EMIT("add             $0x20, %[dst]")
709 
710             // x4 block
711             __ASM_EMIT("6:")
712             __ASM_EMIT("add             $4, %[count]")
713             __ASM_EMIT("jl              8f")
714             __ASM_EMIT("vmovups         0x00(%[dst]), %%xmm0")
715             __ASM_EMIT("vmulps          %[LOG2E], %%xmm0, %%xmm0")
716             POW2_FMA3_CORE_X4
717             __ASM_EMIT("vmovups         %%xmm0, 0x00(%[dst])")
718             __ASM_EMIT("sub             $4, %[count]")
719             __ASM_EMIT("add             $0x10, %[dst]")
720 
721             // Tail: 1x-3x block
722             __ASM_EMIT("8:")
723             __ASM_EMIT("add             $4, %[count]")
724             __ASM_EMIT("jle             16f")
725             __ASM_EMIT("mov             %[dst], %[src]")
726             __ASM_EMIT("test            $1, %[count]")
727             __ASM_EMIT("jz              10f")
728             __ASM_EMIT("vmovss          0x00(%[src]), %%xmm0")
729             __ASM_EMIT("add             $4, %[src]")
730             __ASM_EMIT("10:")
731             __ASM_EMIT("test            $2, %[count]")
732             __ASM_EMIT("jz              12f")
733             __ASM_EMIT("vmovhps         0x00(%[src]), %%xmm0, %%xmm0")
734             __ASM_EMIT("12:")
735 
736             __ASM_EMIT("vmulps          %[LOG2E], %%xmm0, %%xmm0")
737             POW2_FMA3_CORE_X4
738 
739             __ASM_EMIT("test            $1, %[count]")
740             __ASM_EMIT("jz              14f")
741             __ASM_EMIT("vmovss          %%xmm0, 0x00(%[dst])")
742             __ASM_EMIT("add             $4, %[dst]")
743             __ASM_EMIT("14:")
744             __ASM_EMIT("test            $2, %[count]")
745             __ASM_EMIT("jz              16f")
746             __ASM_EMIT("vmovhps         %%xmm0, 0x00(%[dst])")
747 
748             // End
749             __ASM_EMIT("16:")
750             __ASM_EMIT("vzeroupper")
751 
752             : [dst] "+r" (dst), [src] "=&r" (src), [count] "+r" (count)
753             : [E2C] "o" (EXP2_CONST),
754               [LOG2E] "m" (EXP_LOG2E)
755             : "cc", "memory",
756               "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",
757               "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14", "%xmm15"
758         );
759     }
760 
x64_exp2_fma3(float * dst,const float * src,size_t count)761     void x64_exp2_fma3(float *dst, const float *src, size_t count)
762     {
763         ARCH_X86_ASM(
764             // x32 blocks
765             __ASM_EMIT("sub             $32, %[count]")
766             __ASM_EMIT("jb              2f")
767             __ASM_EMIT("1:")
768             __ASM_EMIT("vmovups         0x00(%[src]), %%ymm0")
769             __ASM_EMIT("vmovups         0x20(%[src]), %%ymm4")
770             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
771             __ASM_EMIT("vmovups         0x40(%[src]), %%ymm8")
772             __ASM_EMIT("vmulps          %[LOG2E], %%ymm4, %%ymm4")
773             __ASM_EMIT("vmovups         0x60(%[src]), %%ymm12")
774             __ASM_EMIT("vmulps          %[LOG2E], %%ymm8, %%ymm8")
775             __ASM_EMIT("vmulps          %[LOG2E], %%ymm12, %%ymm12")
776             POW2_FMA3_CORE_X32
777             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
778             __ASM_EMIT("vmovups         %%ymm4, 0x20(%[dst])")
779             __ASM_EMIT("vmovups         %%ymm8, 0x40(%[dst])")
780             __ASM_EMIT("vmovups         %%ymm12, 0x60(%[dst])")
781             __ASM_EMIT("add             $0x80, %[src]")
782             __ASM_EMIT("add             $0x80, %[dst]")
783             __ASM_EMIT("sub             $32, %[count]")
784             __ASM_EMIT("jae             1b")
785 
786             // x16 block
787             __ASM_EMIT("2:")
788             __ASM_EMIT("add             $16, %[count]")
789             __ASM_EMIT("jl              4f")
790             __ASM_EMIT("vmovups         0x00(%[src]), %%ymm0")
791             __ASM_EMIT("vmovups         0x20(%[src]), %%ymm4")
792             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
793             __ASM_EMIT("vmulps          %[LOG2E], %%ymm4, %%ymm4")
794             POW2_FMA3_CORE_X16
795             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
796             __ASM_EMIT("vmovups         %%ymm4, 0x20(%[dst])")
797             __ASM_EMIT("sub             $16, %[count]")
798             __ASM_EMIT("add             $0x40, %[src]")
799             __ASM_EMIT("add             $0x40, %[dst]")
800 
801             // x8 block
802             __ASM_EMIT("4:")
803             __ASM_EMIT("add             $8, %[count]")
804             __ASM_EMIT("jl              6f")
805             __ASM_EMIT("vmovups         0x00(%[src]), %%ymm0")
806             __ASM_EMIT("vmulps          %[LOG2E], %%ymm0, %%ymm0")
807             POW2_FMA3_CORE_X8
808             __ASM_EMIT("vmovups         %%ymm0, 0x00(%[dst])")
809             __ASM_EMIT("sub             $8, %[count]")
810             __ASM_EMIT("add             $0x20, %[src]")
811             __ASM_EMIT("add             $0x20, %[dst]")
812 
813             // x4 block
814             __ASM_EMIT("6:")
815             __ASM_EMIT("add             $4, %[count]")
816             __ASM_EMIT("jl              8f")
817             __ASM_EMIT("vmovups         0x00(%[src]), %%xmm0")
818             __ASM_EMIT("vmulps          %[LOG2E], %%xmm0, %%xmm0")
819             POW2_FMA3_CORE_X4
820             __ASM_EMIT("vmovups         %%xmm0, 0x00(%[dst])")
821             __ASM_EMIT("sub             $4, %[count]")
822             __ASM_EMIT("add             $0x10, %[src]")
823             __ASM_EMIT("add             $0x10, %[dst]")
824 
825             // Tail: 1x-3x block
826             __ASM_EMIT("8:")
827             __ASM_EMIT("add             $4, %[count]")
828             __ASM_EMIT("jle             16f")
829             __ASM_EMIT("test            $1, %[count]")
830             __ASM_EMIT("jz              10f")
831             __ASM_EMIT("vmovss          0x00(%[src]), %%xmm0")
832             __ASM_EMIT("add             $4, %[src]")
833             __ASM_EMIT("10:")
834             __ASM_EMIT("test            $2, %[count]")
835             __ASM_EMIT("jz              12f")
836             __ASM_EMIT("vmovhps         0x00(%[src]), %%xmm0, %%xmm0")
837             __ASM_EMIT("12:")
838 
839             __ASM_EMIT("vmulps          %[LOG2E], %%xmm0, %%xmm0")
840             POW2_FMA3_CORE_X4
841 
842             __ASM_EMIT("test            $1, %[count]")
843             __ASM_EMIT("jz              14f")
844             __ASM_EMIT("vmovss          %%xmm0, 0x00(%[dst])")
845             __ASM_EMIT("add             $4, %[dst]")
846             __ASM_EMIT("14:")
847             __ASM_EMIT("test            $2, %[count]")
848             __ASM_EMIT("jz              16f")
849             __ASM_EMIT("vmovhps         %%xmm0, 0x00(%[dst])")
850 
851             // End
852             __ASM_EMIT("16:")
853             __ASM_EMIT("vzeroupper")
854 
855             : [dst] "+r" (dst), [src] "+r" (src), [count] "+r" (count)
856             : [E2C] "o" (EXP2_CONST),
857               [LOG2E] "m" (EXP_LOG2E)
858             : "cc", "memory",
859               "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",
860               "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14", "%xmm15"
861         );
862     }
863 
864 }
865 
866 #endif /* ARCH_X86_64 */
867 
868 #endif /* DSP_ARCH_X86_AVX2_PMATH_EXP_H_ */
869