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: 26 нояб. 2019 г.
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_ARM_NEON_D32_PMATH_ABS_VV_H_
23 #define DSP_ARCH_ARM_NEON_D32_PMATH_ABS_VV_H_
24 
25 #ifndef DSP_ARCH_ARM_NEON_32_IMPL
26     #error "This header should not be included directly"
27 #endif /* DSP_ARCH_ARM_NEON_32_IMPL */
28 
29 namespace neon_d32
30 {
31 #define OP_DSEL(a, b)      a
32 #define OP_RSEL(a, b)      b
33 
34 #define ABS_VV2_CORE(DST, SRC, OP, SEL) \
35     __ASM_EMIT("subs        %[count], $32") \
36     __ASM_EMIT("blo         2f") \
37     /* 32x blocks */ \
38     __ASM_EMIT("1:") \
39     __ASM_EMIT("vldm        %[" SEL(SRC, DST) "], {q8-q15}") \
40     __ASM_EMIT("vldm        %[" SEL(DST, SRC) "], {q0-q7}") \
41     __ASM_EMIT("vabs.f32    " SEL("q8, q8", "q0, q0")) \
42     __ASM_EMIT("vabs.f32    " SEL("q9, q9", "q1, q1")) \
43     __ASM_EMIT("vabs.f32    " SEL("q10, q10", "q2, q2")) \
44     __ASM_EMIT("vabs.f32    " SEL("q11, q11", "q3, q3")) \
45     __ASM_EMIT("vabs.f32    " SEL("q12, q12", "q4, q4")) \
46     __ASM_EMIT("vabs.f32    " SEL("q13, q13", "q5, q5")) \
47     __ASM_EMIT("vabs.f32    " SEL("q14, q14", "q6, q6")) \
48     __ASM_EMIT("vabs.f32    " SEL("q15, q15", "q7, q7")) \
49     __ASM_EMIT(OP ".f32     q0, q0, q8") \
50     __ASM_EMIT(OP ".f32     q1, q1, q9") \
51     __ASM_EMIT(OP ".f32     q2, q2, q10") \
52     __ASM_EMIT(OP ".f32     q3, q3, q11") \
53     __ASM_EMIT(OP ".f32     q4, q4, q12") \
54     __ASM_EMIT(OP ".f32     q5, q5, q13") \
55     __ASM_EMIT(OP ".f32     q6, q6, q14") \
56     __ASM_EMIT(OP ".f32     q7, q7, q15") \
57     __ASM_EMIT("subs        %[count], $32") \
58     __ASM_EMIT("vstm        %[" DST "]!, {q0-q7}") \
59     __ASM_EMIT("add         %[" SRC "], $0x80") \
60     __ASM_EMIT("bhs         1b") \
61     /* 16x block */ \
62     __ASM_EMIT("2:") \
63     __ASM_EMIT("adds        %[count], $16") /* 32 - 16 */ \
64     __ASM_EMIT("blt         4f") \
65     __ASM_EMIT("vldm        %[" SEL(SRC, DST) "], {q8-q11}") \
66     __ASM_EMIT("vldm        %[" SEL(DST, SRC) "], {q0-q3}") \
67     __ASM_EMIT("vabs.f32    " SEL("q8, q8", "q0, q0")) \
68     __ASM_EMIT("vabs.f32    " SEL("q9, q9", "q1, q1")) \
69     __ASM_EMIT("vabs.f32    " SEL("q10, q10", "q2, q2")) \
70     __ASM_EMIT("vabs.f32    " SEL("q11, q11", "q3, q3")) \
71     __ASM_EMIT(OP ".f32     q0, q0, q8") \
72     __ASM_EMIT(OP ".f32     q1, q1, q9") \
73     __ASM_EMIT(OP ".f32     q2, q2, q10") \
74     __ASM_EMIT(OP ".f32     q3, q3, q11") \
75     __ASM_EMIT("sub         %[count], $16") \
76     __ASM_EMIT("vstm        %[" DST "]!, {q0-q3}") \
77     __ASM_EMIT("add         %[" SRC "], $0x40") \
78     /* 8x block */ \
79     __ASM_EMIT("4:") \
80     __ASM_EMIT("adds        %[count], $8") /* 16 - 8 */ \
81     __ASM_EMIT("blt         6f") \
82     __ASM_EMIT("vldm        %[" SEL(SRC, DST) "], {q8-q9}") \
83     __ASM_EMIT("vldm        %[" SEL(DST, SRC) "], {q0-q1}") \
84     __ASM_EMIT("vabs.f32    " SEL("q8, q8", "q0, q0")) \
85     __ASM_EMIT("vabs.f32    " SEL("q9, q9", "q1, q1")) \
86     __ASM_EMIT(OP ".f32     q0, q0, q8") \
87     __ASM_EMIT(OP ".f32     q1, q1, q9") \
88     __ASM_EMIT("sub         %[count], $8") \
89     __ASM_EMIT("vstm        %[" DST "]!, {q0-q1}") \
90     __ASM_EMIT("add         %[" SRC "], $0x20") \
91     /* 4x block */ \
92     __ASM_EMIT("6:") \
93     __ASM_EMIT("adds        %[count], $4") /* 8 - 4 */ \
94     __ASM_EMIT("blt         8f") \
95     __ASM_EMIT("vldm        %[" SEL(SRC, DST) "], {q8}") \
96     __ASM_EMIT("vldm        %[" SEL(DST, SRC) "], {q0}") \
97     __ASM_EMIT("vabs.f32    " SEL("q8, q8", "q0, q0")) \
98     __ASM_EMIT(OP ".f32     q0, q0, q8") \
99     __ASM_EMIT("sub         %[count], $4") \
100     __ASM_EMIT("vstm        %[" DST "]!, {q0}") \
101     __ASM_EMIT("add         %[" SRC "], $0x10") \
102     /* 1x block */ \
103     __ASM_EMIT("8:") \
104     __ASM_EMIT("adds        %[count], $3") /* 4 - 3 */ \
105     __ASM_EMIT("blt         10f") \
106     __ASM_EMIT("9:") \
107     __ASM_EMIT("vld1.32     {d16[], d17[]}, [%[" SEL(SRC, DST) "]]") \
108     __ASM_EMIT("vld1.32     {d0[], d1[]}, [%[" SEL(DST, SRC) "]]") \
109     __ASM_EMIT("vabs.f32    " SEL("q8, q8", "q0, q0")) \
110     __ASM_EMIT(OP ".f32     q0, q0, q8") \
111     __ASM_EMIT("subs        %[count], $1") \
112     __ASM_EMIT("vst1.32     {d0[0]}, [%[" DST "]]!") \
113     __ASM_EMIT("add         %[" SRC "], $0x04") \
114     __ASM_EMIT("bge         9b") \
115     __ASM_EMIT("10:")
116 
abs_add2(float * dst,const float * src,size_t count)117     void abs_add2(float *dst, const float *src, size_t count)
118     {
119         ARCH_ARM_ASM
120         (
121             ABS_VV2_CORE("dst", "src", "vadd", OP_DSEL)
122             : [dst] "+r" (dst), [src] "+r" (src),
123               [count] "+r" (count)
124             :
125             : "cc", "memory",
126               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
127               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
128         );
129     }
130 
abs_sub2(float * dst,const float * src,size_t count)131     void abs_sub2(float *dst, const float *src, size_t count)
132     {
133         ARCH_ARM_ASM
134         (
135             ABS_VV2_CORE("dst", "src", "vsub", OP_DSEL)
136             : [dst] "+r" (dst), [src] "+r" (src),
137               [count] "+r" (count)
138             :
139             : "cc", "memory",
140               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
141               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
142         );
143     }
144 
abs_rsub2(float * dst,const float * src,size_t count)145     void abs_rsub2(float *dst, const float *src, size_t count)
146     {
147         ARCH_ARM_ASM
148         (
149             ABS_VV2_CORE("dst", "src", "vsub", OP_RSEL)
150             : [dst] "+r" (dst), [src] "+r" (src),
151               [count] "+r" (count)
152             :
153             : "cc", "memory",
154               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
155               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
156         );
157     }
158 
abs_mul2(float * dst,const float * src,size_t count)159     void abs_mul2(float *dst, const float *src, size_t count)
160     {
161         ARCH_ARM_ASM
162         (
163             ABS_VV2_CORE("dst", "src", "vmul", OP_DSEL)
164             : [dst] "+r" (dst), [src] "+r" (src),
165               [count] "+r" (count)
166             :
167             : "cc", "memory",
168               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
169               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
170         );
171     }
172 
173 #undef ABS_VV2_CORE
174 
175 #define ABS_DIV2_CORE(DST, SRC, SEL)   \
176     __ASM_EMIT("subs            %[count], $16") \
177     __ASM_EMIT("blo             2f") \
178     /* 16x blocks */ \
179     __ASM_EMIT("1:") \
180     __ASM_EMIT("vldm            %[" SEL(SRC, DST) "], {q0-q3}") \
181     __ASM_EMIT("vldm            %[" SEL(DST, SRC) "], {q4-q7}") \
182     __ASM_EMIT("vabs.f32    " SEL("q0, q0", "q4, q4")) \
183     __ASM_EMIT("vabs.f32    " SEL("q1, q1", "q5, q5")) \
184     __ASM_EMIT("vabs.f32    " SEL("q2, q2", "q6, q6")) \
185     __ASM_EMIT("vabs.f32    " SEL("q3, q3", "q7, q7")) \
186     __ASM_EMIT("vrecpe.f32      q8, q0")                    /* q8 = s2 */ \
187     __ASM_EMIT("vrecpe.f32      q9, q1") \
188     __ASM_EMIT("vrecpe.f32      q10, q2") \
189     __ASM_EMIT("vrecpe.f32      q11, q3") \
190     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2) */ \
191     __ASM_EMIT("vrecps.f32      q13, q9, q1") \
192     __ASM_EMIT("vrecps.f32      q14, q10, q2") \
193     __ASM_EMIT("vrecps.f32      q15, q11, q3") \
194     __ASM_EMIT("vmul.f32        q8, q12, q8")               /* q8 = s2' = s2 * (2 - R*s2) */ \
195     __ASM_EMIT("vmul.f32        q9, q13, q9") \
196     __ASM_EMIT("vmul.f32        q10, q14, q10") \
197     __ASM_EMIT("vmul.f32        q11, q15, q11") \
198     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2') */ \
199     __ASM_EMIT("vrecps.f32      q13, q9, q1") \
200     __ASM_EMIT("vrecps.f32      q14, q10, q2") \
201     __ASM_EMIT("vrecps.f32      q15, q11, q3") \
202     __ASM_EMIT("vmul.f32        q0, q12, q8")               /* q0 = s2" = s2' * (2 - R*s2) = 1/s2 */  \
203     __ASM_EMIT("vmul.f32        q1, q13, q9") \
204     __ASM_EMIT("vmul.f32        q2, q14, q10") \
205     __ASM_EMIT("vmul.f32        q3, q15, q11") \
206     __ASM_EMIT("vmul.f32        q0, q0, q4")                /* s1 / s2 */ \
207     __ASM_EMIT("vmul.f32        q1, q1, q5") \
208     __ASM_EMIT("vmul.f32        q2, q2, q6") \
209     __ASM_EMIT("vmul.f32        q3, q3, q7") \
210     __ASM_EMIT("vstm            %[" DST "]!, {q0-q3}") \
211     __ASM_EMIT("subs            %[count], $16") \
212     __ASM_EMIT("add             %[" SRC "], $0x40") \
213     __ASM_EMIT("bhs             1b") \
214     /* 8x block */ \
215     __ASM_EMIT("2:") \
216     __ASM_EMIT("adds            %[count], $8") \
217     __ASM_EMIT("blt             4f") \
218     __ASM_EMIT("vldm            %[" SEL(SRC, DST) "], {q0-q1}") \
219     __ASM_EMIT("vldm            %[" SEL(DST, SRC) "], {q4-q5}") \
220     __ASM_EMIT("vabs.f32    " SEL("q0, q0", "q4, q4")) \
221     __ASM_EMIT("vabs.f32    " SEL("q1, q1", "q5, q5")) \
222     __ASM_EMIT("vrecpe.f32      q8, q0")                    /* q8 = s2 */ \
223     __ASM_EMIT("vrecpe.f32      q9, q1") \
224     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2) */ \
225     __ASM_EMIT("vrecps.f32      q13, q9, q1") \
226     __ASM_EMIT("vmul.f32        q8, q12, q8")               /* q8 = s2' = s2 * (2 - R*s2) */ \
227     __ASM_EMIT("vmul.f32        q9, q13, q9") \
228     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2') */ \
229     __ASM_EMIT("vrecps.f32      q13, q9, q1") \
230     __ASM_EMIT("vmul.f32        q0, q12, q8")               /* q0 = s2" = s2' * (2 - R*s2) = 1/s2 */  \
231     __ASM_EMIT("vmul.f32        q1, q13, q9") \
232     __ASM_EMIT("vmul.f32        q0, q0, q4")                /* s1 / s2 */ \
233     __ASM_EMIT("vmul.f32        q1, q1, q5") \
234     __ASM_EMIT("sub             %[count], $8") \
235     __ASM_EMIT("vstm            %[" DST "]!, {q0-q1}") \
236     __ASM_EMIT("add             %[" SRC "], $0x20") \
237     /* 4x blocks */ \
238     __ASM_EMIT("4:") \
239     __ASM_EMIT("adds            %[count], $4") \
240     __ASM_EMIT("blt             6f") \
241     __ASM_EMIT("vldm            %[" SEL(SRC, DST) "], {q0}") \
242     __ASM_EMIT("vldm            %[" SEL(DST, SRC) "], {q4}") \
243     __ASM_EMIT("vabs.f32    " SEL("q0, q0", "q4, q4")) \
244     __ASM_EMIT("vrecpe.f32      q8, q0")                    /* q8 = s2 */ \
245     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2) */ \
246     __ASM_EMIT("vmul.f32        q8, q12, q8")               /* q8 = s2' = s2 * (2 - R*s2) */ \
247     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2') */ \
248     __ASM_EMIT("vmul.f32        q0, q12, q8")               /* q0 = s2" = s2' * (2 - R*s2) = 1/s2 */  \
249     __ASM_EMIT("vmul.f32        q0, q0, q4")                /* s1 / s2 */ \
250     __ASM_EMIT("sub             %[count], $4") \
251     __ASM_EMIT("vstm            %[" DST "]!, {q0}") \
252     __ASM_EMIT("add             %[" SRC "], $0x10") \
253     /* 1x blocks */ \
254     __ASM_EMIT("6:") \
255     __ASM_EMIT("adds            %[count], $3") \
256     __ASM_EMIT("blt             8f") \
257     __ASM_EMIT("7:") \
258     __ASM_EMIT("vld1.32         {d0[], d1[]}, [%[" SEL(SRC, DST) "]]") \
259     __ASM_EMIT("vld1.32         {d8[], d9[]}, [%[" SEL(DST, SRC) "]]") \
260     __ASM_EMIT("vabs.f32    " SEL("q0, q0", "q4, q4")) \
261     __ASM_EMIT("vrecpe.f32      q8, q0")                    /* q8 = s2 */ \
262     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2) */ \
263     __ASM_EMIT("vmul.f32        q8, q12, q8")               /* q8 = s2' = s2 * (2 - R*s2) */ \
264     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2') */ \
265     __ASM_EMIT("vmul.f32        q0, q12, q8")               /* q0 = s2" = s2' * (2 - R*s2) = 1/s2 */  \
266     __ASM_EMIT("vmul.f32        q0, q0, q4")                /* s1 / s2 */ \
267     __ASM_EMIT("subs            %[count], $1") \
268     __ASM_EMIT("vst1.32         {d0[0]}, [%[" DST "]]!") \
269     __ASM_EMIT("add             %[" SRC "], $0x04") \
270     __ASM_EMIT("bge             7b") \
271     __ASM_EMIT("8:")
272 
abs_div2(float * dst,const float * src,size_t count)273     void abs_div2(float *dst, const float *src, size_t count)
274     {
275         ARCH_ARM_ASM
276         (
277             ABS_DIV2_CORE("dst", "src", OP_DSEL)
278             : [dst] "+r" (dst), [src] "+r" (src),
279               [count] "+r" (count)
280             :
281             : "cc", "memory",
282               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
283               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
284         );
285     }
286 
abs_rdiv2(float * dst,const float * src,size_t count)287     void abs_rdiv2(float *dst, const float *src, size_t count)
288     {
289         ARCH_ARM_ASM
290         (
291             ABS_DIV2_CORE("dst", "src", OP_RSEL)
292             : [dst] "+r" (dst), [src] "+r" (src),
293               [count] "+r" (count)
294             :
295             : "cc", "memory",
296               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
297               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
298         );
299     }
300 
301 #undef ABS_DIV2_CORE
302 
303 #define ABS_VV3_CORE(DST, SRC1, SRC2, OP, SEL) \
304     __ASM_EMIT("subs        %[count], $32") \
305     __ASM_EMIT("blo         2f") \
306     /* 32x blocks */ \
307     __ASM_EMIT("1:") \
308     __ASM_EMIT("vldm        %[" SRC1 "]!, {q0-q7}") \
309     __ASM_EMIT("vldm        %[" SRC2 "]!, {q8-q15}") \
310     __ASM_EMIT("vabs.f32    q8, q8") \
311     __ASM_EMIT("vabs.f32    q9, q9") \
312     __ASM_EMIT("vabs.f32    q10, q10") \
313     __ASM_EMIT("vabs.f32    q11, q11") \
314     __ASM_EMIT("vabs.f32    q12, q12") \
315     __ASM_EMIT("vabs.f32    q13, q13") \
316     __ASM_EMIT("vabs.f32    q14, q14") \
317     __ASM_EMIT("vabs.f32    q15, q15") \
318     __ASM_EMIT(OP ".f32     q0, "  SEL("q0, q8", "q8, q0")) \
319     __ASM_EMIT(OP ".f32     q1, "  SEL("q1, q9", "q9, q1")) \
320     __ASM_EMIT(OP ".f32     q2, "  SEL("q2, q10", "q10, q2")) \
321     __ASM_EMIT(OP ".f32     q3, "  SEL("q3, q11", "q11, q3")) \
322     __ASM_EMIT(OP ".f32     q4, "  SEL("q4, q12", "q12, q4")) \
323     __ASM_EMIT(OP ".f32     q5, "  SEL("q5, q13", "q13, q5")) \
324     __ASM_EMIT(OP ".f32     q6, "  SEL("q6, q14", "q14, q6")) \
325     __ASM_EMIT(OP ".f32     q7, "  SEL("q7, q15", "q15, q7")) \
326     __ASM_EMIT("subs        %[count], $32") \
327     __ASM_EMIT("vstm        %[" DST "]!, {q0-q7}") \
328     __ASM_EMIT("bhs         1b") \
329     /* 16x block */ \
330     __ASM_EMIT("2:") \
331     __ASM_EMIT("adds        %[count], $16") /* 32 - 16 */ \
332     __ASM_EMIT("blt         4f") \
333     __ASM_EMIT("vldm        %[" SRC1 "]!, {q0-q3}") \
334     __ASM_EMIT("vldm        %[" SRC2 "]!, {q8-q11}") \
335     __ASM_EMIT("vabs.f32    q8, q8") \
336     __ASM_EMIT("vabs.f32    q9, q9") \
337     __ASM_EMIT("vabs.f32    q10, q10") \
338     __ASM_EMIT("vabs.f32    q11, q11") \
339     __ASM_EMIT(OP ".f32     q0, "  SEL("q0, q8", "q8, q0")) \
340     __ASM_EMIT(OP ".f32     q1, "  SEL("q1, q9", "q9, q1")) \
341     __ASM_EMIT(OP ".f32     q2, "  SEL("q2, q10", "q10, q2")) \
342     __ASM_EMIT(OP ".f32     q3, "  SEL("q3, q11", "q11, q3")) \
343     __ASM_EMIT("sub         %[count], $16") \
344     __ASM_EMIT("vstm        %[" DST "]!, {q0-q3}") \
345     /* 8x block */ \
346     __ASM_EMIT("4:") \
347     __ASM_EMIT("adds        %[count], $8") /* 16 - 8 */ \
348     __ASM_EMIT("blt         6f") \
349     __ASM_EMIT("vldm        %[" SRC1 "]!, {q0-q1}") \
350     __ASM_EMIT("vldm        %[" SRC2 "]!, {q8-q9}") \
351     __ASM_EMIT("vabs.f32    q8, q8") \
352     __ASM_EMIT("vabs.f32    q9, q9") \
353     __ASM_EMIT(OP ".f32     q0, "  SEL("q0, q8", "q8, q0")) \
354     __ASM_EMIT(OP ".f32     q1, "  SEL("q1, q9", "q9, q1")) \
355     __ASM_EMIT("sub         %[count], $8") \
356     __ASM_EMIT("vstm        %[" DST "]!, {q0-q1}") \
357     /* 4x block */ \
358     __ASM_EMIT("6:") \
359     __ASM_EMIT("adds        %[count], $4") /* 8 - 4 */ \
360     __ASM_EMIT("blt         8f") \
361     __ASM_EMIT("vldm        %[" SRC1 "]!, {q0}") \
362     __ASM_EMIT("vldm        %[" SRC2 "]!, {q8}") \
363     __ASM_EMIT("vabs.f32    q8, q8") \
364     __ASM_EMIT(OP ".f32     q0, "  SEL("q0, q8", "q8, q0")) \
365     __ASM_EMIT("sub         %[count], $4") \
366     __ASM_EMIT("vstm        %[" DST "]!, {q0}") \
367     /* 1x block */ \
368     __ASM_EMIT("8:") \
369     __ASM_EMIT("adds        %[count], $3") /* 4 - 3 */ \
370     __ASM_EMIT("blt         10f") \
371     __ASM_EMIT("9:") \
372     __ASM_EMIT("vld1.32     {d0[], d1[]}, [%[" SRC1 "]]!") \
373     __ASM_EMIT("vld1.32     {d16[], d17[]}, [%[" SRC2 "]]!") \
374     __ASM_EMIT("vabs.f32    q8, q8") \
375     __ASM_EMIT(OP ".f32     q0, "  SEL("q0, q8", "q8, q0")) \
376     __ASM_EMIT("subs        %[count], $1") \
377     __ASM_EMIT("vst1.32     {d0[0]}, [%[" DST "]]!") \
378     __ASM_EMIT("bge         9b") \
379     __ASM_EMIT("10:")
380 
abs_add3(float * dst,const float * src1,const float * src2,size_t count)381     void abs_add3(float *dst, const float *src1, const float *src2, size_t count)
382     {
383         ARCH_ARM_ASM
384         (
385             ABS_VV3_CORE("dst", "src1", "src2", "vadd", OP_DSEL)
386             : [dst] "+r" (dst), [src1] "+r" (src1), [src2] "+r" (src2),
387               [count] "+r" (count)
388             :
389             : "cc", "memory",
390               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
391               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
392         );
393     }
394 
abs_sub3(float * dst,const float * src1,const float * src2,size_t count)395     void abs_sub3(float *dst, const float *src1, const float *src2, size_t count)
396     {
397         ARCH_ARM_ASM
398         (
399             ABS_VV3_CORE("dst", "src1", "src2", "vsub", OP_DSEL)
400             : [dst] "+r" (dst), [src1] "+r" (src1), [src2] "+r" (src2),
401               [count] "+r" (count)
402             :
403             : "cc", "memory",
404               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
405               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
406         );
407     }
408 
abs_rsub3(float * dst,const float * src1,const float * src2,size_t count)409     void abs_rsub3(float *dst, const float *src1, const float *src2, size_t count)
410     {
411         ARCH_ARM_ASM
412         (
413             ABS_VV3_CORE("dst", "src1", "src2", "vsub", OP_RSEL)
414             : [dst] "+r" (dst), [src1] "+r" (src1), [src2] "+r" (src2),
415               [count] "+r" (count)
416             :
417             : "cc", "memory",
418               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
419               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
420         );
421     }
422 
abs_mul3(float * dst,const float * src1,const float * src2,size_t count)423     void abs_mul3(float *dst, const float *src1, const float *src2, size_t count)
424     {
425         ARCH_ARM_ASM
426         (
427             ABS_VV3_CORE("dst", "src1", "src2", "vmul", OP_DSEL)
428             : [dst] "+r" (dst), [src1] "+r" (src1), [src2] "+r" (src2),
429               [count] "+r" (count)
430             :
431             : "cc", "memory",
432               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
433               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
434         );
435     }
436 #undef ABS_VV3_CORE
437 
438 #define ABS_DIV3_CORE(DST, SRC1, SRC2, SEL)   \
439     __ASM_EMIT("subs            %[count], $16") \
440     __ASM_EMIT("blo             2f") \
441     /* 16x blocks */ \
442     __ASM_EMIT("1:") \
443     __ASM_EMIT("vldm            %[" SEL(SRC2, SRC1) "]!, {q0-q3}") \
444     __ASM_EMIT("vldm            %[" SEL(SRC1, SRC2) "]!, {q4-q7}") \
445     __ASM_EMIT("vabs.f32    " SEL("q0, q0", "q4, q4")) \
446     __ASM_EMIT("vabs.f32    " SEL("q1, q1", "q5, q5")) \
447     __ASM_EMIT("vabs.f32    " SEL("q2, q2", "q6, q6")) \
448     __ASM_EMIT("vabs.f32    " SEL("q3, q3", "q7, q7")) \
449     __ASM_EMIT("vrecpe.f32      q8, q0")                    /* q8 = s2 */ \
450     __ASM_EMIT("vrecpe.f32      q9, q1") \
451     __ASM_EMIT("vrecpe.f32      q10, q2") \
452     __ASM_EMIT("vrecpe.f32      q11, q3") \
453     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2) */ \
454     __ASM_EMIT("vrecps.f32      q13, q9, q1") \
455     __ASM_EMIT("vrecps.f32      q14, q10, q2") \
456     __ASM_EMIT("vrecps.f32      q15, q11, q3") \
457     __ASM_EMIT("vmul.f32        q8, q12, q8")               /* q8 = s2' = s2 * (2 - R*s2) */ \
458     __ASM_EMIT("vmul.f32        q9, q13, q9") \
459     __ASM_EMIT("vmul.f32        q10, q14, q10") \
460     __ASM_EMIT("vmul.f32        q11, q15, q11") \
461     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2') */ \
462     __ASM_EMIT("vrecps.f32      q13, q9, q1") \
463     __ASM_EMIT("vrecps.f32      q14, q10, q2") \
464     __ASM_EMIT("vrecps.f32      q15, q11, q3") \
465     __ASM_EMIT("vmul.f32        q0, q12, q8")               /* q0 = s2" = s2' * (2 - R*s2) = 1/s2 */  \
466     __ASM_EMIT("vmul.f32        q1, q13, q9") \
467     __ASM_EMIT("vmul.f32        q2, q14, q10") \
468     __ASM_EMIT("vmul.f32        q3, q15, q11") \
469     __ASM_EMIT("vmul.f32        q0, q0, q4")                /* s1 / s2 */ \
470     __ASM_EMIT("vmul.f32        q1, q1, q5") \
471     __ASM_EMIT("vmul.f32        q2, q2, q6") \
472     __ASM_EMIT("vmul.f32        q3, q3, q7") \
473     __ASM_EMIT("vstm            %[" DST "]!, {q0-q3}") \
474     __ASM_EMIT("subs            %[count], $16") \
475     __ASM_EMIT("bhs             1b") \
476     /* 8x block */ \
477     __ASM_EMIT("2:") \
478     __ASM_EMIT("adds            %[count], $8") \
479     __ASM_EMIT("blt             4f") \
480     __ASM_EMIT("vldm            %[" SEL(SRC2, SRC1) "]!, {q0-q1}") \
481     __ASM_EMIT("vldm            %[" SEL(SRC1, SRC2) "]!, {q4-q5}") \
482     __ASM_EMIT("vabs.f32    " SEL("q0, q0", "q4, q4")) \
483     __ASM_EMIT("vabs.f32    " SEL("q1, q1", "q5, q5")) \
484     __ASM_EMIT("vrecpe.f32      q8, q0")                    /* q8 = s2 */ \
485     __ASM_EMIT("vrecpe.f32      q9, q1") \
486     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2) */ \
487     __ASM_EMIT("vrecps.f32      q13, q9, q1") \
488     __ASM_EMIT("vmul.f32        q8, q12, q8")               /* q8 = s2' = s2 * (2 - R*s2) */ \
489     __ASM_EMIT("vmul.f32        q9, q13, q9") \
490     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2') */ \
491     __ASM_EMIT("vrecps.f32      q13, q9, q1") \
492     __ASM_EMIT("vmul.f32        q0, q12, q8")               /* q0 = s2" = s2' * (2 - R*s2) = 1/s2 */  \
493     __ASM_EMIT("vmul.f32        q1, q13, q9") \
494     __ASM_EMIT("vmul.f32        q0, q0, q4")                /* s1 / s2 */ \
495     __ASM_EMIT("vmul.f32        q1, q1, q5") \
496     __ASM_EMIT("sub             %[count], $8") \
497     __ASM_EMIT("vstm            %[" DST "]!, {q0-q1}") \
498     /* 4x blocks */ \
499     __ASM_EMIT("4:") \
500     __ASM_EMIT("adds            %[count], $4") \
501     __ASM_EMIT("blt             6f") \
502     __ASM_EMIT("vldm            %[" SEL(SRC2, SRC1) "]!, {q0}") \
503     __ASM_EMIT("vldm            %[" SEL(SRC1, SRC2) "]!, {q4}") \
504     __ASM_EMIT("vabs.f32    " SEL("q0, q0", "q4, q4")) \
505     __ASM_EMIT("vrecpe.f32      q8, q0")                    /* q8 = s2 */ \
506     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2) */ \
507     __ASM_EMIT("vmul.f32        q8, q12, q8")               /* q8 = s2' = s2 * (2 - R*s2) */ \
508     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2') */ \
509     __ASM_EMIT("vmul.f32        q0, q12, q8")               /* q0 = s2" = s2' * (2 - R*s2) = 1/s2 */  \
510     __ASM_EMIT("vmul.f32        q0, q0, q4")                /* s1 / s2 */ \
511     __ASM_EMIT("sub             %[count], $4") \
512     __ASM_EMIT("vstm            %[" DST "]!, {q0}") \
513     /* 1x blocks */ \
514     __ASM_EMIT("6:") \
515     __ASM_EMIT("adds            %[count], $3") \
516     __ASM_EMIT("blt             8f") \
517     __ASM_EMIT("7:") \
518     __ASM_EMIT("vld1.32         {d0[], d1[]}, [%[" SEL(SRC2, SRC1) "]]!") \
519     __ASM_EMIT("vld1.32         {d8[], d9[]}, [%[" SEL(SRC1, SRC2) "]]!") \
520     __ASM_EMIT("vabs.f32    " SEL("q0, q0", "q4, q4")) \
521     __ASM_EMIT("vrecpe.f32      q8, q0")                    /* q8 = s2 */ \
522     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2) */ \
523     __ASM_EMIT("vmul.f32        q8, q12, q8")               /* q8 = s2' = s2 * (2 - R*s2) */ \
524     __ASM_EMIT("vrecps.f32      q12, q8, q0")               /* q12 = (2 - R*s2') */ \
525     __ASM_EMIT("vmul.f32        q0, q12, q8")               /* q0 = s2" = s2' * (2 - R*s2) = 1/s2 */  \
526     __ASM_EMIT("vmul.f32        q0, q0, q4")                /* s1 / s2 */ \
527     __ASM_EMIT("subs            %[count], $1") \
528     __ASM_EMIT("vst1.32         {d0[0]}, [%[" DST "]]!") \
529     __ASM_EMIT("bge             7b") \
530     __ASM_EMIT("8:")
531 
abs_div3(float * dst,const float * src1,const float * src2,size_t count)532     void abs_div3(float *dst, const float *src1, const float *src2, size_t count)
533     {
534         ARCH_ARM_ASM
535         (
536             ABS_DIV3_CORE("dst", "src1", "src2", OP_DSEL)
537             : [dst] "+r" (dst), [src1] "+r" (src1), [src2] "+r" (src2),
538               [count] "+r" (count)
539             :
540             : "cc", "memory",
541               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
542               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
543         );
544     }
545 
abs_rdiv3(float * dst,const float * src1,const float * src2,size_t count)546     void abs_rdiv3(float *dst, const float *src1, const float *src2, size_t count)
547     {
548         ARCH_ARM_ASM
549         (
550             ABS_DIV3_CORE("dst", "src1", "src2", OP_RSEL)
551             : [dst] "+r" (dst), [src1] "+r" (src1), [src2] "+r" (src2),
552               [count] "+r" (count)
553             :
554             : "cc", "memory",
555               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7",
556               "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
557         );
558     }
559 
560 #undef ABS_DIV3_CORE
561 
abs1(float * dst,size_t count)562     void abs1(float *dst, size_t count)
563     {
564         ARCH_ARM_ASM
565         (
566             /* 32x block */
567             __ASM_EMIT("subs        %[count], $32")
568             __ASM_EMIT("blt         2f")
569             __ASM_EMIT("1:")
570             __ASM_EMIT("vldm        %[dst], {q0-q7}")
571             __ASM_EMIT("vabs.f32    q0, q0")
572             __ASM_EMIT("vabs.f32    q1, q1")
573             __ASM_EMIT("vabs.f32    q2, q2")
574             __ASM_EMIT("vabs.f32    q3, q3")
575             __ASM_EMIT("vabs.f32    q4, q4")
576             __ASM_EMIT("vabs.f32    q5, q5")
577             __ASM_EMIT("vabs.f32    q6, q6")
578             __ASM_EMIT("vabs.f32    q7, q7")
579             __ASM_EMIT("vstm        %[dst]!, {q0-q7}")
580             __ASM_EMIT("subs        %[count], %[count], $32")
581             __ASM_EMIT("bhs         1b")
582             /* 16x block */
583             __ASM_EMIT("2:")
584             __ASM_EMIT("adds        %[count], $16") // 32-16
585             __ASM_EMIT("blt         4f")
586             __ASM_EMIT("vldm        %[dst], {q0-q3}")
587             __ASM_EMIT("vabs.f32    q0, q0")
588             __ASM_EMIT("vabs.f32    q1, q1")
589             __ASM_EMIT("vabs.f32    q2, q2")
590             __ASM_EMIT("vabs.f32    q3, q3")
591             __ASM_EMIT("vstm        %[dst]!, {q0-q3}")
592             __ASM_EMIT("sub         %[count], %[count], $16")
593             /* 8x block */
594             __ASM_EMIT("4:")
595             __ASM_EMIT("adds        %[count], $8") // 16-8
596             __ASM_EMIT("blt         6f")
597             __ASM_EMIT("vldm        %[dst], {q0-q1}")
598             __ASM_EMIT("vabs.f32    q0, q0")
599             __ASM_EMIT("vabs.f32    q1, q1")
600             __ASM_EMIT("vstm        %[dst]!, {q0-q1}")
601             __ASM_EMIT("sub         %[count], $8")
602             /* 4x block */
603             __ASM_EMIT("6:")
604             __ASM_EMIT("adds        %[count], $4") // 8-4
605             __ASM_EMIT("blt         8f")
606             __ASM_EMIT("vldm        %[dst], {q0}")
607             __ASM_EMIT("vabs.f32    q0, q0")
608             __ASM_EMIT("vabs.f32    q1, q1")
609             __ASM_EMIT("vstm        %[dst]!, {q0}")
610             __ASM_EMIT("sub         %[count], $4")
611             /* 1x blocks */
612             __ASM_EMIT("8:")
613             __ASM_EMIT("adds        %[count], $3") // 4-1
614             __ASM_EMIT("blt         10f")
615             __ASM_EMIT("13:")
616             __ASM_EMIT("vld1.32     {d0[], d1[]}, [%[dst]]")
617             __ASM_EMIT("vabs.f32    q0, q0")
618             __ASM_EMIT("vst1.32     {d0[0]}, [%[dst]]!")
619             __ASM_EMIT("subs        %[count], $1")
620             __ASM_EMIT("bge         13b")
621 
622             /* End of copy */
623             __ASM_EMIT("10:")
624 
625             : [dst] "+r" (dst),
626               [count] "+r" (count)
627             :
628             : "cc", "memory",
629               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7"
630         );
631     }
632 
abs2(float * dst,const float * src,size_t count)633     void abs2(float *dst, const float *src, size_t count)
634     {
635         ARCH_ARM_ASM
636         (
637             /* 32x block */
638             __ASM_EMIT("subs        %[count], $32")
639             __ASM_EMIT("blt         2f")
640             __ASM_EMIT("1:")
641             __ASM_EMIT("vldm        %[src]!, {q0-q7}")
642             __ASM_EMIT("vabs.f32    q0, q0")
643             __ASM_EMIT("vabs.f32    q1, q1")
644             __ASM_EMIT("vabs.f32    q2, q2")
645             __ASM_EMIT("vabs.f32    q3, q3")
646             __ASM_EMIT("vabs.f32    q4, q4")
647             __ASM_EMIT("vabs.f32    q5, q5")
648             __ASM_EMIT("vabs.f32    q6, q6")
649             __ASM_EMIT("vabs.f32    q7, q7")
650             __ASM_EMIT("vstm        %[dst]!, {q0-q7}")
651             __ASM_EMIT("subs        %[count], %[count], $32")
652             __ASM_EMIT("bhs         1b")
653             /* 16x block */
654             __ASM_EMIT("2:")
655             __ASM_EMIT("adds        %[count], $16") // 32-16
656             __ASM_EMIT("blt         4f")
657             __ASM_EMIT("vldm        %[src]!, {q0-q3}")
658             __ASM_EMIT("vabs.f32    q0, q0")
659             __ASM_EMIT("vabs.f32    q1, q1")
660             __ASM_EMIT("vabs.f32    q2, q2")
661             __ASM_EMIT("vabs.f32    q3, q3")
662             __ASM_EMIT("vstm        %[dst]!, {q0-q3}")
663             __ASM_EMIT("sub         %[count], %[count], $16")
664             /* 8x block */
665             __ASM_EMIT("4:")
666             __ASM_EMIT("adds        %[count], $8") // 16-8
667             __ASM_EMIT("blt         6f")
668             __ASM_EMIT("vldm        %[src]!, {q0-q1}")
669             __ASM_EMIT("vabs.f32    q0, q0")
670             __ASM_EMIT("vabs.f32    q1, q1")
671             __ASM_EMIT("vstm        %[dst]!, {q0-q1}")
672             __ASM_EMIT("sub         %[count], $8")
673             /* 4x block */
674             __ASM_EMIT("6:")
675             __ASM_EMIT("adds        %[count], $4") // 8-4
676             __ASM_EMIT("blt         8f")
677             __ASM_EMIT("vldm        %[src]!, {q0}")
678             __ASM_EMIT("vabs.f32    q0, q0")
679             __ASM_EMIT("vabs.f32    q1, q1")
680             __ASM_EMIT("vstm        %[dst]!, {q0}")
681             __ASM_EMIT("sub         %[count], $4")
682             /* 1x blocks */
683             __ASM_EMIT("8:")
684             __ASM_EMIT("adds        %[count], $3") // 4-1
685             __ASM_EMIT("blt         10f")
686             __ASM_EMIT("13:")
687             __ASM_EMIT("vld1.32     {d0[], d1[]}, [%[src]]!")
688             __ASM_EMIT("vabs.f32    q0, q0")
689             __ASM_EMIT("vst1.32     {d0[0]}, [%[dst]]!")
690             __ASM_EMIT("subs        %[count], $1")
691             __ASM_EMIT("bge         13b")
692 
693             /* End of copy */
694             __ASM_EMIT("10:")
695 
696             : [dst] "+r" (dst), [src] "+r" (src),
697               [count] "+r" (count)
698             :
699             : "cc", "memory",
700               "q0", "q1", "q2", "q3" , "q4", "q5", "q6", "q7"
701         );
702     }
703 
704 }
705 
706 
707 #endif /* DSP_ARCH_ARM_NEON_D32_PMATH_ABS_VV_H_ */
708