1;
2;  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
3;
4;  Use of this source code is governed by a BSD-style license
5;  that can be found in the LICENSE file in the root of the source
6;  tree. An additional intellectual property rights grant can be found
7;  in the file PATENTS.  All contributing project authors may
8;  be found in the AUTHORS file in the root of the source tree.
9;
10
11    EXPORT  |vp9_idct8x8_64_add_neon|
12    EXPORT  |vp9_idct8x8_12_add_neon|
13    ARM
14    REQUIRE8
15    PRESERVE8
16
17    AREA ||.text||, CODE, READONLY, ALIGN=2
18
19    ; Parallel 1D IDCT on all the columns of a 8x8 16bit data matrix which are
20    ; loaded in q8-q15. The output will be stored back into q8-q15 registers.
21    ; This macro will touch q0-q7 registers and use them as buffer during
22    ; calculation.
23    MACRO
24    IDCT8x8_1D
25    ; stage 1
26    vdup.16         d0, r3                    ; duplicate cospi_28_64
27    vdup.16         d1, r4                    ; duplicate cospi_4_64
28    vdup.16         d2, r5                    ; duplicate cospi_12_64
29    vdup.16         d3, r6                    ; duplicate cospi_20_64
30
31    ; input[1] * cospi_28_64
32    vmull.s16       q2, d18, d0
33    vmull.s16       q3, d19, d0
34
35    ; input[5] * cospi_12_64
36    vmull.s16       q5, d26, d2
37    vmull.s16       q6, d27, d2
38
39    ; input[1]*cospi_28_64-input[7]*cospi_4_64
40    vmlsl.s16       q2, d30, d1
41    vmlsl.s16       q3, d31, d1
42
43    ; input[5] * cospi_12_64 - input[3] * cospi_20_64
44    vmlsl.s16       q5, d22, d3
45    vmlsl.s16       q6, d23, d3
46
47    ; dct_const_round_shift(input_dc * cospi_16_64)
48    vqrshrn.s32     d8, q2, #14               ; >> 14
49    vqrshrn.s32     d9, q3, #14               ; >> 14
50
51    ; dct_const_round_shift(input_dc * cospi_16_64)
52    vqrshrn.s32     d10, q5, #14              ; >> 14
53    vqrshrn.s32     d11, q6, #14              ; >> 14
54
55    ; input[1] * cospi_4_64
56    vmull.s16       q2, d18, d1
57    vmull.s16       q3, d19, d1
58
59    ; input[5] * cospi_20_64
60    vmull.s16       q9, d26, d3
61    vmull.s16       q13, d27, d3
62
63    ; input[1]*cospi_4_64+input[7]*cospi_28_64
64    vmlal.s16       q2, d30, d0
65    vmlal.s16       q3, d31, d0
66
67    ; input[5] * cospi_20_64 + input[3] * cospi_12_64
68    vmlal.s16       q9, d22, d2
69    vmlal.s16       q13, d23, d2
70
71    ; dct_const_round_shift(input_dc * cospi_16_64)
72    vqrshrn.s32     d14, q2, #14              ; >> 14
73    vqrshrn.s32     d15, q3, #14              ; >> 14
74
75    ; stage 2 & stage 3 - even half
76    vdup.16         d0, r7                    ; duplicate cospi_16_64
77
78    ; dct_const_round_shift(input_dc * cospi_16_64)
79    vqrshrn.s32     d12, q9, #14              ; >> 14
80    vqrshrn.s32     d13, q13, #14              ; >> 14
81
82    ; input[0] * cospi_16_64
83    vmull.s16       q2, d16, d0
84    vmull.s16       q3, d17, d0
85
86    ; input[0] * cospi_16_64
87    vmull.s16       q13, d16, d0
88    vmull.s16       q15, d17, d0
89
90    ; (input[0] + input[2]) * cospi_16_64
91    vmlal.s16       q2,  d24, d0
92    vmlal.s16       q3, d25, d0
93
94    ; (input[0] - input[2]) * cospi_16_64
95    vmlsl.s16       q13, d24, d0
96    vmlsl.s16       q15, d25, d0
97
98    vdup.16         d0, r8                    ; duplicate cospi_24_64
99    vdup.16         d1, r9                    ; duplicate cospi_8_64
100
101    ; dct_const_round_shift(input_dc * cospi_16_64)
102    vqrshrn.s32     d18, q2, #14              ; >> 14
103    vqrshrn.s32     d19, q3, #14              ; >> 14
104
105    ; dct_const_round_shift(input_dc * cospi_16_64)
106    vqrshrn.s32     d22, q13, #14              ; >> 14
107    vqrshrn.s32     d23, q15, #14              ; >> 14
108
109    ; input[1] * cospi_24_64 - input[3] * cospi_8_64
110    ; input[1] * cospi_24_64
111    vmull.s16       q2, d20, d0
112    vmull.s16       q3, d21, d0
113
114    ; input[1] * cospi_8_64
115    vmull.s16       q8, d20, d1
116    vmull.s16       q12, d21, d1
117
118    ; input[1] * cospi_24_64 - input[3] * cospi_8_64
119    vmlsl.s16       q2, d28, d1
120    vmlsl.s16       q3, d29, d1
121
122    ; input[1] * cospi_8_64 + input[3] * cospi_24_64
123    vmlal.s16       q8, d28, d0
124    vmlal.s16       q12, d29, d0
125
126    ; dct_const_round_shift(input_dc * cospi_16_64)
127    vqrshrn.s32     d26, q2, #14              ; >> 14
128    vqrshrn.s32     d27, q3, #14              ; >> 14
129
130    ; dct_const_round_shift(input_dc * cospi_16_64)
131    vqrshrn.s32     d30, q8, #14              ; >> 14
132    vqrshrn.s32     d31, q12, #14              ; >> 14
133
134    vadd.s16        q0, q9, q15               ; output[0] = step[0] + step[3]
135    vadd.s16        q1, q11, q13              ; output[1] = step[1] + step[2]
136    vsub.s16        q2, q11, q13              ; output[2] = step[1] - step[2]
137    vsub.s16        q3, q9, q15               ; output[3] = step[0] - step[3]
138
139    ; stage 3 -odd half
140    vdup.16         d16, r7                   ; duplicate cospi_16_64
141
142    ; stage 2 - odd half
143    vsub.s16        q13, q4, q5               ; step2[5] = step1[4] - step1[5]
144    vadd.s16        q4, q4, q5                ; step2[4] = step1[4] + step1[5]
145    vsub.s16        q14, q7, q6               ; step2[6] = -step1[6] + step1[7]
146    vadd.s16        q7, q7, q6                ; step2[7] = step1[6] + step1[7]
147
148    ; step2[6] * cospi_16_64
149    vmull.s16       q9, d28, d16
150    vmull.s16       q10, d29, d16
151
152    ; step2[6] * cospi_16_64
153    vmull.s16       q11, d28, d16
154    vmull.s16       q12, d29, d16
155
156    ; (step2[6] - step2[5]) * cospi_16_64
157    vmlsl.s16       q9, d26, d16
158    vmlsl.s16       q10, d27, d16
159
160    ; (step2[5] + step2[6]) * cospi_16_64
161    vmlal.s16       q11, d26, d16
162    vmlal.s16       q12, d27, d16
163
164    ; dct_const_round_shift(input_dc * cospi_16_64)
165    vqrshrn.s32     d10, q9, #14              ; >> 14
166    vqrshrn.s32     d11, q10, #14             ; >> 14
167
168    ; dct_const_round_shift(input_dc * cospi_16_64)
169    vqrshrn.s32     d12, q11, #14              ; >> 14
170    vqrshrn.s32     d13, q12, #14             ; >> 14
171
172    ; stage 4
173    vadd.s16        q8, q0, q7                ; output[0] = step1[0] + step1[7];
174    vadd.s16        q9, q1, q6                ; output[1] = step1[1] + step1[6];
175    vadd.s16        q10, q2, q5               ; output[2] = step1[2] + step1[5];
176    vadd.s16        q11, q3, q4               ; output[3] = step1[3] + step1[4];
177    vsub.s16        q12, q3, q4               ; output[4] = step1[3] - step1[4];
178    vsub.s16        q13, q2, q5               ; output[5] = step1[2] - step1[5];
179    vsub.s16        q14, q1, q6               ; output[6] = step1[1] - step1[6];
180    vsub.s16        q15, q0, q7               ; output[7] = step1[0] - step1[7];
181    MEND
182
183    ; Transpose a 8x8 16bit data matrix. Datas are loaded in q8-q15.
184    MACRO
185    TRANSPOSE8X8
186    vswp            d17, d24
187    vswp            d23, d30
188    vswp            d21, d28
189    vswp            d19, d26
190    vtrn.32         q8, q10
191    vtrn.32         q9, q11
192    vtrn.32         q12, q14
193    vtrn.32         q13, q15
194    vtrn.16         q8, q9
195    vtrn.16         q10, q11
196    vtrn.16         q12, q13
197    vtrn.16         q14, q15
198    MEND
199
200    AREA    Block, CODE, READONLY ; name this block of code
201;void vp9_idct8x8_64_add_neon(int16_t *input, uint8_t *dest, int dest_stride)
202;
203; r0  int16_t input
204; r1  uint8_t *dest
205; r2  int dest_stride)
206
207|vp9_idct8x8_64_add_neon| PROC
208    push            {r4-r9}
209    vpush           {d8-d15}
210    vld1.s16        {q8,q9}, [r0]!
211    vld1.s16        {q10,q11}, [r0]!
212    vld1.s16        {q12,q13}, [r0]!
213    vld1.s16        {q14,q15}, [r0]!
214
215    ; transpose the input data
216    TRANSPOSE8X8
217
218    ; generate  cospi_28_64 = 3196
219    mov             r3, #0x0c00
220    add             r3, #0x7c
221
222    ; generate cospi_4_64  = 16069
223    mov             r4, #0x3e00
224    add             r4, #0xc5
225
226    ; generate cospi_12_64 = 13623
227    mov             r5, #0x3500
228    add             r5, #0x37
229
230    ; generate cospi_20_64 = 9102
231    mov             r6, #0x2300
232    add             r6, #0x8e
233
234    ; generate cospi_16_64 = 11585
235    mov             r7, #0x2d00
236    add             r7, #0x41
237
238    ; generate cospi_24_64 = 6270
239    mov             r8, #0x1800
240    add             r8, #0x7e
241
242    ; generate cospi_8_64 = 15137
243    mov             r9, #0x3b00
244    add             r9, #0x21
245
246    ; First transform rows
247    IDCT8x8_1D
248
249    ; Transpose the matrix
250    TRANSPOSE8X8
251
252    ; Then transform columns
253    IDCT8x8_1D
254
255    ; ROUND_POWER_OF_TWO(temp_out[j], 5)
256    vrshr.s16       q8, q8, #5
257    vrshr.s16       q9, q9, #5
258    vrshr.s16       q10, q10, #5
259    vrshr.s16       q11, q11, #5
260    vrshr.s16       q12, q12, #5
261    vrshr.s16       q13, q13, #5
262    vrshr.s16       q14, q14, #5
263    vrshr.s16       q15, q15, #5
264
265    ; save dest pointer
266    mov             r0, r1
267
268    ; load destination data
269    vld1.64         {d0}, [r1], r2
270    vld1.64         {d1}, [r1], r2
271    vld1.64         {d2}, [r1], r2
272    vld1.64         {d3}, [r1], r2
273    vld1.64         {d4}, [r1], r2
274    vld1.64         {d5}, [r1], r2
275    vld1.64         {d6}, [r1], r2
276    vld1.64         {d7}, [r1]
277
278    ; ROUND_POWER_OF_TWO(temp_out[j], 5) + dest[j * dest_stride + i]
279    vaddw.u8        q8, q8, d0
280    vaddw.u8        q9, q9, d1
281    vaddw.u8        q10, q10, d2
282    vaddw.u8        q11, q11, d3
283    vaddw.u8        q12, q12, d4
284    vaddw.u8        q13, q13, d5
285    vaddw.u8        q14, q14, d6
286    vaddw.u8        q15, q15, d7
287
288    ; clip_pixel
289    vqmovun.s16     d0, q8
290    vqmovun.s16     d1, q9
291    vqmovun.s16     d2, q10
292    vqmovun.s16     d3, q11
293    vqmovun.s16     d4, q12
294    vqmovun.s16     d5, q13
295    vqmovun.s16     d6, q14
296    vqmovun.s16     d7, q15
297
298    ; store the data
299    vst1.64         {d0}, [r0], r2
300    vst1.64         {d1}, [r0], r2
301    vst1.64         {d2}, [r0], r2
302    vst1.64         {d3}, [r0], r2
303    vst1.64         {d4}, [r0], r2
304    vst1.64         {d5}, [r0], r2
305    vst1.64         {d6}, [r0], r2
306    vst1.64         {d7}, [r0], r2
307
308    vpop            {d8-d15}
309    pop             {r4-r9}
310    bx              lr
311    ENDP  ; |vp9_idct8x8_64_add_neon|
312
313;void vp9_idct8x8_12_add_neon(int16_t *input, uint8_t *dest, int dest_stride)
314;
315; r0  int16_t input
316; r1  uint8_t *dest
317; r2  int dest_stride)
318
319|vp9_idct8x8_12_add_neon| PROC
320    push            {r4-r9}
321    vpush           {d8-d15}
322    vld1.s16        {q8,q9}, [r0]!
323    vld1.s16        {q10,q11}, [r0]!
324    vld1.s16        {q12,q13}, [r0]!
325    vld1.s16        {q14,q15}, [r0]!
326
327    ; transpose the input data
328    TRANSPOSE8X8
329
330    ; generate  cospi_28_64 = 3196
331    mov             r3, #0x0c00
332    add             r3, #0x7c
333
334    ; generate cospi_4_64  = 16069
335    mov             r4, #0x3e00
336    add             r4, #0xc5
337
338    ; generate cospi_12_64 = 13623
339    mov             r5, #0x3500
340    add             r5, #0x37
341
342    ; generate cospi_20_64 = 9102
343    mov             r6, #0x2300
344    add             r6, #0x8e
345
346    ; generate cospi_16_64 = 11585
347    mov             r7, #0x2d00
348    add             r7, #0x41
349
350    ; generate cospi_24_64 = 6270
351    mov             r8, #0x1800
352    add             r8, #0x7e
353
354    ; generate cospi_8_64 = 15137
355    mov             r9, #0x3b00
356    add             r9, #0x21
357
358    ; First transform rows
359    ; stage 1
360    ; The following instructions use vqrdmulh to do the
361    ; dct_const_round_shift(input[1] * cospi_28_64). vqrdmulh will do doubling
362    ; multiply and shift the result by 16 bits instead of 14 bits. So we need
363    ; to double the constants before multiplying to compensate this.
364    mov             r12, r3, lsl #1
365    vdup.16         q0, r12                   ; duplicate cospi_28_64*2
366    mov             r12, r4, lsl #1
367    vdup.16         q1, r12                   ; duplicate cospi_4_64*2
368
369    ; dct_const_round_shift(input[1] * cospi_28_64)
370    vqrdmulh.s16    q4, q9, q0
371
372    mov             r12, r6, lsl #1
373    rsb             r12, #0
374    vdup.16         q0, r12                   ; duplicate -cospi_20_64*2
375
376    ; dct_const_round_shift(input[1] * cospi_4_64)
377    vqrdmulh.s16    q7, q9, q1
378
379    mov             r12, r5, lsl #1
380    vdup.16         q1, r12                   ; duplicate cospi_12_64*2
381
382    ; dct_const_round_shift(- input[3] * cospi_20_64)
383    vqrdmulh.s16    q5, q11, q0
384
385    mov             r12, r7, lsl #1
386    vdup.16         q0, r12                   ; duplicate cospi_16_64*2
387
388    ; dct_const_round_shift(input[3] * cospi_12_64)
389    vqrdmulh.s16    q6, q11, q1
390
391    ; stage 2 & stage 3 - even half
392    mov             r12, r8, lsl #1
393    vdup.16         q1, r12                   ; duplicate cospi_24_64*2
394
395    ; dct_const_round_shift(input_dc * cospi_16_64)
396    vqrdmulh.s16    q9, q8, q0
397
398    mov             r12, r9, lsl #1
399    vdup.16         q0, r12                   ; duplicate cospi_8_64*2
400
401    ; dct_const_round_shift(input[1] * cospi_24_64)
402    vqrdmulh.s16    q13, q10, q1
403
404    ; dct_const_round_shift(input[1] * cospi_8_64)
405    vqrdmulh.s16    q15, q10, q0
406
407    ; stage 3 -odd half
408    vdup.16         d16, r7                   ; duplicate cospi_16_64
409
410    vadd.s16        q0, q9, q15               ; output[0] = step[0] + step[3]
411    vadd.s16        q1, q9, q13               ; output[1] = step[1] + step[2]
412    vsub.s16        q2, q9, q13               ; output[2] = step[1] - step[2]
413    vsub.s16        q3, q9, q15               ; output[3] = step[0] - step[3]
414
415    ; stage 2 - odd half
416    vsub.s16        q13, q4, q5               ; step2[5] = step1[4] - step1[5]
417    vadd.s16        q4, q4, q5                ; step2[4] = step1[4] + step1[5]
418    vsub.s16        q14, q7, q6               ; step2[6] = -step1[6] + step1[7]
419    vadd.s16        q7, q7, q6                ; step2[7] = step1[6] + step1[7]
420
421    ; step2[6] * cospi_16_64
422    vmull.s16       q9, d28, d16
423    vmull.s16       q10, d29, d16
424
425    ; step2[6] * cospi_16_64
426    vmull.s16       q11, d28, d16
427    vmull.s16       q12, d29, d16
428
429    ; (step2[6] - step2[5]) * cospi_16_64
430    vmlsl.s16       q9, d26, d16
431    vmlsl.s16       q10, d27, d16
432
433    ; (step2[5] + step2[6]) * cospi_16_64
434    vmlal.s16       q11, d26, d16
435    vmlal.s16       q12, d27, d16
436
437    ; dct_const_round_shift(input_dc * cospi_16_64)
438    vqrshrn.s32     d10, q9, #14              ; >> 14
439    vqrshrn.s32     d11, q10, #14             ; >> 14
440
441    ; dct_const_round_shift(input_dc * cospi_16_64)
442    vqrshrn.s32     d12, q11, #14              ; >> 14
443    vqrshrn.s32     d13, q12, #14             ; >> 14
444
445    ; stage 4
446    vadd.s16        q8, q0, q7                ; output[0] = step1[0] + step1[7];
447    vadd.s16        q9, q1, q6                ; output[1] = step1[1] + step1[6];
448    vadd.s16        q10, q2, q5               ; output[2] = step1[2] + step1[5];
449    vadd.s16        q11, q3, q4               ; output[3] = step1[3] + step1[4];
450    vsub.s16        q12, q3, q4               ; output[4] = step1[3] - step1[4];
451    vsub.s16        q13, q2, q5               ; output[5] = step1[2] - step1[5];
452    vsub.s16        q14, q1, q6               ; output[6] = step1[1] - step1[6];
453    vsub.s16        q15, q0, q7               ; output[7] = step1[0] - step1[7];
454
455    ; Transpose the matrix
456    TRANSPOSE8X8
457
458    ; Then transform columns
459    IDCT8x8_1D
460
461    ; ROUND_POWER_OF_TWO(temp_out[j], 5)
462    vrshr.s16       q8, q8, #5
463    vrshr.s16       q9, q9, #5
464    vrshr.s16       q10, q10, #5
465    vrshr.s16       q11, q11, #5
466    vrshr.s16       q12, q12, #5
467    vrshr.s16       q13, q13, #5
468    vrshr.s16       q14, q14, #5
469    vrshr.s16       q15, q15, #5
470
471    ; save dest pointer
472    mov             r0, r1
473
474    ; load destination data
475    vld1.64         {d0}, [r1], r2
476    vld1.64         {d1}, [r1], r2
477    vld1.64         {d2}, [r1], r2
478    vld1.64         {d3}, [r1], r2
479    vld1.64         {d4}, [r1], r2
480    vld1.64         {d5}, [r1], r2
481    vld1.64         {d6}, [r1], r2
482    vld1.64         {d7}, [r1]
483
484    ; ROUND_POWER_OF_TWO(temp_out[j], 5) + dest[j * dest_stride + i]
485    vaddw.u8        q8, q8, d0
486    vaddw.u8        q9, q9, d1
487    vaddw.u8        q10, q10, d2
488    vaddw.u8        q11, q11, d3
489    vaddw.u8        q12, q12, d4
490    vaddw.u8        q13, q13, d5
491    vaddw.u8        q14, q14, d6
492    vaddw.u8        q15, q15, d7
493
494    ; clip_pixel
495    vqmovun.s16     d0, q8
496    vqmovun.s16     d1, q9
497    vqmovun.s16     d2, q10
498    vqmovun.s16     d3, q11
499    vqmovun.s16     d4, q12
500    vqmovun.s16     d5, q13
501    vqmovun.s16     d6, q14
502    vqmovun.s16     d7, q15
503
504    ; store the data
505    vst1.64         {d0}, [r0], r2
506    vst1.64         {d1}, [r0], r2
507    vst1.64         {d2}, [r0], r2
508    vst1.64         {d3}, [r0], r2
509    vst1.64         {d4}, [r0], r2
510    vst1.64         {d5}, [r0], r2
511    vst1.64         {d6}, [r0], r2
512    vst1.64         {d7}, [r0], r2
513
514    vpop            {d8-d15}
515    pop             {r4-r9}
516    bx              lr
517    ENDP  ; |vp9_idct8x8_12_add_neon|
518
519    END
520