d1b24cfc045dbf7378654cb9114368c2d7ac91e6
[ffmpeg.git] / libavcodec / arm / vc1dsp_neon.S
1 /*
2  * VC1 NEON optimisations
3  *
4  * Copyright (c) 2010 Rob Clark <rob@ti.com>
5  * Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
6  *
7  * This file is part of Libav.
8  *
9  * Libav is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * Libav is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with Libav; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23
24 #include "libavutil/arm/asm.S"
25 #include "neon.S"
26
27 @ Transpose rows into columns of a matrix of 16-bit elements. For 4x4, pass
28 @ double-word registers, for 8x4, pass quad-word registers.
29 .macro transpose16 r0, r1, r2, r3
30         @ At this point:
31         @   row[0]  r0
32         @   row[1]  r1
33         @   row[2]  r2
34         @   row[3]  r3
35
36         vtrn.16         \r0,  \r1         @ first and second row
37         vtrn.16         \r2,  \r3         @ third and fourth row
38         vtrn.32         \r0,  \r2         @ first and third row
39         vtrn.32         \r1,  \r3         @ second and fourth row
40
41         @ At this point, if registers are quad-word:
42         @   column[0]   d0
43         @   column[1]   d2
44         @   column[2]   d4
45         @   column[3]   d6
46         @   column[4]   d1
47         @   column[5]   d3
48         @   column[6]   d5
49         @   column[7]   d7
50
51         @ At this point, if registers are double-word:
52         @   column[0]   d0
53         @   column[1]   d1
54         @   column[2]   d2
55         @   column[3]   d3
56 .endm
57
58 @ ff_vc1_inv_trans_{4,8}x{4,8}_neon and overflow: The input values in the file
59 @ are supposed to be in a specific range as to allow for 16-bit math without
60 @ causing overflows, but sometimes the input values are just big enough to
61 @ barely cause overflow in vadd instructions like:
62 @
63 @   vadd.i16  q0, q8, q10
64 @   vshr.s16  q0, q0, #\rshift
65 @
66 @ To prevent these borderline cases from overflowing, we just need one more
67 @ bit of precision, which is accomplished by replacing the sequence above with:
68 @
69 @   vhadd.s16 q0, q8, q10
70 @   vshr.s16  q0, q0, #(\rshift -1)
71 @
72 @ This works because vhadd is a single instruction that adds, then shifts to
73 @ the right once, all before writing the result to the destination register.
74 @
75 @ Even with this workaround, there were still some files that caused overflows
76 @ in ff_vc1_inv_trans_8x8_neon. See the comments in ff_vc1_inv_trans_8x8_neon
77 @ for the additional workaround.
78
79 @ Takes 4 columns of 8 values each and operates on it. Modeled after the first
80 @ for loop in vc1_inv_trans_4x8_c.
81 @ Input columns: q0 q1 q2 q3
82 @ Output columns: q0 q1 q2 q3
83 @ Trashes: r12 q8 q9 q10 q11 q12 q13
84 .macro vc1_inv_trans_4x8_helper add rshift
85         @ Compute temp1, temp2 and setup scalar #17, #22, #10
86         vadd.i16        q12,   q0,  q2              @ temp1 = src[0] + src[2]
87         movw            r12,   #17
88         vsub.i16        q13,   q0,  q2              @ temp2 = src[0] - src[2]
89         movt            r12,   #22
90         vmov.32         d0[0], r12
91         movw            r12,   #10
92         vmov.16         d1[0], r12
93
94         vmov.i16        q8,  #\add                  @ t1 will accumulate here
95         vmov.i16        q9,  #\add                  @ t2 will accumulate here
96
97         vmul.i16        q10, q1,  d0[1]             @ t3 = 22 * (src[1])
98         vmul.i16        q11, q3,  d0[1]             @ t4 = 22 * (src[3])
99
100         vmla.i16        q8,  q12, d0[0]             @ t1 = 17 * (temp1) + 4
101         vmla.i16        q9,  q13, d0[0]             @ t2 = 17 * (temp2) + 4
102
103         vmla.i16        q10, q3,  d1[0]             @ t3 += 10 * src[3]
104         vmls.i16        q11, q1,  d1[0]             @ t4 -= 10 * src[1]
105
106         vhadd.s16       q0,  q8,  q10               @ dst[0] = (t1 + t3) >> 1
107         vhsub.s16       q3,  q8,  q10               @ dst[3] = (t1 - t3) >> 1
108         vhsub.s16       q1,  q9,  q11               @ dst[1] = (t2 - t4) >> 1
109         vhadd.s16       q2,  q9,  q11               @ dst[2] = (t2 + t4) >> 1
110
111         @ Halving add/sub above already did one shift
112         vshr.s16        q0,  q0,  #(\rshift - 1)    @ dst[0] >>= (rshift - 1)
113         vshr.s16        q3,  q3,  #(\rshift - 1)    @ dst[3] >>= (rshift - 1)
114         vshr.s16        q1,  q1,  #(\rshift - 1)    @ dst[1] >>= (rshift - 1)
115         vshr.s16        q2,  q2,  #(\rshift - 1)    @ dst[2] >>= (rshift - 1)
116 .endm
117
118 @ Takes 8 columns of 4 values each and operates on it. Modeled after the second
119 @ for loop in vc1_inv_trans_4x8_c.
120 @ Input columns: d0 d2 d4 d6 d1 d3 d5 d7
121 @ Output columns: d16 d17 d18 d19 d21 d20 d23 d22
122 @ Trashes all NEON registers (and r12) except for: q4 q5 q6 q7
123 .macro vc1_inv_trans_8x4_helper add add1beforeshift rshift
124         @ At this point:
125         @   src[0]      d0 overwritten later
126         @   src[8]      d2
127         @   src[16]     d4 overwritten later
128         @   src[24]     d6
129         @   src[32]     d1 overwritten later
130         @   src[40]     d3
131         @   src[48]     d5 overwritten later
132         @   src[56]     d7
133
134         movw            r12,   #12
135         vmov.i16        q14,   #\add            @ t1|t2 will accumulate here
136         movt            r12,   #6
137
138         vadd.i16        d20,   d0,  d1          @ temp1 = src[0] + src[32]
139         vsub.i16        d21,   d0,  d1          @ temp2 = src[0] - src[32]
140         vmov.i32        d0[0], r12              @ 16-bit: d0[0] = #12, d0[1] = #6
141
142         vshl.i16        q15,   q2,  #4          @ t3|t4 = 16 * (src[16]|src[48])
143         vswp            d4,    d5               @ q2 = src[48]|src[16]
144         vmla.i16        q14,   q10, d0[0]       @ t1|t2 = 12 * (temp1|temp2) + 64
145         movw            r12,   #15
146         movt            r12,   #9
147         vmov.i32        d0[1], r12              @ 16-bit: d0[2] = #15, d0[3] = #9
148         vneg.s16        d31,   d31              @ t4 = -t4
149         vmla.i16        q15,   q2,  d0[1]       @ t3|t4 += 6 * (src[48]|src[16])
150
151         @ At this point:
152         @   d0[2]   #15
153         @   d0[3]   #9
154         @   q1      src[8]|src[40]
155         @   q3      src[24]|src[56]
156         @   q14     old t1|t2
157         @   q15     old t3|t4
158
159         vshl.i16        q8,  q1,  #4            @ t1|t2 = 16 * (src[8]|src[40])
160         vswp            d2,  d3                 @ q1 = src[40]|src[8]
161         vshl.i16        q12, q3,  #4            @ temp3a|temp4a = 16 * src[24]|src[56]
162         vswp            d6,  d7                 @ q3 = src[56]|src[24]
163         vshl.i16        q13, q1,  #2            @ temp3b|temp4b = 4 * (src[40]|src[8])
164         vshl.i16        q2,  q3,  #2            @ temp1|temp2 = 4 * (src[56]|src[24])
165         vswp            d3,  d6                 @ q1 = src[40]|src[56], q3 = src[8]|src[24]
166         vsub.i16        q9,  q13, q12           @ t3|t4 = - (temp3a|temp4a) + (temp3b|temp4b)
167         vadd.i16        q8,  q8,  q2            @ t1|t2 += temp1|temp2
168         vmul.i16        q12, q3,  d0[3]         @ temp3|temp4 = 9 * src[8]|src[24]
169         vmla.i16        q8,  q1,  d0[3]         @ t1|t2 += 9 * (src[40]|src[56])
170         vswp            d6,  d7                 @ q3 = src[24]|src[8]
171         vswp            d2,  d3                 @ q1 = src[56]|src[40]
172
173         vsub.i16        q11, q14, q15           @ t8|t7 = old t1|t2 - old t3|t4
174         vadd.i16        q10, q14, q15           @ t5|t6 = old t1|t2 + old t3|t4
175   .if \add1beforeshift
176         vmov.i16        q15, #1
177   .endif
178
179         vadd.i16        d18, d18, d24           @ t3 += temp3
180         vsub.i16        d19, d19, d25           @ t4 -= temp4
181
182         vswp            d22, d23                @ q11 = t7|t8
183
184         vneg.s16        d17, d17                @ t2 = -t2
185         vmla.i16        q9,  q1,  d0[2]         @ t3|t4 += 15 * src[56]|src[40]
186         vmla.i16        q8,  q3,  d0[2]         @ t1|t2 += 15 * src[24]|src[8]
187
188         @ At this point:
189         @   t1  d16
190         @   t2  d17
191         @   t3  d18
192         @   t4  d19
193         @   t5  d20
194         @   t6  d21
195         @   t7  d22
196         @   t8  d23
197         @   #1  q15
198
199   .if \add1beforeshift
200         vadd.i16        q3,  q15, q10           @ line[7,6] = t5|t6 + 1
201         vadd.i16        q2,  q15, q11           @ line[5,4] = t7|t8 + 1
202   .endif
203
204         @ Sometimes this overflows, so to get one additional bit of precision, use
205         @ a single instruction that both adds and shifts right (halving).
206         vhadd.s16       q1,  q9,  q11           @ line[2,3] = (t3|t4 + t7|t8) >> 1
207         vhadd.s16       q0,  q8,  q10           @ line[0,1] = (t1|t2 + t5|t6) >> 1
208   .if \add1beforeshift
209         vhsub.s16       q2,  q2,  q9            @ line[5,4] = (t7|t8 - t3|t4 + 1) >> 1
210         vhsub.s16       q3,  q3,  q8            @ line[7,6] = (t5|t6 - t1|t2 + 1) >> 1
211   .else
212         vhsub.s16       q2,  q11, q9            @ line[5,4] = (t7|t8 - t3|t4) >> 1
213         vhsub.s16       q3,  q10, q8            @ line[7,6] = (t5|t6 - t1|t2) >> 1
214   .endif
215
216         vshr.s16        q9,  q1,  #(\rshift - 1)    @ one shift is already done by vhadd/vhsub above
217         vshr.s16        q8,  q0,  #(\rshift - 1)
218         vshr.s16        q10, q2,  #(\rshift - 1)
219         vshr.s16        q11, q3,  #(\rshift - 1)
220
221         @ At this point:
222         @   dst[0]   d16
223         @   dst[1]   d17
224         @   dst[2]   d18
225         @   dst[3]   d19
226         @   dst[4]   d21
227         @   dst[5]   d20
228         @   dst[6]   d23
229         @   dst[7]   d22
230 .endm
231
232 @ This is modeled after the first and second for loop in vc1_inv_trans_8x8_c.
233 @ Input columns:  q8, q9, q10, q11, q12, q13, q14, q15
234 @ Output columns: q8, q9, q10, q11, q12, q13, q14, q15
235 @ Trashes all NEON registers (and r12) except for: q4 q5 q6 q7
236 .macro vc1_inv_trans_8x8_helper add add1beforeshift rshift
237         @ This actually computes half of t1, t2, t3, t4, as explained below
238         @ near `tNhalf`.
239         vmov.i16        q0,    #(6 / 2)         @ q0 = #6/2
240         vshl.i16        q1,    q10, #3          @ t3 = 16/2 * src[16]
241         vshl.i16        q3,    q14, #3          @ temp4 = 16/2 * src[48]
242         vmul.i16        q2,    q10, q0          @ t4 = 6/2 * src[16]
243         vmla.i16        q1,    q14, q0          @ t3 += 6/2 * src[48]
244         @ unused: q0, q10, q14
245         vmov.i16        q0,    #(12 / 2)        @ q0 = #12/2
246         vadd.i16        q10,   q8,  q12         @ temp1 = src[0] + src[32]
247         vsub.i16        q14,   q8,  q12         @ temp2 = src[0] - src[32]
248         @ unused: q8, q12
249         vmov.i16        q8,    #(\add / 2)      @ t1 will accumulate here
250         vmov.i16        q12,   #(\add / 2)      @ t2 will accumulate here
251         movw            r12,   #15
252         vsub.i16        q2,    q2,  q3          @ t4 = 6/2 * src[16] - 16/2 * src[48]
253         movt            r12,   #9
254         @ unused: q3
255         vmla.i16        q8,    q10, q0          @ t1 = 12/2 * temp1 + add
256         vmla.i16        q12,   q14, q0          @ t2 = 12/2 * temp2 + add
257         vmov.i32        d0[0], r12
258         @ unused: q3, q10, q14
259
260         @ At this point:
261         @   q0          d0=#15|#9
262         @   q1  old t3
263         @   q2  old t4
264         @   q3
265         @   q8  old t1
266         @   q9          src[8]
267         @   q10
268         @   q11         src[24]
269         @   q12 old t2
270         @   q13         src[40]
271         @   q14
272         @   q15         src[56]
273
274         @ unused: q3, q10, q14
275         movw            r12,   #16
276         vshl.i16        q3,    q9,  #4          @ t1 = 16 * src[8]
277         movt            r12,   #4
278         vshl.i16        q10,   q9,  #2          @ t4 = 4 * src[8]
279         vmov.i32        d1[0], r12
280         vmul.i16        q14,   q9,  d0[0]       @ t2 = 15 * src[8]
281         vmul.i16        q9,    q9,  d0[1]       @ t3 = 9 * src[8]
282         @ unused: none
283         vmla.i16        q3,    q11, d0[0]       @ t1 += 15 * src[24]
284         vmls.i16        q10,   q11, d0[1]       @ t4 -= 9 * src[24]
285         vmls.i16        q14,   q11, d1[1]       @ t2 -= 4 * src[24]
286         vmls.i16        q9,    q11, d1[0]       @ t3 -= 16 * src[24]
287         @ unused: q11
288         vmla.i16        q3,    q13, d0[1]       @ t1 += 9 * src[40]
289         vmla.i16        q10,   q13, d0[0]       @ t4 += 15 * src[40]
290         vmls.i16        q14,   q13, d1[0]       @ t2 -= 16 * src[40]
291         vmla.i16        q9,    q13, d1[1]       @ t3 += 4 * src[40]
292         @ unused: q11, q13
293
294         @ Compute t5, t6, t7, t8 from old t1, t2, t3, t4. Actually, it computes
295         @ half of t5, t6, t7, t8 since t1, t2, t3, t4 are halved.
296         vadd.i16        q11,   q8,  q1          @ t5 = t1 + t3
297         vsub.i16        q1,    q8,  q1          @ t8 = t1 - t3
298         vadd.i16        q13,   q12, q2          @ t6 = t2 + t4
299         vsub.i16        q2,    q12, q2          @ t7 = t2 - t4
300         @ unused: q8, q12
301
302   .if \add1beforeshift
303         vmov.i16        q12,   #1
304   .endif
305
306         @ unused: q8
307         vmla.i16        q3,    q15, d1[1]       @ t1 += 4 * src[56]
308         vmls.i16        q14,   q15, d0[1]       @ t2 -= 9 * src[56]
309         vmla.i16        q9,    q15, d0[0]       @ t3 += 15 * src[56]
310         vmls.i16        q10,   q15, d1[0]       @ t4 -= 16 * src[56]
311         @ unused: q0, q8, q15
312
313         @ At this point:
314         @   t1      q3
315         @   t2      q14
316         @   t3      q9
317         @   t4      q10
318         @   t5half  q11
319         @   t6half  q13
320         @   t7half  q2
321         @   t8half  q1
322         @   #1      q12
323         @
324         @ tNhalf is half of the value of tN (as described in vc1_inv_trans_8x8_c).
325         @ This is done because sometimes files have input that causes tN + tM to
326         @ overflow. To avoid this overflow, we compute tNhalf, then compute
327         @ tNhalf + tM (which doesn't overflow), and then we use vhadd to compute
328         @ (tNhalf + (tNhalf + tM)) >> 1 which does not overflow because it is
329         @ one instruction.
330
331         @ For each pair of tN and tM, do:
332         @   lineA = t5half + t1
333         @   if add1beforeshift:  t1 -= 1
334         @   lineA = (t5half + lineA) >> 1
335         @   lineB = t5half - t1
336         @   lineB = (t5half + lineB) >> 1
337         @   lineA >>= rshift - 1
338         @   lineB >>= rshift - 1
339
340         vadd.i16        q8,  q11, q3                @ q8 = t5half + t1
341   .if \add1beforeshift
342         vsub.i16        q3,  q3,  q12               @ q3 = t1 - 1
343   .endif
344
345         vadd.i16        q0,  q13, q14               @ q0  = t6half + t2
346   .if \add1beforeshift
347         vsub.i16        q14, q14, q12               @ q14 = t2 - 1
348   .endif
349
350         vadd.i16        q15, q2,  q9                @ q15 = t7half + t3
351   .if \add1beforeshift
352         vsub.i16        q9,  q9,  q12               @ q9  = t3 - 1
353   .endif
354         @ unused: none
355
356         vhadd.s16       q8,  q11, q8                @ q8  = (t5half + t5half + t1) >> 1
357         vsub.i16        q3,  q11, q3                @ q3  = t5half - t1 + 1
358
359         vhadd.s16       q0,  q13, q0                @ q0  = (t6half + t6half + t2) >> 1
360         vsub.i16        q14, q13, q14               @ q14 = t6half - t2 + 1
361
362         vhadd.s16       q15, q2,  q15               @ q15 = (t7half + t7half + t3) >> 1
363         vsub.i16        q9,  q2,  q9                @ q9  = t7half - t3 + 1
364
365         vhadd.s16       q3,  q11, q3                @ q3  = (t5half + t5half - t1 + 1) >> 1
366         @ unused: q11
367
368         vadd.i16        q11, q1,  q10               @ q11 = t8half + t4
369   .if \add1beforeshift
370         vsub.i16        q10, q10, q12               @ q10 = t4 - 1
371   .endif
372         @ unused: q12
373
374         vhadd.s16       q14, q13, q14               @ q14 = (t6half + t6half - t2 + 1) >> 1
375         @ unused: q12, q13
376         vhadd.s16       q13, q2,  q9                @ q9  = (t7half + t7half - t3 + 1) >> 1
377         @ unused: q12, q2, q9
378
379         vsub.i16        q10, q1,  q10               @ q10 = t8half - t4 + 1
380         vhadd.s16       q11, q1,  q11               @ q11 = (t8half + t8half + t4) >> 1
381
382         vshr.s16        q8,  q8,  #(\rshift - 1)    @ q8  = line[0]
383         vhadd.s16       q12, q1,  q10               @ q12 = (t8half + t8half - t4 + 1) >> 1
384         vshr.s16        q9,  q0,  #(\rshift - 1)    @ q9  = line[1]
385         vshr.s16        q10, q15, #(\rshift - 1)    @ q10 = line[2]
386         vshr.s16        q11, q11, #(\rshift - 1)    @ q11 = line[3]
387         vshr.s16        q12, q12, #(\rshift - 1)    @ q12 = line[4]
388         vshr.s16        q13, q13, #(\rshift - 1)    @ q13 = line[5]
389         vshr.s16        q14, q14, #(\rshift - 1)    @ q14 = line[6]
390         vshr.s16        q15, q3,  #(\rshift - 1)    @ q15 = line[7]
391 .endm
392
393 @ (int16_t *block [r0])
394 function ff_vc1_inv_trans_8x8_neon, export=1
395         vld1.64         {q8-q9},   [r0,:128]!
396         vld1.64         {q10-q11}, [r0,:128]!
397         vld1.64         {q12-q13}, [r0,:128]!
398         vld1.64         {q14-q15}, [r0,:128]
399         sub             r0, r0, #(16 * 2 * 3)   @ restore r0
400
401         @ At this point:
402         @   src[0]  q8
403         @   src[8]  q9
404         @   src[16] q10
405         @   src[24] q11
406         @   src[32] q12
407         @   src[40] q13
408         @   src[48] q14
409         @   src[56] q15
410
411         vc1_inv_trans_8x8_helper add=4 add1beforeshift=0 rshift=3
412
413         @ Transpose result matrix of 8x8
414         swap4           d17, d19, d21, d23, d24, d26, d28, d30
415         transpose16_4x4 q8,  q9,  q10, q11, q12, q13, q14, q15
416
417         vc1_inv_trans_8x8_helper add=64 add1beforeshift=1 rshift=7
418
419         vst1.64         {q8-q9},   [r0,:128]!
420         vst1.64         {q10-q11}, [r0,:128]!
421         vst1.64         {q12-q13}, [r0,:128]!
422         vst1.64         {q14-q15}, [r0,:128]
423
424         bx              lr
425 endfunc
426
427 @ (uint8_t *dest [r0], int linesize [r1], int16_t *block [r2])
428 function ff_vc1_inv_trans_8x4_neon, export=1
429         vld1.64         {q0-q1}, [r2,:128]!     @ load 8 * 4 * 2 = 64 bytes / 16 bytes per quad = 4 quad registers
430         vld1.64         {q2-q3}, [r2,:128]
431
432         transpose16     q0 q1 q2 q3             @ transpose rows to columns
433
434         @ At this point:
435         @   src[0]   d0
436         @   src[1]   d2
437         @   src[2]   d4
438         @   src[3]   d6
439         @   src[4]   d1
440         @   src[5]   d3
441         @   src[6]   d5
442         @   src[7]   d7
443
444         vc1_inv_trans_8x4_helper    add=4 add1beforeshift=0 rshift=3
445
446         @ Move output to more standardized registers
447         vmov        d0, d16
448         vmov        d2, d17
449         vmov        d4, d18
450         vmov        d6, d19
451         vmov        d1, d21
452         vmov        d3, d20
453         vmov        d5, d23
454         vmov        d7, d22
455
456         @ At this point:
457         @   dst[0]   d0
458         @   dst[1]   d2
459         @   dst[2]   d4
460         @   dst[3]   d6
461         @   dst[4]   d1
462         @   dst[5]   d3
463         @   dst[6]   d5
464         @   dst[7]   d7
465
466         transpose16     q0 q1 q2 q3   @ turn columns into rows
467
468         @ At this point:
469         @   row[0] q0
470         @   row[1] q1
471         @   row[2] q2
472         @   row[3] q3
473
474         vc1_inv_trans_4x8_helper    add=64 rshift=7
475
476         @ At this point:
477         @   line[0].l   d0
478         @   line[0].h   d1
479         @   line[1].l   d2
480         @   line[1].h   d3
481         @   line[2].l   d4
482         @   line[2].h   d5
483         @   line[3].l   d6
484         @   line[3].h   d7
485
486         @ unused registers: q12, q13, q14, q15
487
488         vld1.64         {d28}, [r0,:64], r1     @ read dest
489         vld1.64         {d29}, [r0,:64], r1
490         vld1.64         {d30}, [r0,:64], r1
491         vld1.64         {d31}, [r0,:64], r1
492         sub             r0,  r0,  r1, lsl #2    @ restore original r0 value
493
494         vaddw.u8        q0,  q0,  d28           @ line[0] += dest[0]
495         vaddw.u8        q1,  q1,  d29           @ line[1] += dest[1]
496         vaddw.u8        q2,  q2,  d30           @ line[2] += dest[2]
497         vaddw.u8        q3,  q3,  d31           @ line[3] += dest[3]
498
499         vqmovun.s16     d0,  q0                 @ line[0]
500         vqmovun.s16     d1,  q1                 @ line[1]
501         vqmovun.s16     d2,  q2                 @ line[2]
502         vqmovun.s16     d3,  q3                 @ line[3]
503
504         vst1.64         {d0},  [r0,:64], r1     @ write dest
505         vst1.64         {d1},  [r0,:64], r1
506         vst1.64         {d2},  [r0,:64], r1
507         vst1.64         {d3},  [r0,:64]
508
509         bx              lr
510 endfunc
511
512 @ (uint8_t *dest [r0], int linesize [r1], int16_t *block [r2])
513 function ff_vc1_inv_trans_4x8_neon, export=1
514         mov             r12, #(8 * 2)  @ 8 elements per line, each element 2 bytes
515         vld4.16         {d0[],  d2[],  d4[],  d6[]},  [r2,:64], r12     @ read each column into a q register
516         vld4.16         {d0[1], d2[1], d4[1], d6[1]}, [r2,:64], r12
517         vld4.16         {d0[2], d2[2], d4[2], d6[2]}, [r2,:64], r12
518         vld4.16         {d0[3], d2[3], d4[3], d6[3]}, [r2,:64], r12
519         vld4.16         {d1[],  d3[],  d5[],  d7[]},  [r2,:64], r12
520         vld4.16         {d1[1], d3[1], d5[1], d7[1]}, [r2,:64], r12
521         vld4.16         {d1[2], d3[2], d5[2], d7[2]}, [r2,:64], r12
522         vld4.16         {d1[3], d3[3], d5[3], d7[3]}, [r2,:64]
523
524         vc1_inv_trans_4x8_helper    add=4 rshift=3
525
526         @ At this point:
527         @   dst[0] = q0
528         @   dst[1] = q1
529         @   dst[2] = q2
530         @   dst[3] = q3
531
532         transpose16     q0 q1 q2 q3     @ Transpose rows (registers) into columns
533
534         vc1_inv_trans_8x4_helper    add=64 add1beforeshift=1 rshift=7
535
536         vld1.32         {d28[]},  [r0,:32], r1  @ read dest
537         vld1.32         {d28[1]}, [r0,:32], r1
538         vld1.32         {d29[]},  [r0,:32], r1
539         vld1.32         {d29[1]}, [r0,:32], r1
540
541         vld1.32         {d30[]},  [r0,:32], r1
542         vld1.32         {d30[0]}, [r0,:32], r1
543         vld1.32         {d31[]},  [r0,:32], r1
544         vld1.32         {d31[0]}, [r0,:32], r1
545         sub             r0,  r0,  r1, lsl #3    @ restore original r0 value
546
547         vaddw.u8        q8,  q8,  d28           @ line[0,1] += dest[0,1]
548         vaddw.u8        q9,  q9,  d29           @ line[2,3] += dest[2,3]
549         vaddw.u8        q10, q10, d30           @ line[5,4] += dest[5,4]
550         vaddw.u8        q11, q11, d31           @ line[7,6] += dest[7,6]
551
552         vqmovun.s16     d16, q8                 @ clip(line[0,1])
553         vqmovun.s16     d18, q9                 @ clip(line[2,3])
554         vqmovun.s16     d20, q10                @ clip(line[5,4])
555         vqmovun.s16     d22, q11                @ clip(line[7,6])
556
557         vst1.32         {d16[0]}, [r0,:32], r1  @ write dest
558         vst1.32         {d16[1]}, [r0,:32], r1
559         vst1.32         {d18[0]}, [r0,:32], r1
560         vst1.32         {d18[1]}, [r0,:32], r1
561
562         vst1.32         {d20[1]}, [r0,:32], r1
563         vst1.32         {d20[0]}, [r0,:32], r1
564         vst1.32         {d22[1]}, [r0,:32], r1
565         vst1.32         {d22[0]}, [r0,:32]
566
567         bx              lr
568 endfunc
569
570 @ Setup constants in registers which are used by vc1_inv_trans_4x4_helper
571 .macro vc1_inv_trans_4x4_helper_setup
572         vmov.i16        q13, #17
573         vmov.i16        q14, #22
574         vmov.i16        d30, #10                @ only need double-word, not quad-word
575 .endm
576
577 @ This is modeled after the first for loop in vc1_inv_trans_4x4_c.
578 .macro vc1_inv_trans_4x4_helper add rshift
579         vmov.i16        q2,  #\add              @ t1|t2 will accumulate here
580
581         vadd.i16        d16, d0,  d1            @ temp1 = src[0] + src[2]
582         vsub.i16        d17, d0,  d1            @ temp2 = src[0] - src[2]
583         vmul.i16        q3,  q14, q1            @ t3|t4 = 22 * (src[1]|src[3])
584         vmla.i16        q2,  q13, q8            @ t1|t2 = 17 * (temp1|temp2) + add
585         vmla.i16        d6,  d30, d3            @ t3 += 10 * src[3]
586         vmls.i16        d7,  d30, d2            @ t4 -= 10 * src[1]
587
588         vadd.i16        q0,  q2,  q3            @ dst[0,2] = (t1|t2 + t3|t4)
589         vsub.i16        q1,  q2,  q3            @ dst[3,1] = (t1|t2 - t3|t4)
590         vshr.s16        q0,  q0,  #\rshift      @ dst[0,2] >>= rshift
591         vshr.s16        q1,  q1,  #\rshift      @ dst[3,1] >>= rshift
592 .endm
593
594 @ (uint8_t *dest [r0], int linesize [r1], int16_t *block [r2])
595 function ff_vc1_inv_trans_4x4_neon, export=1
596         mov             r12, #(8 * 2)  @ 8 elements per line, each element 2 bytes
597         vld4.16         {d0[],  d1[],  d2[],  d3[]},  [r2,:64], r12     @ read each column into a register
598         vld4.16         {d0[1], d1[1], d2[1], d3[1]}, [r2,:64], r12
599         vld4.16         {d0[2], d1[2], d2[2], d3[2]}, [r2,:64], r12
600         vld4.16         {d0[3], d1[3], d2[3], d3[3]}, [r2,:64]
601
602         vswp            d1,  d2         @ so that we can later access column 1 and column 3 as a single q1 register
603
604         vc1_inv_trans_4x4_helper_setup
605
606         @ At this point:
607         @   src[0] = d0
608         @   src[1] = d2
609         @   src[2] = d1
610         @   src[3] = d3
611
612         vc1_inv_trans_4x4_helper add=4 rshift=3      @ compute t1, t2, t3, t4 and combine them into dst[0-3]
613
614         @ At this point:
615         @   dst[0] = d0
616         @   dst[1] = d3
617         @   dst[2] = d1
618         @   dst[3] = d2
619
620         transpose16     d0 d3 d1 d2     @ Transpose rows (registers) into columns
621
622         @ At this point:
623         @   src[0]  = d0
624         @   src[8]  = d3
625         @   src[16] = d1
626         @   src[24] = d2
627
628         vswp            d2,  d3         @ so that we can later access column 1 and column 3 in order as a single q1 register
629
630         @ At this point:
631         @   src[0]  = d0
632         @   src[8]  = d2
633         @   src[16] = d1
634         @   src[24] = d3
635
636         vc1_inv_trans_4x4_helper add=64 rshift=7              @ compute t1, t2, t3, t4 and combine them into dst[0-3]
637
638         @ At this point:
639         @   line[0] = d0
640         @   line[1] = d3
641         @   line[2] = d1
642         @   line[3] = d2
643
644         vld1.32         {d18[]},  [r0,:32], r1  @ read dest
645         vld1.32         {d19[]},  [r0,:32], r1
646         vld1.32         {d18[1]}, [r0,:32], r1
647         vld1.32         {d19[0]}, [r0,:32], r1
648         sub             r0,  r0,  r1, lsl #2    @ restore original r0 value
649
650         vaddw.u8        q0,  q0,  d18           @ line[0,2] += dest[0,2]
651         vaddw.u8        q1,  q1,  d19           @ line[3,1] += dest[3,1]
652
653         vqmovun.s16     d0,  q0                 @ clip(line[0,2])
654         vqmovun.s16     d1,  q1                 @ clip(line[3,1])
655
656         vst1.32         {d0[0]},  [r0,:32], r1  @ write dest
657         vst1.32         {d1[1]},  [r0,:32], r1
658         vst1.32         {d0[1]},  [r0,:32], r1
659         vst1.32         {d1[0]},  [r0,:32]
660
661         bx              lr
662 endfunc
663
664 @ The absolute value of multiplication constants from vc1_mspel_filter and vc1_mspel_{ver,hor}_filter_16bits.
665 @ The sign is embedded in the code below that carries out the multiplication (mspel_filter{,.16}).
666 #define MSPEL_MODE_1_MUL_CONSTANTS  4 53 18 3
667 #define MSPEL_MODE_2_MUL_CONSTANTS  1 9  9  1
668 #define MSPEL_MODE_3_MUL_CONSTANTS  3 18 53 4
669
670 @ These constants are from reading the source code of vc1_mspel_mc and determining the value that
671 @ is added to `rnd` to result in the variable `r`, and the value of the variable `shift`.
672 #define MSPEL_MODES_11_ADDSHIFT_CONSTANTS   15 5
673 #define MSPEL_MODES_12_ADDSHIFT_CONSTANTS   3  3
674 #define MSPEL_MODES_13_ADDSHIFT_CONSTANTS   15 5
675 #define MSPEL_MODES_21_ADDSHIFT_CONSTANTS   MSPEL_MODES_12_ADDSHIFT_CONSTANTS
676 #define MSPEL_MODES_22_ADDSHIFT_CONSTANTS   0  1
677 #define MSPEL_MODES_23_ADDSHIFT_CONSTANTS   3  3
678 #define MSPEL_MODES_31_ADDSHIFT_CONSTANTS   MSPEL_MODES_13_ADDSHIFT_CONSTANTS
679 #define MSPEL_MODES_32_ADDSHIFT_CONSTANTS   MSPEL_MODES_23_ADDSHIFT_CONSTANTS
680 #define MSPEL_MODES_33_ADDSHIFT_CONSTANTS   15 5
681
682 @ The addition and shift constants from vc1_mspel_filter.
683 #define MSPEL_MODE_1_ADDSHIFT_CONSTANTS     32 6
684 #define MSPEL_MODE_2_ADDSHIFT_CONSTANTS     8  4
685 #define MSPEL_MODE_3_ADDSHIFT_CONSTANTS     32 6
686
687 @ Setup constants in registers for a subsequent use of mspel_filter{,.16}.
688 .macro mspel_constants typesize reg_a reg_b reg_c reg_d filter_a filter_b filter_c filter_d reg_add filter_add_register
689   @ Define double-word register aliases. Typesize should be i8 or i16.
690   ra .dn \reg_a\().\typesize
691   rb .dn \reg_b\().\typesize
692   rc .dn \reg_c\().\typesize
693   rd .dn \reg_d\().\typesize
694
695   @ Only set the register if the value is not 1 and unique
696   .if \filter_a != 1
697         vmov            ra,  #\filter_a              @ ra = filter_a
698   .endif
699         vmov            rb,  #\filter_b              @ rb = filter_b
700   .if \filter_b != \filter_c
701         vmov            rc,  #\filter_c              @ rc = filter_c
702   .endif
703   .if \filter_d != 1
704         vmov            rd,  #\filter_d              @ rd = filter_d
705   .endif
706   @ vdup to double the size of typesize
707   .ifc \typesize,i8
708         vdup.16         \reg_add,  \filter_add_register     @ reg_add = filter_add_register
709   .else
710         vdup.32         \reg_add,  \filter_add_register     @ reg_add = filter_add_register
711   .endif
712
713   .unreq ra
714   .unreq rb
715   .unreq rc
716   .unreq rd
717 .endm
718
719 @ After mspel_constants has been used, do the filtering.
720 .macro mspel_filter acc dest src0 src1 src2 src3 filter_a filter_b filter_c filter_d reg_a reg_b reg_c reg_d reg_add filter_shift narrow=1
721   .if \filter_a != 1
722         @ If filter_a != 1, then we need a move and subtract instruction
723         vmov            \acc,  \reg_add                     @ acc = reg_add
724         vmlsl.u8        \acc,  \reg_a,  \src0               @ acc -= filter_a * src[-stride]
725   .else
726         @ If filter_a is 1, then just subtract without an extra move
727         vsubw.u8        \acc,  \reg_add,  \src0             @ acc = reg_add - src[-stride]      @ since filter_a == 1
728   .endif
729         vmlal.u8        \acc,  \reg_b,  \src1               @ acc += filter_b * src[0]
730   .if \filter_b != \filter_c
731         vmlal.u8        \acc,  \reg_c,  \src2               @ acc += filter_c * src[stride]
732   .else
733         @ If filter_b is the same as filter_c, use the same reg_b register
734         vmlal.u8        \acc,  \reg_b,  \src2               @ acc += filter_c * src[stride]     @ where filter_c == filter_b
735   .endif
736   .if \filter_d != 1
737         @ If filter_d != 1, then do a multiply accumulate
738         vmlsl.u8        \acc,  \reg_d,  \src3               @ acc -= filter_d * src[stride * 2]
739   .else
740         @ If filter_d is 1, then just do a subtract
741         vsubw.u8        \acc,  \acc,    \src3               @ acc -= src[stride * 2]            @ since filter_d == 1
742   .endif
743   .if \narrow
744         vqshrun.s16     \dest, \acc,    #\filter_shift      @ dest = clip_uint8(acc >> filter_shift)
745   .else
746         vshr.s16        \dest, \acc,    #\filter_shift      @ dest = acc >> filter_shift
747   .endif
748 .endm
749
750 @ This is similar to mspel_filter, but the input is 16-bit instead of 8-bit and narrow=0 is not supported.
751 .macro mspel_filter.16 acc0 acc1 acc0_0 acc0_1 dest src0 src1 src2 src3 src4 src5 src6 src7 filter_a filter_b filter_c filter_d reg_a reg_b reg_c reg_d reg_add filter_shift
752   .if \filter_a != 1
753         vmov            \acc0,  \reg_add
754         vmov            \acc1,  \reg_add
755         vmlsl.s16       \acc0,  \reg_a,  \src0
756         vmlsl.s16       \acc1,  \reg_a,  \src1
757   .else
758         vsubw.s16       \acc0,  \reg_add,  \src0
759         vsubw.s16       \acc1,  \reg_add,  \src1
760   .endif
761         vmlal.s16       \acc0,  \reg_b,  \src2
762         vmlal.s16       \acc1,  \reg_b,  \src3
763   .if \filter_b != \filter_c
764         vmlal.s16       \acc0,  \reg_c,  \src4
765         vmlal.s16       \acc1,  \reg_c,  \src5
766   .else
767         vmlal.s16       \acc0,  \reg_b,  \src4
768         vmlal.s16       \acc1,  \reg_b,  \src5
769   .endif
770   .if \filter_d != 1
771         vmlsl.s16       \acc0,  \reg_d,  \src6
772         vmlsl.s16       \acc1,  \reg_d,  \src7
773   .else
774         vsubw.s16       \acc0,  \acc0,   \src6
775         vsubw.s16       \acc1,  \acc1,   \src7
776   .endif
777         @ Use acc0_0 and acc0_1 as temp space
778         vqshrun.s32     \acc0_0, \acc0,  #\filter_shift     @ Shift and narrow with saturation from s32 to u16
779         vqshrun.s32     \acc0_1, \acc1,  #\filter_shift
780         vqmovn.u16      \dest,  \acc0                       @ Narrow with saturation from u16 to u8
781 .endm
782
783 @ Register usage for put_vc1_mspel_mc functions. Registers marked 'hv' are only used in put_vc1_mspel_mc_hv.
784 @
785 @   r0        adjusted dst
786 @   r1        adjusted src
787 @   r2        stride
788 @   r3        adjusted rnd
789 @   r4 [hv]   tmp
790 @   r11 [hv]  sp saved
791 @   r12       loop counter
792 @   d0        src[-stride]
793 @   d1        src[0]
794 @   d2        src[stride]
795 @   d3        src[stride * 2]
796 @   q0 [hv]   src[-stride]
797 @   q1 [hv]   src[0]
798 @   q2 [hv]   src[stride]
799 @   q3 [hv]   src[stride * 2]
800 @   d21       often result from mspel_filter
801 @   q11       accumulator 0
802 @   q12 [hv]  accumulator 1
803 @   q13       accumulator initial value
804 @   d28       filter_a
805 @   d29       filter_b
806 @   d30       filter_c
807 @   d31       filter_d
808
809 @ (uint8_t *dst [r0], const uint8_t *src [r1], ptrdiff_t stride [r2], int rnd [r3])
810 .macro put_vc1_mspel_mc_hv hmode vmode filter_h_a filter_h_b filter_h_c filter_h_d filter_v_a filter_v_b filter_v_c filter_v_d filter_add filter_shift
811 function ff_put_vc1_mspel_mc\hmode\()\vmode\()_neon, export=1
812         push            {r4, r11, lr}
813         mov             r11, sp                 @ r11 = stack pointer before realignmnet
814 A       bic             sp,  sp,  #15           @ sp = round down to multiple of 16 bytes
815 T       bic             r4,  r11, #15
816 T       mov             sp,  r4
817         sub             sp,  sp,  #(8*2*16)     @ make space for 8 rows * 2 byte per element * 16 elements per row (to fit 11 actual elements per row)
818         mov             r4,  sp                 @ r4 = int16_t tmp[8 * 16]
819
820         sub             r1,  r1,  #1            @ src -= 1
821   .if \filter_add != 0
822         add             r3,  r3,  #\filter_add  @ r3 = filter_add + rnd
823   .endif
824         mov             r12, #8                 @ loop counter
825         sub             r1,  r1,  r2            @ r1 = &src[-stride]      @ slide back
826
827         @ Do vertical filtering from src into tmp
828         mspel_constants i8 d28 d29 d30 d31 \filter_v_a \filter_v_b \filter_v_c \filter_v_d q13 r3
829
830         vld1.64         {d0,d1}, [r1], r2
831         vld1.64         {d2,d3}, [r1], r2
832         vld1.64         {d4,d5}, [r1], r2
833
834 1:
835         subs            r12,  r12,  #4
836
837         vld1.64         {d6,d7}, [r1], r2
838         mspel_filter    q11 q11 d0 d2 d4 d6 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0
839         mspel_filter    q12 q12 d1 d3 d5 d7 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0
840         vst1.64         {q11,q12}, [r4,:128]!   @ store and increment
841
842         vld1.64         {d0,d1}, [r1], r2
843         mspel_filter    q11 q11 d2 d4 d6 d0 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0
844         mspel_filter    q12 q12 d3 d5 d7 d1 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0
845         vst1.64         {q11,q12}, [r4,:128]!   @ store and increment
846
847         vld1.64         {d2,d3}, [r1], r2
848         mspel_filter    q11 q11 d4 d6 d0 d2 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0
849         mspel_filter    q12 q12 d5 d7 d1 d3 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0
850         vst1.64         {q11,q12}, [r4,:128]!   @ store and increment
851
852         vld1.64         {d4,d5}, [r1], r2
853         mspel_filter    q11 q11 d6 d0 d2 d4 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0
854         mspel_filter    q12 q12 d7 d1 d3 d5 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0
855         vst1.64         {q11,q12}, [r4,:128]!   @ store and increment
856
857         bne             1b
858
859         rsb             r3,   r3,  #(64 + \filter_add)      @ r3 = (64 + filter_add) - r3
860         mov             r12,  #8                @ loop counter
861         mov             r4,   sp                @ r4 = tmp
862
863         @ Do horizontal filtering from temp to dst
864         mspel_constants i16 d28 d29 d30 d31 \filter_h_a \filter_h_b \filter_h_c \filter_h_d q13 r3
865
866 2:
867         subs            r12,  r12,  #1
868
869         vld1.64         {q0,q1}, [r4,:128]!     @ read one line of tmp
870         vext.16         q2,   q0,   q1,  #2
871         vext.16         q3,   q0,   q1,  #3
872         vext.16         q1,   q0,   q1,  #1     @ do last because it writes to q1 which is read by the other vext instructions
873
874         mspel_filter.16 q11 q12 d22 d23 d21 d0 d1 d2 d3 d4 d5 d6 d7 \filter_h_a \filter_h_b \filter_h_c \filter_h_d d28 d29 d30 d31 q13 7
875
876         vst1.64         {d21}, [r0,:64], r2     @ store and increment dst
877
878         bne             2b
879
880         mov             sp,  r11
881         pop             {r4, r11, pc}
882 endfunc
883 .endm
884
885 @ Use C preprocessor and assembler macros to expand to functions for horizontal and vertical filtering.
886 #define PUT_VC1_MSPEL_MC_HV(hmode, vmode)   \
887     put_vc1_mspel_mc_hv hmode vmode \
888         MSPEL_MODE_ ## hmode ## _MUL_CONSTANTS \
889         MSPEL_MODE_ ## vmode ## _MUL_CONSTANTS \
890         MSPEL_MODES_ ## hmode ## vmode ## _ADDSHIFT_CONSTANTS
891
892 PUT_VC1_MSPEL_MC_HV(1, 1)
893 PUT_VC1_MSPEL_MC_HV(1, 2)
894 PUT_VC1_MSPEL_MC_HV(1, 3)
895 PUT_VC1_MSPEL_MC_HV(2, 1)
896 PUT_VC1_MSPEL_MC_HV(2, 2)
897 PUT_VC1_MSPEL_MC_HV(2, 3)
898 PUT_VC1_MSPEL_MC_HV(3, 1)
899 PUT_VC1_MSPEL_MC_HV(3, 2)
900 PUT_VC1_MSPEL_MC_HV(3, 3)
901
902 #undef PUT_VC1_MSPEL_MC_HV
903
904 .macro  put_vc1_mspel_mc_h_only hmode filter_a filter_b filter_c filter_d filter_add filter_shift
905 function ff_put_vc1_mspel_mc\hmode\()0_neon, export=1
906         rsb             r3,   r3,   #\filter_add        @ r3 = filter_add - r = filter_add - rnd
907         mov             r12,  #8                        @ loop counter
908         sub             r1,   r1,   #1                  @ slide back, using immediate
909
910         mspel_constants i8 d28 d29 d30 d31 \filter_a \filter_b \filter_c \filter_d q13 r3
911
912 1:
913         subs            r12,  r12,  #1
914
915         vld1.64         {d0,d1}, [r1], r2               @ read 16 bytes even though we only need 11, also src += stride
916         vext.8          d2,   d0,   d1,  #2
917         vext.8          d3,   d0,   d1,  #3
918         vext.8          d1,   d0,   d1,  #1             @ do last because it writes to d1 which is read by the other vext instructions
919
920         mspel_filter    q11 d21 d0 d1 d2 d3 \filter_a \filter_b \filter_c \filter_d d28 d29 d30 d31 q13 \filter_shift
921
922         vst1.64         {d21}, [r0,:64], r2             @ store and increment dst
923
924         bne             1b
925
926         bx              lr
927 endfunc
928 .endm
929
930 @ Use C preprocessor and assembler macros to expand to functions for horizontal only filtering.
931 #define PUT_VC1_MSPEL_MC_H_ONLY(hmode) \
932         put_vc1_mspel_mc_h_only hmode MSPEL_MODE_ ## hmode ## _MUL_CONSTANTS MSPEL_MODE_ ## hmode ## _ADDSHIFT_CONSTANTS
933
934 PUT_VC1_MSPEL_MC_H_ONLY(1)
935 PUT_VC1_MSPEL_MC_H_ONLY(2)
936 PUT_VC1_MSPEL_MC_H_ONLY(3)
937
938 #undef PUT_VC1_MSPEL_MC_H_ONLY
939
940 @ (uint8_t *dst [r0], const uint8_t *src [r1], ptrdiff_t stride [r2], int rnd [r3])
941 .macro put_vc1_mspel_mc_v_only vmode filter_a filter_b filter_c filter_d filter_add filter_shift
942 function ff_put_vc1_mspel_mc0\vmode\()_neon, export=1
943         add             r3,   r3,   #\filter_add - 1    @ r3 = filter_add - r = filter_add - (1 - rnd) = filter_add - 1 + rnd
944         mov             r12,  #8                        @ loop counter
945         sub             r1,   r1,   r2                  @ r1 = &src[-stride]      @ slide back
946
947         mspel_constants i8 d28 d29 d30 d31 \filter_a \filter_b \filter_c \filter_d q13 r3
948
949         vld1.64         {d0},  [r1], r2                 @ d0 = src[-stride]
950         vld1.64         {d1},  [r1], r2                 @ d1 = src[0]
951         vld1.64         {d2},  [r1], r2                 @ d2 = src[stride]
952
953 1:
954         subs            r12,  r12,  #4
955
956         vld1.64         {d3},  [r1], r2                 @ d3 = src[stride * 2]
957         mspel_filter    q11 d21 d0 d1 d2 d3 \filter_a \filter_b \filter_c \filter_d d28 d29 d30 d31 q13 \filter_shift
958         vst1.64         {d21}, [r0,:64], r2             @ store and increment dst
959
960         vld1.64         {d0},  [r1], r2                 @ d0 = next line
961         mspel_filter    q11 d21 d1 d2 d3 d0 \filter_a \filter_b \filter_c \filter_d d28 d29 d30 d31 q13 \filter_shift
962         vst1.64         {d21}, [r0,:64], r2             @ store and increment dst
963
964         vld1.64         {d1},  [r1], r2                 @ d1 = next line
965         mspel_filter    q11 d21 d2 d3 d0 d1 \filter_a \filter_b \filter_c \filter_d d28 d29 d30 d31 q13 \filter_shift
966         vst1.64         {d21}, [r0,:64], r2             @ store and increment dst
967
968         vld1.64         {d2},  [r1], r2                 @ d2 = next line
969         mspel_filter    q11 d21 d3 d0 d1 d2 \filter_a \filter_b \filter_c \filter_d d28 d29 d30 d31 q13 \filter_shift
970         vst1.64         {d21}, [r0,:64], r2             @ store and increment dst
971
972         bne             1b
973
974         bx              lr
975 endfunc
976 .endm
977
978 @ Use C preprocessor and assembler macros to expand to functions for vertical only filtering.
979 #define PUT_VC1_MSPEL_MC_V_ONLY(vmode) \
980         put_vc1_mspel_mc_v_only vmode MSPEL_MODE_ ## vmode ## _MUL_CONSTANTS MSPEL_MODE_ ## vmode ## _ADDSHIFT_CONSTANTS
981
982 PUT_VC1_MSPEL_MC_V_ONLY(1)
983 PUT_VC1_MSPEL_MC_V_ONLY(2)
984 PUT_VC1_MSPEL_MC_V_ONLY(3)
985
986 #undef PUT_VC1_MSPEL_MC_V_ONLY
987
988 function ff_put_pixels8x8_neon, export=1
989         vld1.64         {d0}, [r1], r2
990         vld1.64         {d1}, [r1], r2
991         vld1.64         {d2}, [r1], r2
992         vld1.64         {d3}, [r1], r2
993         vld1.64         {d4}, [r1], r2
994         vld1.64         {d5}, [r1], r2
995         vld1.64         {d6}, [r1], r2
996         vld1.64         {d7}, [r1]
997         vst1.64         {d0}, [r0,:64], r2
998         vst1.64         {d1}, [r0,:64], r2
999         vst1.64         {d2}, [r0,:64], r2
1000         vst1.64         {d3}, [r0,:64], r2
1001         vst1.64         {d4}, [r0,:64], r2
1002         vst1.64         {d5}, [r0,:64], r2
1003         vst1.64         {d6}, [r0,:64], r2
1004         vst1.64         {d7}, [r0,:64]
1005         bx              lr
1006 endfunc
1007
1008 function ff_vc1_inv_trans_8x8_dc_neon, export=1
1009         ldrsh           r2, [r2]              @ int dc = block[0];
1010
1011         vld1.64         {d0},  [r0,:64], r1
1012         vld1.64         {d1},  [r0,:64], r1
1013         vld1.64         {d4},  [r0,:64], r1
1014         vld1.64         {d5},  [r0,:64], r1
1015
1016         add             r2, r2, r2, lsl #1    @ dc = (3 * dc +  1) >> 1;
1017         vld1.64         {d6},  [r0,:64], r1
1018         add             r2, r2, #1
1019         vld1.64         {d7},  [r0,:64], r1
1020         vld1.64         {d16}, [r0,:64], r1
1021         vld1.64         {d17}, [r0,:64], r1
1022         asr             r2, r2, #1
1023
1024         sub             r0,  r0,  r1, lsl #3  @ restore r0 to original value
1025
1026         add             r2, r2, r2, lsl #1    @ dc = (3 * dc + 16) >> 5;
1027         add             r2, r2, #16
1028         asr             r2, r2, #5
1029
1030         vdup.16         q1,  r2               @ dc
1031
1032         vaddw.u8        q9,   q1,  d0
1033         vaddw.u8        q10,  q1,  d1
1034         vaddw.u8        q11,  q1,  d4
1035         vaddw.u8        q12,  q1,  d5
1036         vqmovun.s16     d0,  q9
1037         vqmovun.s16     d1,  q10
1038         vqmovun.s16     d4,  q11
1039         vst1.64         {d0},  [r0,:64], r1
1040         vqmovun.s16     d5,  q12
1041         vst1.64         {d1},  [r0,:64], r1
1042         vaddw.u8        q13,  q1,  d6
1043         vst1.64         {d4},  [r0,:64], r1
1044         vaddw.u8        q14,  q1,  d7
1045         vst1.64         {d5},  [r0,:64], r1
1046         vaddw.u8        q15,  q1,  d16
1047         vaddw.u8        q1,   q1,  d17        @ this destroys q1
1048         vqmovun.s16     d6,  q13
1049         vqmovun.s16     d7,  q14
1050         vqmovun.s16     d16, q15
1051         vqmovun.s16     d17, q1
1052         vst1.64         {d6},  [r0,:64], r1
1053         vst1.64         {d7},  [r0,:64], r1
1054         vst1.64         {d16}, [r0,:64], r1
1055         vst1.64         {d17}, [r0,:64]
1056         bx              lr
1057 endfunc
1058
1059 function ff_vc1_inv_trans_8x4_dc_neon, export=1
1060         ldrsh           r2, [r2]              @ int dc = block[0];
1061
1062         vld1.64         {d0},  [r0,:64], r1
1063         vld1.64         {d1},  [r0,:64], r1
1064         vld1.64         {d4},  [r0,:64], r1
1065         vld1.64         {d5},  [r0,:64], r1
1066
1067         add             r2, r2, r2, lsl #1    @ dc = ( 3 * dc +  1) >> 1;
1068
1069         sub             r0,  r0,  r1, lsl #2  @ restore r0 to original value
1070
1071         add             r2, r2, #1
1072         asr             r2, r2, #1
1073
1074         add             r2, r2, r2, lsl #4    @ dc = (17 * dc + 64) >> 7;
1075         add             r2, r2, #64
1076         asr             r2, r2, #7
1077
1078         vdup.16         q1,  r2               @ dc
1079
1080         vaddw.u8        q3,  q1,  d0
1081         vaddw.u8        q8,  q1,  d1
1082         vaddw.u8        q9,  q1,  d4
1083         vaddw.u8        q10, q1,  d5
1084         vqmovun.s16     d0,  q3
1085         vqmovun.s16     d1,  q8
1086         vqmovun.s16     d4,  q9
1087         vst1.64         {d0},  [r0,:64], r1
1088         vqmovun.s16     d5,  q10
1089         vst1.64         {d1},  [r0,:64], r1
1090         vst1.64         {d4},  [r0,:64], r1
1091         vst1.64         {d5},  [r0,:64]
1092         bx              lr
1093 endfunc
1094
1095 function ff_vc1_inv_trans_4x8_dc_neon, export=1
1096         ldrsh           r2, [r2]              @ int dc = block[0];
1097
1098         vld1.32         {d0[]},   [r0,:32], r1
1099         vld1.32         {d1[]},   [r0,:32], r1
1100         vld1.32         {d0[1]},  [r0,:32], r1
1101         vld1.32         {d1[1]},  [r0,:32], r1
1102
1103         add             r2, r2, r2, lsl #4    @ dc = (17 * dc +  4) >> 3;
1104         vld1.32         {d4[]},   [r0,:32], r1
1105         add             r2, r2, #4
1106         vld1.32         {d5[]},   [r0,:32], r1
1107         vld1.32         {d4[1]},  [r0,:32], r1
1108         asr             r2, r2, #3
1109         vld1.32         {d5[1]},  [r0,:32], r1
1110
1111         add             r2, r2, r2, lsl #1    @ dc = (12 * dc + 64) >> 7;
1112
1113         sub             r0,  r0,  r1, lsl #3  @ restore r0 to original value
1114
1115         lsl             r2, r2, #2
1116         add             r2, r2, #64
1117         asr             r2, r2, #7
1118
1119         vdup.16         q1,  r2               @ dc
1120
1121         vaddw.u8        q3,  q1,  d0
1122         vaddw.u8        q8,  q1,  d1
1123         vaddw.u8        q9,  q1,  d4
1124         vaddw.u8        q10, q1,  d5
1125         vqmovun.s16     d0,  q3
1126         vst1.32         {d0[0]},  [r0,:32], r1
1127         vqmovun.s16     d1,  q8
1128         vst1.32         {d1[0]},  [r0,:32], r1
1129         vqmovun.s16     d4,  q9
1130         vst1.32         {d0[1]},  [r0,:32], r1
1131         vqmovun.s16     d5,  q10
1132         vst1.32         {d1[1]},  [r0,:32], r1
1133         vst1.32         {d4[0]},  [r0,:32], r1
1134         vst1.32         {d5[0]},  [r0,:32], r1
1135         vst1.32         {d4[1]},  [r0,:32], r1
1136         vst1.32         {d5[1]},  [r0,:32]
1137         bx              lr
1138 endfunc
1139
1140 function ff_vc1_inv_trans_4x4_dc_neon, export=1
1141         ldrsh           r2, [r2]              @ int dc = block[0];
1142
1143         vld1.32         {d0[]},   [r0,:32], r1
1144         vld1.32         {d1[]},   [r0,:32], r1
1145         vld1.32         {d0[1]},  [r0,:32], r1
1146         vld1.32         {d1[1]},  [r0,:32], r1
1147
1148         add             r2, r2, r2, lsl #4    @ dc = (17 * dc +  4) >> 3;
1149
1150         sub             r0,  r0,  r1, lsl #2  @ restore r0 to original value
1151
1152         add             r2, r2, #4
1153         asr             r2, r2, #3
1154
1155         add             r2, r2, r2, lsl #4    @ dc = (17 * dc + 64) >> 7;
1156         add             r2, r2, #64
1157         asr             r2, r2, #7
1158
1159         vdup.16         q1,  r2               @ dc
1160
1161         vaddw.u8        q2,  q1,  d0
1162         vaddw.u8        q3,  q1,  d1
1163         vqmovun.s16     d0,  q2
1164         vst1.32         {d0[0]},  [r0,:32], r1
1165         vqmovun.s16     d1,  q3
1166         vst1.32         {d1[0]},  [r0,:32], r1
1167         vst1.32         {d0[1]},  [r0,:32], r1
1168         vst1.32         {d1[1]},  [r0,:32]
1169         bx              lr
1170 endfunc