376db0b53484f88a7472759721cf52d9dac2bc33
[libav.git] / libavcodec / arm / simple_idct_neon.S
1 /*
2 * ARM NEON IDCT
3 *
4 * Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
5 *
6 * Based on Simple IDCT
7 * Copyright (c) 2001 Michael Niedermayer <michaelni@gmx.at>
8 *
9 * This file is part of FFmpeg.
10 *
11 * FFmpeg is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * FFmpeg is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with FFmpeg; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26 #include "asm.S"
27
28 #define W1 22725 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
29 #define W2 21407 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
30 #define W3 19266 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
31 #define W4 16383 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
32 #define W5 12873 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
33 #define W6 8867 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
34 #define W7 4520 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
35 #define W4c ((1<<(COL_SHIFT-1))/W4)
36 #define ROW_SHIFT 11
37 #define COL_SHIFT 20
38
39 #define w1 d0[0]
40 #define w2 d0[1]
41 #define w3 d0[2]
42 #define w4 d0[3]
43 #define w5 d1[0]
44 #define w6 d1[1]
45 #define w7 d1[2]
46 #define w4c d1[3]
47
48 .fpu neon
49
50 .macro idct_col4_top
51 vmull.s16 q7, d6, w2 /* q9 = W2 * col[2] */
52 vmull.s16 q8, d6, w6 /* q10 = W6 * col[2] */
53 vmull.s16 q9, d4, w1 /* q9 = W1 * col[1] */
54 vadd.i32 q11, q15, q7
55 vmull.s16 q10, d4, w3 /* q10 = W3 * col[1] */
56 vadd.i32 q12, q15, q8
57 vmull.s16 q5, d4, w5 /* q5 = W5 * col[1] */
58 vsub.i32 q13, q15, q8
59 vmull.s16 q6, d4, w7 /* q6 = W7 * col[1] */
60 vsub.i32 q14, q15, q7
61
62 vmlal.s16 q9, d8, w3 /* q9 += W3 * col[3] */
63 vmlsl.s16 q10, d8, w7 /* q10 -= W7 * col[3] */
64 vmlsl.s16 q5, d8, w1 /* q5 -= W1 * col[3] */
65 vmlsl.s16 q6, d8, w5 /* q6 -= W5 * col[3] */
66 .endm
67
68 .text
69 .align 6
70
71 function idct_row4_neon
72 vmov.i32 q15, #(1<<(ROW_SHIFT-1))
73 vld1.64 {d2-d5}, [r2,:128]!
74 vmlal.s16 q15, d2, w4 /* q15 += W4 * col[0] */
75 vld1.64 {d6,d7}, [r2,:128]!
76 vorr d10, d3, d5
77 vld1.64 {d8,d9}, [r2,:128]!
78 add r2, r2, #-64
79
80 vorr d11, d7, d9
81 vorr d10, d10, d11
82 vmov r3, r4, d10
83
84 idct_col4_top
85
86 orrs r3, r3, r4
87 beq 1f
88
89 vmull.s16 q7, d3, w4 /* q7 = W4 * col[4] */
90 vmlal.s16 q9, d5, w5 /* q9 += W5 * col[5] */
91 vmlsl.s16 q10, d5, w1 /* q10 -= W1 * col[5] */
92 vmull.s16 q8, d7, w2 /* q8 = W2 * col[6] */
93 vmlal.s16 q5, d5, w7 /* q5 += W7 * col[5] */
94 vadd.i32 q11, q11, q7
95 vsub.i32 q12, q12, q7
96 vsub.i32 q13, q13, q7
97 vadd.i32 q14, q14, q7
98 vmlal.s16 q6, d5, w3 /* q6 += W3 * col[5] */
99 vmull.s16 q7, d7, w6 /* q7 = W6 * col[6] */
100 vmlal.s16 q9, d9, w7
101 vmlsl.s16 q10, d9, w5
102 vmlal.s16 q5, d9, w3
103 vmlsl.s16 q6, d9, w1
104 vadd.i32 q11, q11, q7
105 vsub.i32 q12, q12, q8
106 vadd.i32 q13, q13, q8
107 vsub.i32 q14, q14, q7
108
109 1: vadd.i32 q3, q11, q9
110 vadd.i32 q4, q12, q10
111 vshrn.i32 d2, q3, #ROW_SHIFT
112 vshrn.i32 d4, q4, #ROW_SHIFT
113 vadd.i32 q7, q13, q5
114 vadd.i32 q8, q14, q6
115 vtrn.16 d2, d4
116 vshrn.i32 d6, q7, #ROW_SHIFT
117 vshrn.i32 d8, q8, #ROW_SHIFT
118 vsub.i32 q14, q14, q6
119 vsub.i32 q11, q11, q9
120 vtrn.16 d6, d8
121 vsub.i32 q13, q13, q5
122 vshrn.i32 d3, q14, #ROW_SHIFT
123 vtrn.32 d2, d6
124 vsub.i32 q12, q12, q10
125 vtrn.32 d4, d8
126 vshrn.i32 d5, q13, #ROW_SHIFT
127 vshrn.i32 d7, q12, #ROW_SHIFT
128 vshrn.i32 d9, q11, #ROW_SHIFT
129
130 vtrn.16 d3, d5
131 vtrn.16 d7, d9
132 vtrn.32 d3, d7
133 vtrn.32 d5, d9
134
135 vst1.64 {d2-d5}, [r2,:128]!
136 vst1.64 {d6-d9}, [r2,:128]!
137
138 bx lr
139 .endfunc
140
141 function idct_col4_neon
142 mov ip, #16
143 vld1.64 {d2}, [r2,:64], ip /* d2 = col[0] */
144 vdup.16 d30, w4c
145 vld1.64 {d4}, [r2,:64], ip /* d3 = col[1] */
146 vadd.i16 d30, d30, d2
147 vld1.64 {d6}, [r2,:64], ip /* d4 = col[2] */
148 vmull.s16 q15, d30, w4 /* q15 = W4*(col[0]+(1<<COL_SHIFT-1)/W4)*/
149 vld1.64 {d8}, [r2,:64], ip /* d5 = col[3] */
150
151 ldrd r4, [r2]
152 ldrd r6, [r2, #16]
153 orrs r4, r4, r5
154
155 idct_col4_top
156 addeq r2, r2, #16
157 beq 1f
158
159 vld1.64 {d3}, [r2,:64], ip /* d6 = col[4] */
160 vmull.s16 q7, d3, w4 /* q7 = W4 * col[4] */
161 vadd.i32 q11, q11, q7
162 vsub.i32 q12, q12, q7
163 vsub.i32 q13, q13, q7
164 vadd.i32 q14, q14, q7
165
166 1: orrs r6, r6, r7
167 ldrd r4, [r2, #16]
168 addeq r2, r2, #16
169 beq 2f
170
171 vld1.64 {d5}, [r2,:64], ip /* d7 = col[5] */
172 vmlal.s16 q9, d5, w5 /* q9 += W5 * col[5] */
173 vmlsl.s16 q10, d5, w1 /* q10 -= W1 * col[5] */
174 vmlal.s16 q5, d5, w7 /* q5 += W7 * col[5] */
175 vmlal.s16 q6, d5, w3 /* q6 += W3 * col[5] */
176
177 2: orrs r4, r4, r5
178 ldrd r4, [r2, #16]
179 addeq r2, r2, #16
180 beq 3f
181
182 vld1.64 {d7}, [r2,:64], ip /* d8 = col[6] */
183 vmull.s16 q7, d7, w6 /* q7 = W6 * col[6] */
184 vmull.s16 q8, d7, w2 /* q8 = W2 * col[6] */
185 vadd.i32 q11, q11, q7
186 vsub.i32 q14, q14, q7
187 vsub.i32 q12, q12, q8
188 vadd.i32 q13, q13, q8
189
190 3: orrs r4, r4, r5
191 addeq r2, r2, #16
192 beq 4f
193
194 vld1.64 {d9}, [r2,:64], ip /* d9 = col[7] */
195 vmlal.s16 q9, d9, w7
196 vmlsl.s16 q10, d9, w5
197 vmlal.s16 q5, d9, w3
198 vmlsl.s16 q6, d9, w1
199
200 4: vaddhn.i32 d2, q11, q9
201 vaddhn.i32 d3, q12, q10
202 vaddhn.i32 d4, q13, q5
203 vaddhn.i32 d5, q14, q6
204 vsubhn.i32 d9, q11, q9
205 vsubhn.i32 d8, q12, q10
206 vsubhn.i32 d7, q13, q5
207 vsubhn.i32 d6, q14, q6
208
209 bx lr
210 .endfunc
211
212 .align 6
213
214 function idct_col4_st8_neon
215 vqshrun.s16 d2, q1, #COL_SHIFT-16
216 vqshrun.s16 d3, q2, #COL_SHIFT-16
217 vqshrun.s16 d4, q3, #COL_SHIFT-16
218 vqshrun.s16 d5, q4, #COL_SHIFT-16
219 vst1.32 {d2[0]}, [r0,:32], r1
220 vst1.32 {d2[1]}, [r0,:32], r1
221 vst1.32 {d3[0]}, [r0,:32], r1
222 vst1.32 {d3[1]}, [r0,:32], r1
223 vst1.32 {d4[0]}, [r0,:32], r1
224 vst1.32 {d4[1]}, [r0,:32], r1
225 vst1.32 {d5[0]}, [r0,:32], r1
226 vst1.32 {d5[1]}, [r0,:32], r1
227
228 bx lr
229 .endfunc
230
231 .section .rodata
232 .align 4
233 const: .short W1, W2, W3, W4, W5, W6, W7, W4c
234 .previous
235
236 .macro idct_start data
237 push {r4-r7, lr}
238 pld [\data]
239 pld [\data, #64]
240 vpush {d8-d15}
241 movw r3, #:lower16:const
242 movt r3, #:upper16:const
243 vld1.64 {d0,d1}, [r3,:128]
244 .endm
245
246 .macro idct_end
247 vpop {d8-d15}
248 pop {r4-r7, pc}
249 .endm
250
251 /* void ff_simple_idct_put_neon(uint8_t *dst, int line_size, DCTELEM *data); */
252 function ff_simple_idct_put_neon, export=1
253 idct_start r2
254
255 bl idct_row4_neon
256 bl idct_row4_neon
257 add r2, r2, #-128
258 bl idct_col4_neon
259 bl idct_col4_st8_neon
260 sub r0, r0, r1, lsl #3
261 add r0, r0, #4
262 add r2, r2, #-120
263 bl idct_col4_neon
264 bl idct_col4_st8_neon
265
266 idct_end
267 .endfunc
268
269 .align 6
270
271 function idct_col4_add8_neon
272 mov ip, r0
273
274 vld1.32 {d10[0]}, [r0,:32], r1
275 vshr.s16 q1, q1, #COL_SHIFT-16
276 vld1.32 {d10[1]}, [r0,:32], r1
277 vshr.s16 q2, q2, #COL_SHIFT-16
278 vld1.32 {d11[0]}, [r0,:32], r1
279 vshr.s16 q3, q3, #COL_SHIFT-16
280 vld1.32 {d11[1]}, [r0,:32], r1
281 vshr.s16 q4, q4, #COL_SHIFT-16
282 vld1.32 {d12[0]}, [r0,:32], r1
283 vaddw.u8 q1, q1, d10
284 vld1.32 {d12[1]}, [r0,:32], r1
285 vaddw.u8 q2, q2, d11
286 vld1.32 {d13[0]}, [r0,:32], r1
287 vqmovun.s16 d2, q1
288 vld1.32 {d13[1]}, [r0,:32], r1
289 vaddw.u8 q3, q3, d12
290 vst1.32 {d2[0]}, [ip,:32], r1
291 vqmovun.s16 d3, q2
292 vst1.32 {d2[1]}, [ip,:32], r1
293 vaddw.u8 q4, q4, d13
294 vst1.32 {d3[0]}, [ip,:32], r1
295 vqmovun.s16 d4, q3
296 vst1.32 {d3[1]}, [ip,:32], r1
297 vqmovun.s16 d5, q4
298 vst1.32 {d4[0]}, [ip,:32], r1
299 vst1.32 {d4[1]}, [ip,:32], r1
300 vst1.32 {d5[0]}, [ip,:32], r1
301 vst1.32 {d5[1]}, [ip,:32], r1
302
303 bx lr
304 .endfunc
305
306 /* void ff_simple_idct_add_neon(uint8_t *dst, int line_size, DCTELEM *data); */
307 function ff_simple_idct_add_neon, export=1
308 idct_start r2
309
310 bl idct_row4_neon
311 bl idct_row4_neon
312 add r2, r2, #-128
313 bl idct_col4_neon
314 bl idct_col4_add8_neon
315 sub r0, r0, r1, lsl #3
316 add r0, r0, #4
317 add r2, r2, #-120
318 bl idct_col4_neon
319 bl idct_col4_add8_neon
320
321 idct_end
322 .endfunc
323
324 .align 6
325
326 function idct_col4_st16_neon
327 mov ip, #16
328
329 vshr.s16 q1, q1, #COL_SHIFT-16
330 vshr.s16 q2, q2, #COL_SHIFT-16
331 vst1.64 {d2}, [r2,:64], ip
332 vshr.s16 q3, q3, #COL_SHIFT-16
333 vst1.64 {d3}, [r2,:64], ip
334 vshr.s16 q4, q4, #COL_SHIFT-16
335 vst1.64 {d4}, [r2,:64], ip
336 vst1.64 {d5}, [r2,:64], ip
337 vst1.64 {d6}, [r2,:64], ip
338 vst1.64 {d7}, [r2,:64], ip
339 vst1.64 {d8}, [r2,:64], ip
340 vst1.64 {d9}, [r2,:64], ip
341
342 bx lr
343 .endfunc
344
345 /* void ff_simple_idct_neon(DCTELEM *data); */
346 function ff_simple_idct_neon, export=1
347 idct_start r0
348
349 mov r2, r0
350 bl idct_row4_neon
351 bl idct_row4_neon
352 add r2, r2, #-128
353 bl idct_col4_neon
354 add r2, r2, #-128
355 bl idct_col4_st16_neon
356 add r2, r2, #-120
357 bl idct_col4_neon
358 add r2, r2, #-128
359 bl idct_col4_st16_neon
360
361 idct_end
362 .endfunc