1;
2;  Copyright (c) 2010 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
12    EXPORT  |idct_dequant_dc_full_2x_neon|
13    ARM
14    REQUIRE8
15    PRESERVE8
16
17    AREA ||.text||, CODE, READONLY, ALIGN=2
18;void idct_dequant_dc_full_2x_neon(short *q, short *dq, unsigned char *pre,
19;                                  unsigned char *dst, int stride, short *dc);
20; r0    *q,
21; r1    *dq,
22; r2    *pre
23; r3    *dst
24; sp    stride
25; sp+4  *dc
26|idct_dequant_dc_full_2x_neon| PROC
27    vld1.16         {q0, q1}, [r1]          ; dq (same l/r)
28    vld1.16         {q2, q3}, [r0]          ; l q
29    mov             r1, #16                 ; pitch
30    add             r0, r0, #32
31    vld1.16         {q4, q5}, [r0]          ; r q
32    add             r12, r2, #4
33    ; interleave the predictors
34    vld1.32         {d28[0]}, [r2], r1      ; l pre
35    vld1.32         {d28[1]}, [r12], r1     ; r pre
36    vld1.32         {d29[0]}, [r2], r1
37    vld1.32         {d29[1]}, [r12], r1
38    vld1.32         {d30[0]}, [r2], r1
39    vld1.32         {d30[1]}, [r12], r1
40    vld1.32         {d31[0]}, [r2]
41    ldr             r1, [sp, #4]
42    vld1.32         {d31[1]}, [r12]
43
44    ldr             r2, _CONSTANTS_
45
46    ldrh            r12, [r1], #2           ; lo *dc
47    ldrh            r1, [r1]                ; hi *dc
48
49    ; dequant: q[i] = q[i] * dq[i]
50    vmul.i16        q2, q2, q0
51    vmul.i16        q3, q3, q1
52    vmul.i16        q4, q4, q0
53    vmul.i16        q5, q5, q1
54
55    ; move dc up to neon and overwrite first element
56    vmov.16         d4[0], r12
57    vmov.16         d8[0], r1
58
59    vld1.16         {d0}, [r2]
60
61    ; q2: l0r0  q3: l8r8
62    ; q4: l4r4  q5: l12r12
63    vswp            d5, d8
64    vswp            d7, d10
65
66    ; _CONSTANTS_ * 4,12 >> 16
67    ; q6:  4 * sinpi : c1/temp1
68    ; q7: 12 * sinpi : d1/temp2
69    ; q8:  4 * cospi
70    ; q9: 12 * cospi
71    vqdmulh.s16     q6, q4, d0[2]           ; sinpi8sqrt2
72    vqdmulh.s16     q7, q5, d0[2]
73    vqdmulh.s16     q8, q4, d0[0]           ; cospi8sqrt2minus1
74    vqdmulh.s16     q9, q5, d0[0]
75
76    vqadd.s16       q10, q2, q3             ; a1 = 0 + 8
77    vqsub.s16       q11, q2, q3             ; b1 = 0 - 8
78
79    ; vqdmulh only accepts signed values. this was a problem because
80    ; our constant had the high bit set, and was treated as a negative value.
81    ; vqdmulh also doubles the value before it shifts by 16. we need to
82    ; compensate for this. in the case of sinpi8sqrt2, the lowest bit is 0,
83    ; so we can shift the constant without losing precision. this avoids
84    ; shift again afterward, but also avoids the sign issue. win win!
85    ; for cospi8sqrt2minus1 the lowest bit is 1, so we lose precision if we
86    ; pre-shift it
87    vshr.s16        q8, q8, #1
88    vshr.s16        q9, q9, #1
89
90    ; q4:  4 +  4 * cospi : d1/temp1
91    ; q5: 12 + 12 * cospi : c1/temp2
92    vqadd.s16       q4, q4, q8
93    vqadd.s16       q5, q5, q9
94
95    ; c1 = temp1 - temp2
96    ; d1 = temp1 + temp2
97    vqsub.s16       q2, q6, q5
98    vqadd.s16       q3, q4, q7
99
100    ; [0]: a1+d1
101    ; [1]: b1+c1
102    ; [2]: b1-c1
103    ; [3]: a1-d1
104    vqadd.s16       q4, q10, q3
105    vqadd.s16       q5, q11, q2
106    vqsub.s16       q6, q11, q2
107    vqsub.s16       q7, q10, q3
108
109    ; rotate
110    vtrn.32         q4, q6
111    vtrn.32         q5, q7
112    vtrn.16         q4, q5
113    vtrn.16         q6, q7
114    ; idct loop 2
115    ; q4: l 0, 4, 8,12 r 0, 4, 8,12
116    ; q5: l 1, 5, 9,13 r 1, 5, 9,13
117    ; q6: l 2, 6,10,14 r 2, 6,10,14
118    ; q7: l 3, 7,11,15 r 3, 7,11,15
119
120    ; q8:  1 * sinpi : c1/temp1
121    ; q9:  3 * sinpi : d1/temp2
122    ; q10: 1 * cospi
123    ; q11: 3 * cospi
124    vqdmulh.s16     q8, q5, d0[2]           ; sinpi8sqrt2
125    vqdmulh.s16     q9, q7, d0[2]
126    vqdmulh.s16     q10, q5, d0[0]          ; cospi8sqrt2minus1
127    vqdmulh.s16     q11, q7, d0[0]
128
129    vqadd.s16       q2, q4, q6             ; a1 = 0 + 2
130    vqsub.s16       q3, q4, q6             ; b1 = 0 - 2
131
132    ; see note on shifting above
133    vshr.s16        q10, q10, #1
134    vshr.s16        q11, q11, #1
135
136    ; q10: 1 + 1 * cospi : d1/temp1
137    ; q11: 3 + 3 * cospi : c1/temp2
138    vqadd.s16       q10, q5, q10
139    vqadd.s16       q11, q7, q11
140
141    ; q8: c1 = temp1 - temp2
142    ; q9: d1 = temp1 + temp2
143    vqsub.s16       q8, q8, q11
144    vqadd.s16       q9, q10, q9
145
146    ; a1+d1
147    ; b1+c1
148    ; b1-c1
149    ; a1-d1
150    vqadd.s16       q4, q2, q9
151    vqadd.s16       q5, q3, q8
152    vqsub.s16       q6, q3, q8
153    vqsub.s16       q7, q2, q9
154
155    ; +4 >> 3 (rounding)
156    vrshr.s16       q4, q4, #3              ; lo
157    vrshr.s16       q5, q5, #3
158    vrshr.s16       q6, q6, #3              ; hi
159    vrshr.s16       q7, q7, #3
160
161    vtrn.32         q4, q6
162    vtrn.32         q5, q7
163    vtrn.16         q4, q5
164    vtrn.16         q6, q7
165
166    ; adding pre
167    ; input is still packed. pre was read interleaved
168    vaddw.u8        q4, q4, d28
169    vaddw.u8        q5, q5, d29
170    vaddw.u8        q6, q6, d30
171    vaddw.u8        q7, q7, d31
172
173    vmov.i16        q14, #0
174    vmov            q15, q14
175    vst1.16         {q14, q15}, [r0]        ; write over high input
176    sub             r0, r0, #32
177    vst1.16         {q14, q15}, [r0]        ; write over low input
178
179    ;saturate and narrow
180    vqmovun.s16     d0, q4                  ; lo
181    vqmovun.s16     d1, q5
182    vqmovun.s16     d2, q6                  ; hi
183    vqmovun.s16     d3, q7
184
185    ldr             r1, [sp]                ; stride
186    add             r2, r3, #4              ; hi
187    vst1.32         {d0[0]}, [r3], r1       ; lo
188    vst1.32         {d0[1]}, [r2], r1       ; hi
189    vst1.32         {d1[0]}, [r3], r1
190    vst1.32         {d1[1]}, [r2], r1
191    vst1.32         {d2[0]}, [r3], r1
192    vst1.32         {d2[1]}, [r2], r1
193    vst1.32         {d3[0]}, [r3]
194    vst1.32         {d3[1]}, [r2]
195
196    bx             lr
197
198    ENDP           ; |idct_dequant_dc_full_2x_neon|
199
200; Constant Pool
201_CONSTANTS_       DCD cospi8sqrt2minus1
202cospi8sqrt2minus1 DCD 0x4e7b
203; because the lowest bit in 0x8a8c is 0, we can pre-shift this
204sinpi8sqrt2       DCD 0x4546
205
206    END
207