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  |vpx_lpf_horizontal_16_neon|
12    EXPORT  |vpx_lpf_horizontal_16_dual_neon|
13    EXPORT  |vpx_lpf_vertical_16_neon|
14    EXPORT  |vpx_lpf_vertical_16_dual_neon|
15    ARM
16
17    AREA ||.text||, CODE, READONLY, ALIGN=2
18
19; void mb_lpf_horizontal_edge(uint8_t *s, int p,
20;                             const uint8_t *blimit,
21;                             const uint8_t *limit,
22;                             const uint8_t *thresh,
23;                             int count)
24; r0    uint8_t *s,
25; r1    int p, /* pitch */
26; r2    const uint8_t *blimit,
27; r3    const uint8_t *limit,
28; sp    const uint8_t *thresh,
29; r12   int count
30|mb_lpf_horizontal_edge| PROC
31    push        {r4-r8, lr}
32    vpush       {d8-d15}
33    ldr         r4, [sp, #88]              ; load thresh
34
35h_count
36    vld1.8      {d16[]}, [r2]              ; load *blimit
37    vld1.8      {d17[]}, [r3]              ; load *limit
38    vld1.8      {d18[]}, [r4]              ; load *thresh
39
40    sub         r8, r0, r1, lsl #3         ; move src pointer down by 8 lines
41
42    vld1.u8     {d0}, [r8@64], r1          ; p7
43    vld1.u8     {d1}, [r8@64], r1          ; p6
44    vld1.u8     {d2}, [r8@64], r1          ; p5
45    vld1.u8     {d3}, [r8@64], r1          ; p4
46    vld1.u8     {d4}, [r8@64], r1          ; p3
47    vld1.u8     {d5}, [r8@64], r1          ; p2
48    vld1.u8     {d6}, [r8@64], r1          ; p1
49    vld1.u8     {d7}, [r8@64], r1          ; p0
50    vld1.u8     {d8}, [r8@64], r1          ; q0
51    vld1.u8     {d9}, [r8@64], r1          ; q1
52    vld1.u8     {d10}, [r8@64], r1         ; q2
53    vld1.u8     {d11}, [r8@64], r1         ; q3
54    vld1.u8     {d12}, [r8@64], r1         ; q4
55    vld1.u8     {d13}, [r8@64], r1         ; q5
56    vld1.u8     {d14}, [r8@64], r1         ; q6
57    vld1.u8     {d15}, [r8@64], r1         ; q7
58
59    bl          vpx_wide_mbfilter_neon
60
61    tst         r7, #1
62    beq         h_mbfilter
63
64    ; flat && mask were not set for any of the channels. Just store the values
65    ; from filter.
66    sub         r8, r0, r1, lsl #1
67
68    vst1.u8     {d25}, [r8@64], r1         ; store op1
69    vst1.u8     {d24}, [r8@64], r1         ; store op0
70    vst1.u8     {d23}, [r8@64], r1         ; store oq0
71    vst1.u8     {d26}, [r8@64], r1         ; store oq1
72
73    b           h_next
74
75h_mbfilter
76    tst         r7, #2
77    beq         h_wide_mbfilter
78
79    ; flat2 was not set for any of the channels. Just store the values from
80    ; mbfilter.
81    sub         r8, r0, r1, lsl #1
82    sub         r8, r8, r1
83
84    vst1.u8     {d18}, [r8@64], r1         ; store op2
85    vst1.u8     {d19}, [r8@64], r1         ; store op1
86    vst1.u8     {d20}, [r8@64], r1         ; store op0
87    vst1.u8     {d21}, [r8@64], r1         ; store oq0
88    vst1.u8     {d22}, [r8@64], r1         ; store oq1
89    vst1.u8     {d23}, [r8@64], r1         ; store oq2
90
91    b           h_next
92
93h_wide_mbfilter
94    sub         r8, r0, r1, lsl #3
95    add         r8, r8, r1
96
97    vst1.u8     {d16}, [r8@64], r1         ; store op6
98    vst1.u8     {d24}, [r8@64], r1         ; store op5
99    vst1.u8     {d25}, [r8@64], r1         ; store op4
100    vst1.u8     {d26}, [r8@64], r1         ; store op3
101    vst1.u8     {d27}, [r8@64], r1         ; store op2
102    vst1.u8     {d18}, [r8@64], r1         ; store op1
103    vst1.u8     {d19}, [r8@64], r1         ; store op0
104    vst1.u8     {d20}, [r8@64], r1         ; store oq0
105    vst1.u8     {d21}, [r8@64], r1         ; store oq1
106    vst1.u8     {d22}, [r8@64], r1         ; store oq2
107    vst1.u8     {d23}, [r8@64], r1         ; store oq3
108    vst1.u8     {d1}, [r8@64], r1          ; store oq4
109    vst1.u8     {d2}, [r8@64], r1          ; store oq5
110    vst1.u8     {d3}, [r8@64], r1          ; store oq6
111
112h_next
113    add         r0, r0, #8
114    subs        r12, r12, #1
115    bne         h_count
116
117    vpop        {d8-d15}
118    pop         {r4-r8, pc}
119
120    ENDP        ; |mb_lpf_horizontal_edge|
121
122; void vpx_lpf_horizontal_16_neon(uint8_t *s, int pitch,
123;                                     const uint8_t *blimit,
124;                                     const uint8_t *limit,
125;                                     const uint8_t *thresh)
126; r0    uint8_t *s,
127; r1    int pitch,
128; r2    const uint8_t *blimit,
129; r3    const uint8_t *limit,
130; sp    const uint8_t *thresh
131|vpx_lpf_horizontal_16_neon| PROC
132    mov r12, #1
133    b mb_lpf_horizontal_edge
134    ENDP        ; |vpx_lpf_horizontal_16_neon|
135
136; void vpx_lpf_horizontal_16_dual_neon(uint8_t *s, int pitch,
137;                                      const uint8_t *blimit,
138;                                      const uint8_t *limit,
139;                                      const uint8_t *thresh)
140; r0    uint8_t *s,
141; r1    int pitch,
142; r2    const uint8_t *blimit,
143; r3    const uint8_t *limit,
144; sp    const uint8_t *thresh
145|vpx_lpf_horizontal_16_dual_neon| PROC
146    mov r12, #2
147    b mb_lpf_horizontal_edge
148    ENDP        ; |vpx_lpf_horizontal_16_dual_neon|
149
150; void mb_lpf_vertical_edge_w(uint8_t *s, int p, const uint8_t *blimit,
151;                             const uint8_t *limit, const uint8_t *thresh,
152;                             int count) {
153; r0    uint8_t *s,
154; r1    int p, /* pitch */
155; r2    const uint8_t *blimit,
156; r3    const uint8_t *limit,
157; sp    const uint8_t *thresh,
158; r12   int count
159|mb_lpf_vertical_edge_w| PROC
160    push        {r4-r8, lr}
161    vpush       {d8-d15}
162    ldr         r4, [sp, #88]              ; load thresh
163
164v_count
165    vld1.8      {d16[]}, [r2]              ; load *blimit
166    vld1.8      {d17[]}, [r3]              ; load *limit
167    vld1.8      {d18[]}, [r4]              ; load *thresh
168
169    sub         r8, r0, #8
170
171    vld1.8      {d0}, [r8@64], r1
172    vld1.8      {d8}, [r0@64], r1
173    vld1.8      {d1}, [r8@64], r1
174    vld1.8      {d9}, [r0@64], r1
175    vld1.8      {d2}, [r8@64], r1
176    vld1.8      {d10}, [r0@64], r1
177    vld1.8      {d3}, [r8@64], r1
178    vld1.8      {d11}, [r0@64], r1
179    vld1.8      {d4}, [r8@64], r1
180    vld1.8      {d12}, [r0@64], r1
181    vld1.8      {d5}, [r8@64], r1
182    vld1.8      {d13}, [r0@64], r1
183    vld1.8      {d6}, [r8@64], r1
184    vld1.8      {d14}, [r0@64], r1
185    vld1.8      {d7}, [r8@64], r1
186    vld1.8      {d15}, [r0@64], r1
187
188    sub         r0, r0, r1, lsl #3
189
190    vtrn.32     q0, q2
191    vtrn.32     q1, q3
192    vtrn.32     q4, q6
193    vtrn.32     q5, q7
194
195    vtrn.16     q0, q1
196    vtrn.16     q2, q3
197    vtrn.16     q4, q5
198    vtrn.16     q6, q7
199
200    vtrn.8      d0, d1
201    vtrn.8      d2, d3
202    vtrn.8      d4, d5
203    vtrn.8      d6, d7
204
205    vtrn.8      d8, d9
206    vtrn.8      d10, d11
207    vtrn.8      d12, d13
208    vtrn.8      d14, d15
209
210    bl          vpx_wide_mbfilter_neon
211
212    tst         r7, #1
213    beq         v_mbfilter
214
215    ; flat && mask were not set for any of the channels. Just store the values
216    ; from filter.
217    sub         r0, #2
218
219    vswp        d23, d25
220
221    vst4.8      {d23[0], d24[0], d25[0], d26[0]}, [r0], r1
222    vst4.8      {d23[1], d24[1], d25[1], d26[1]}, [r0], r1
223    vst4.8      {d23[2], d24[2], d25[2], d26[2]}, [r0], r1
224    vst4.8      {d23[3], d24[3], d25[3], d26[3]}, [r0], r1
225    vst4.8      {d23[4], d24[4], d25[4], d26[4]}, [r0], r1
226    vst4.8      {d23[5], d24[5], d25[5], d26[5]}, [r0], r1
227    vst4.8      {d23[6], d24[6], d25[6], d26[6]}, [r0], r1
228    vst4.8      {d23[7], d24[7], d25[7], d26[7]}, [r0], r1
229    add         r0, #2
230
231    b           v_next
232
233v_mbfilter
234    tst         r7, #2
235    beq         v_wide_mbfilter
236
237    ; flat2 was not set for any of the channels. Just store the values from
238    ; mbfilter.
239    sub         r8, r0, #3
240
241    vst3.8      {d18[0], d19[0], d20[0]}, [r8], r1
242    vst3.8      {d21[0], d22[0], d23[0]}, [r0], r1
243    vst3.8      {d18[1], d19[1], d20[1]}, [r8], r1
244    vst3.8      {d21[1], d22[1], d23[1]}, [r0], r1
245    vst3.8      {d18[2], d19[2], d20[2]}, [r8], r1
246    vst3.8      {d21[2], d22[2], d23[2]}, [r0], r1
247    vst3.8      {d18[3], d19[3], d20[3]}, [r8], r1
248    vst3.8      {d21[3], d22[3], d23[3]}, [r0], r1
249    vst3.8      {d18[4], d19[4], d20[4]}, [r8], r1
250    vst3.8      {d21[4], d22[4], d23[4]}, [r0], r1
251    vst3.8      {d18[5], d19[5], d20[5]}, [r8], r1
252    vst3.8      {d21[5], d22[5], d23[5]}, [r0], r1
253    vst3.8      {d18[6], d19[6], d20[6]}, [r8], r1
254    vst3.8      {d21[6], d22[6], d23[6]}, [r0], r1
255    vst3.8      {d18[7], d19[7], d20[7]}, [r8], r1
256    vst3.8      {d21[7], d22[7], d23[7]}, [r0], r1
257
258    b           v_next
259
260v_wide_mbfilter
261    sub         r8, r0, #8
262
263    vtrn.32     d0,  d26
264    vtrn.32     d16, d27
265    vtrn.32     d24, d18
266    vtrn.32     d25, d19
267
268    vtrn.16     d0,  d24
269    vtrn.16     d16, d25
270    vtrn.16     d26, d18
271    vtrn.16     d27, d19
272
273    vtrn.8      d0,  d16
274    vtrn.8      d24, d25
275    vtrn.8      d26, d27
276    vtrn.8      d18, d19
277
278    vtrn.32     d20, d1
279    vtrn.32     d21, d2
280    vtrn.32     d22, d3
281    vtrn.32     d23, d15
282
283    vtrn.16     d20, d22
284    vtrn.16     d21, d23
285    vtrn.16     d1,  d3
286    vtrn.16     d2,  d15
287
288    vtrn.8      d20, d21
289    vtrn.8      d22, d23
290    vtrn.8      d1,  d2
291    vtrn.8      d3,  d15
292
293    vst1.8      {d0}, [r8@64], r1
294    vst1.8      {d20}, [r0@64], r1
295    vst1.8      {d16}, [r8@64], r1
296    vst1.8      {d21}, [r0@64], r1
297    vst1.8      {d24}, [r8@64], r1
298    vst1.8      {d22}, [r0@64], r1
299    vst1.8      {d25}, [r8@64], r1
300    vst1.8      {d23}, [r0@64], r1
301    vst1.8      {d26}, [r8@64], r1
302    vst1.8      {d1}, [r0@64], r1
303    vst1.8      {d27}, [r8@64], r1
304    vst1.8      {d2}, [r0@64], r1
305    vst1.8      {d18}, [r8@64], r1
306    vst1.8      {d3}, [r0@64], r1
307    vst1.8      {d19}, [r8@64], r1
308    vst1.8      {d15}, [r0@64], r1
309
310v_next
311    subs        r12, #1
312    bne         v_count
313
314    vpop        {d8-d15}
315    pop         {r4-r8, pc}
316
317    ENDP        ; |mb_lpf_vertical_edge_w|
318
319; void vpx_lpf_vertical_16_neon(uint8_t *s, int p, const uint8_t *blimit,
320;                               const uint8_t *limit, const uint8_t *thresh)
321; r0    uint8_t *s,
322; r1    int p, /* pitch */
323; r2    const uint8_t *blimit,
324; r3    const uint8_t *limit,
325; sp    const uint8_t *thresh
326|vpx_lpf_vertical_16_neon| PROC
327    mov r12, #1
328    b mb_lpf_vertical_edge_w
329    ENDP        ; |vpx_lpf_vertical_16_neon|
330
331; void vpx_lpf_vertical_16_dual_neon(uint8_t *s, int p, const uint8_t *blimit,
332;                                    const uint8_t *limit,
333;                                    const uint8_t *thresh)
334; r0    uint8_t *s,
335; r1    int p, /* pitch */
336; r2    const uint8_t *blimit,
337; r3    const uint8_t *limit,
338; sp    const uint8_t *thresh
339|vpx_lpf_vertical_16_dual_neon| PROC
340    mov r12, #2
341    b mb_lpf_vertical_edge_w
342    ENDP        ; |vpx_lpf_vertical_16_dual_neon|
343
344; void vpx_wide_mbfilter_neon();
345; This is a helper function for the loopfilters. The invidual functions do the
346; necessary load, transpose (if necessary) and store.
347;
348; r0-r3 PRESERVE
349; d16    blimit
350; d17    limit
351; d18    thresh
352; d0    p7
353; d1    p6
354; d2    p5
355; d3    p4
356; d4    p3
357; d5    p2
358; d6    p1
359; d7    p0
360; d8    q0
361; d9    q1
362; d10   q2
363; d11   q3
364; d12   q4
365; d13   q5
366; d14   q6
367; d15   q7
368|vpx_wide_mbfilter_neon| PROC
369    mov         r7, #0
370
371    ; filter_mask
372    vabd.u8     d19, d4, d5                ; abs(p3 - p2)
373    vabd.u8     d20, d5, d6                ; abs(p2 - p1)
374    vabd.u8     d21, d6, d7                ; abs(p1 - p0)
375    vabd.u8     d22, d9, d8                ; abs(q1 - q0)
376    vabd.u8     d23, d10, d9               ; abs(q2 - q1)
377    vabd.u8     d24, d11, d10              ; abs(q3 - q2)
378
379    ; only compare the largest value to limit
380    vmax.u8     d19, d19, d20              ; max(abs(p3 - p2), abs(p2 - p1))
381    vmax.u8     d20, d21, d22              ; max(abs(p1 - p0), abs(q1 - q0))
382    vmax.u8     d23, d23, d24              ; max(abs(q2 - q1), abs(q3 - q2))
383    vmax.u8     d19, d19, d20
384
385    vabd.u8     d24, d7, d8                ; abs(p0 - q0)
386
387    vmax.u8     d19, d19, d23
388
389    vabd.u8     d23, d6, d9                ; a = abs(p1 - q1)
390    vqadd.u8    d24, d24, d24              ; b = abs(p0 - q0) * 2
391
392    ; abs () > limit
393    vcge.u8     d19, d17, d19
394
395    ; flatmask4
396    vabd.u8     d25, d7, d5                ; abs(p0 - p2)
397    vabd.u8     d26, d8, d10               ; abs(q0 - q2)
398    vabd.u8     d27, d4, d7                ; abs(p3 - p0)
399    vabd.u8     d28, d11, d8               ; abs(q3 - q0)
400
401    ; only compare the largest value to thresh
402    vmax.u8     d25, d25, d26              ; max(abs(p0 - p2), abs(q0 - q2))
403    vmax.u8     d26, d27, d28              ; max(abs(p3 - p0), abs(q3 - q0))
404    vmax.u8     d25, d25, d26
405    vmax.u8     d20, d20, d25
406
407    vshr.u8     d23, d23, #1               ; a = a / 2
408    vqadd.u8    d24, d24, d23              ; a = b + a
409
410    vmov.u8     d30, #1
411    vcge.u8     d24, d16, d24              ; (a > blimit * 2 + limit) * -1
412
413    vcge.u8     d20, d30, d20              ; flat
414
415    vand        d19, d19, d24              ; mask
416
417    ; hevmask
418    vcgt.u8     d21, d21, d18              ; (abs(p1 - p0) > thresh)*-1
419    vcgt.u8     d22, d22, d18              ; (abs(q1 - q0) > thresh)*-1
420    vorr        d21, d21, d22              ; hev
421
422    vand        d16, d20, d19              ; flat && mask
423    vmov        r5, r6, d16
424
425    ; flatmask5(1, p7, p6, p5, p4, p0, q0, q4, q5, q6, q7)
426    vabd.u8     d22, d3, d7                ; abs(p4 - p0)
427    vabd.u8     d23, d12, d8               ; abs(q4 - q0)
428    vabd.u8     d24, d7, d2                ; abs(p0 - p5)
429    vabd.u8     d25, d8, d13               ; abs(q0 - q5)
430    vabd.u8     d26, d1, d7                ; abs(p6 - p0)
431    vabd.u8     d27, d14, d8               ; abs(q6 - q0)
432    vabd.u8     d28, d0, d7                ; abs(p7 - p0)
433    vabd.u8     d29, d15, d8               ; abs(q7 - q0)
434
435    ; only compare the largest value to thresh
436    vmax.u8     d22, d22, d23              ; max(abs(p4 - p0), abs(q4 - q0))
437    vmax.u8     d23, d24, d25              ; max(abs(p0 - p5), abs(q0 - q5))
438    vmax.u8     d24, d26, d27              ; max(abs(p6 - p0), abs(q6 - q0))
439    vmax.u8     d25, d28, d29              ; max(abs(p7 - p0), abs(q7 - q0))
440
441    vmax.u8     d26, d22, d23
442    vmax.u8     d27, d24, d25
443    vmax.u8     d23, d26, d27
444
445    vcge.u8     d18, d30, d23              ; flat2
446
447    vmov.u8     d22, #0x80
448
449    orrs        r5, r5, r6                 ; Check for 0
450    orreq       r7, r7, #1                 ; Only do filter branch
451
452    vand        d17, d18, d16              ; flat2 && flat && mask
453    vmov        r5, r6, d17
454
455    ; mbfilter() function
456
457    ; filter() function
458    ; convert to signed
459    veor        d23, d8, d22               ; qs0
460    veor        d24, d7, d22               ; ps0
461    veor        d25, d6, d22               ; ps1
462    veor        d26, d9, d22               ; qs1
463
464    vmov.u8     d27, #3
465
466    vsub.s8     d28, d23, d24              ; ( qs0 - ps0)
467    vqsub.s8    d29, d25, d26              ; filter = clamp(ps1-qs1)
468    vmull.s8    q15, d28, d27              ; 3 * ( qs0 - ps0)
469    vand        d29, d29, d21              ; filter &= hev
470    vaddw.s8    q15, q15, d29              ; filter + 3 * (qs0 - ps0)
471    vmov.u8     d29, #4
472
473    ; filter = clamp(filter + 3 * ( qs0 - ps0))
474    vqmovn.s16  d28, q15
475
476    vand        d28, d28, d19              ; filter &= mask
477
478    vqadd.s8    d30, d28, d27              ; filter2 = clamp(filter+3)
479    vqadd.s8    d29, d28, d29              ; filter1 = clamp(filter+4)
480    vshr.s8     d30, d30, #3               ; filter2 >>= 3
481    vshr.s8     d29, d29, #3               ; filter1 >>= 3
482
483
484    vqadd.s8    d24, d24, d30              ; op0 = clamp(ps0 + filter2)
485    vqsub.s8    d23, d23, d29              ; oq0 = clamp(qs0 - filter1)
486
487    ; outer tap adjustments: ++filter1 >> 1
488    vrshr.s8    d29, d29, #1
489    vbic        d29, d29, d21              ; filter &= ~hev
490
491    vqadd.s8    d25, d25, d29              ; op1 = clamp(ps1 + filter)
492    vqsub.s8    d26, d26, d29              ; oq1 = clamp(qs1 - filter)
493
494    veor        d24, d24, d22              ; *f_op0 = u^0x80
495    veor        d23, d23, d22              ; *f_oq0 = u^0x80
496    veor        d25, d25, d22              ; *f_op1 = u^0x80
497    veor        d26, d26, d22              ; *f_oq1 = u^0x80
498
499    tst         r7, #1
500    bxne        lr
501
502    orrs        r5, r5, r6                 ; Check for 0
503    orreq       r7, r7, #2                 ; Only do mbfilter branch
504
505    ; mbfilter flat && mask branch
506    ; TODO(fgalligan): Can I decrease the cycles shifting to consective d's
507    ; and using vibt on the q's?
508    vmov.u8     d29, #2
509    vaddl.u8    q15, d7, d8                ; op2 = p0 + q0
510    vmlal.u8    q15, d4, d27               ; op2 = p0 + q0 + p3 * 3
511    vmlal.u8    q15, d5, d29               ; op2 = p0 + q0 + p3 * 3 + p2 * 2
512    vaddl.u8    q10, d4, d5
513    vaddw.u8    q15, d6                    ; op2=p1 + p0 + q0 + p3 * 3 + p2 *2
514    vaddl.u8    q14, d6, d9
515    vqrshrn.u16 d18, q15, #3               ; r_op2
516
517    vsub.i16    q15, q10
518    vaddl.u8    q10, d4, d6
519    vadd.i16    q15, q14
520    vaddl.u8    q14, d7, d10
521    vqrshrn.u16 d19, q15, #3               ; r_op1
522
523    vsub.i16    q15, q10
524    vadd.i16    q15, q14
525    vaddl.u8    q14, d8, d11
526    vqrshrn.u16 d20, q15, #3               ; r_op0
527
528    vsubw.u8    q15, d4                    ; oq0 = op0 - p3
529    vsubw.u8    q15, d7                    ; oq0 -= p0
530    vadd.i16    q15, q14
531    vaddl.u8    q14, d9, d11
532    vqrshrn.u16 d21, q15, #3               ; r_oq0
533
534    vsubw.u8    q15, d5                    ; oq1 = oq0 - p2
535    vsubw.u8    q15, d8                    ; oq1 -= q0
536    vadd.i16    q15, q14
537    vaddl.u8    q14, d10, d11
538    vqrshrn.u16 d22, q15, #3               ; r_oq1
539
540    vsubw.u8    q15, d6                    ; oq2 = oq0 - p1
541    vsubw.u8    q15, d9                    ; oq2 -= q1
542    vadd.i16    q15, q14
543    vqrshrn.u16 d27, q15, #3               ; r_oq2
544
545    ; Filter does not set op2 or oq2, so use p2 and q2.
546    vbif        d18, d5, d16               ; t_op2 |= p2 & ~(flat & mask)
547    vbif        d19, d25, d16              ; t_op1 |= f_op1 & ~(flat & mask)
548    vbif        d20, d24, d16              ; t_op0 |= f_op0 & ~(flat & mask)
549    vbif        d21, d23, d16              ; t_oq0 |= f_oq0 & ~(flat & mask)
550    vbif        d22, d26, d16              ; t_oq1 |= f_oq1 & ~(flat & mask)
551
552    vbit        d23, d27, d16              ; t_oq2 |= r_oq2 & (flat & mask)
553    vbif        d23, d10, d16              ; t_oq2 |= q2 & ~(flat & mask)
554
555    tst         r7, #2
556    bxne        lr
557
558    ; wide_mbfilter flat2 && flat && mask branch
559    vmov.u8     d16, #7
560    vaddl.u8    q15, d7, d8                ; op6 = p0 + q0
561    vaddl.u8    q12, d2, d3
562    vaddl.u8    q13, d4, d5
563    vaddl.u8    q14, d1, d6
564    vmlal.u8    q15, d0, d16               ; op6 += p7 * 3
565    vadd.i16    q12, q13
566    vadd.i16    q15, q14
567    vaddl.u8    q14, d2, d9
568    vadd.i16    q15, q12
569    vaddl.u8    q12, d0, d1
570    vaddw.u8    q15, d1
571    vaddl.u8    q13, d0, d2
572    vadd.i16    q14, q15, q14
573    vqrshrn.u16 d16, q15, #4               ; w_op6
574
575    vsub.i16    q15, q14, q12
576    vaddl.u8    q14, d3, d10
577    vqrshrn.u16 d24, q15, #4               ; w_op5
578
579    vsub.i16    q15, q13
580    vaddl.u8    q13, d0, d3
581    vadd.i16    q15, q14
582    vaddl.u8    q14, d4, d11
583    vqrshrn.u16 d25, q15, #4               ; w_op4
584
585    vadd.i16    q15, q14
586    vaddl.u8    q14, d0, d4
587    vsub.i16    q15, q13
588    vsub.i16    q14, q15, q14
589    vqrshrn.u16 d26, q15, #4               ; w_op3
590
591    vaddw.u8    q15, q14, d5               ; op2 += p2
592    vaddl.u8    q14, d0, d5
593    vaddw.u8    q15, d12                   ; op2 += q4
594    vbif        d26, d4, d17               ; op3 |= p3 & ~(f2 & f & m)
595    vqrshrn.u16 d27, q15, #4               ; w_op2
596
597    vsub.i16    q15, q14
598    vaddl.u8    q14, d0, d6
599    vaddw.u8    q15, d6                    ; op1 += p1
600    vaddw.u8    q15, d13                   ; op1 += q5
601    vbif        d27, d18, d17              ; op2 |= t_op2 & ~(f2 & f & m)
602    vqrshrn.u16 d18, q15, #4               ; w_op1
603
604    vsub.i16    q15, q14
605    vaddl.u8    q14, d0, d7
606    vaddw.u8    q15, d7                    ; op0 += p0
607    vaddw.u8    q15, d14                   ; op0 += q6
608    vbif        d18, d19, d17              ; op1 |= t_op1 & ~(f2 & f & m)
609    vqrshrn.u16 d19, q15, #4               ; w_op0
610
611    vsub.i16    q15, q14
612    vaddl.u8    q14, d1, d8
613    vaddw.u8    q15, d8                    ; oq0 += q0
614    vaddw.u8    q15, d15                   ; oq0 += q7
615    vbif        d19, d20, d17              ; op0 |= t_op0 & ~(f2 & f & m)
616    vqrshrn.u16 d20, q15, #4               ; w_oq0
617
618    vsub.i16    q15, q14
619    vaddl.u8    q14, d2, d9
620    vaddw.u8    q15, d9                    ; oq1 += q1
621    vaddl.u8    q4, d10, d15
622    vaddw.u8    q15, d15                   ; oq1 += q7
623    vbif        d20, d21, d17              ; oq0 |= t_oq0 & ~(f2 & f & m)
624    vqrshrn.u16 d21, q15, #4               ; w_oq1
625
626    vsub.i16    q15, q14
627    vaddl.u8    q14, d3, d10
628    vadd.i16    q15, q4
629    vaddl.u8    q4, d11, d15
630    vbif        d21, d22, d17              ; oq1 |= t_oq1 & ~(f2 & f & m)
631    vqrshrn.u16 d22, q15, #4               ; w_oq2
632
633    vsub.i16    q15, q14
634    vaddl.u8    q14, d4, d11
635    vadd.i16    q15, q4
636    vaddl.u8    q4, d12, d15
637    vbif        d22, d23, d17              ; oq2 |= t_oq2 & ~(f2 & f & m)
638    vqrshrn.u16 d23, q15, #4               ; w_oq3
639
640    vsub.i16    q15, q14
641    vaddl.u8    q14, d5, d12
642    vadd.i16    q15, q4
643    vaddl.u8    q4, d13, d15
644    vbif        d16, d1, d17               ; op6 |= p6 & ~(f2 & f & m)
645    vqrshrn.u16 d1, q15, #4                ; w_oq4
646
647    vsub.i16    q15, q14
648    vaddl.u8    q14, d6, d13
649    vadd.i16    q15, q4
650    vaddl.u8    q4, d14, d15
651    vbif        d24, d2, d17               ; op5 |= p5 & ~(f2 & f & m)
652    vqrshrn.u16 d2, q15, #4                ; w_oq5
653
654    vsub.i16    q15, q14
655    vbif        d25, d3, d17               ; op4 |= p4 & ~(f2 & f & m)
656    vadd.i16    q15, q4
657    vbif        d23, d11, d17              ; oq3 |= q3 & ~(f2 & f & m)
658    vqrshrn.u16 d3, q15, #4                ; w_oq6
659    vbif        d1, d12, d17               ; oq4 |= q4 & ~(f2 & f & m)
660    vbif        d2, d13, d17               ; oq5 |= q5 & ~(f2 & f & m)
661    vbif        d3, d14, d17               ; oq6 |= q6 & ~(f2 & f & m)
662
663    bx          lr
664    ENDP        ; |vpx_wide_mbfilter_neon|
665
666    END
667