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
71function 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
1091:      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
141function 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
1661:      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
1772:      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
1903:      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
2004:      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
214function 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
233idct_coeff_neon:
234        .short W1, W2, W3, W4, W5, W6, W7, W4c
235        .previous
236
237        .macro idct_start data
238        push            {r4-r7, lr}
239        pld             [\data]
240        pld             [\data, #64]
241        vpush           {d8-d15}
242        movrel          r3,  idct_coeff_neon
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); */
252function 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
271function 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); */
307function 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
326function 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); */
346function 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
363