1
2/* filter_neon.S - NEON optimised filter functions
3 *
4 * Copyright (c) 2013 Glenn Randers-Pehrson
5 * Written by Mans Rullgard, 2011.
6 * Last changed in libpng 1.6.8 [December 19, 2013]
7 *
8 * This code is released under the libpng license.
9 * For conditions of distribution and use, see the disclaimer
10 * and license in png.h
11 */
12
13/* This is required to get the symbol renames, which are #defines, and also
14 * includes the definition (or not) of PNG_ARM_NEON_OPT and
15 * PNG_ARM_NEON_IMPLEMENTATION.
16 */
17#define PNG_VERSION_INFO_ONLY
18#include "../pngpriv.h"
19
20#if defined(__linux__) && defined(__ELF__)
21.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
22#endif
23
24/* Assembler NEON support - only works for 32-bit ARM (i.e. it does not work for
25 * ARM64).  The code in arm/filter_neon_intrinsics.c supports ARM64, however it
26 * only works if -mfpu=neon is specified on the GCC command line.  See pngpriv.h
27 * for the logic which sets PNG_USE_ARM_NEON_ASM:
28 */
29#if PNG_ARM_NEON_IMPLEMENTATION == 2 /* hand-coded assembler */
30
31#ifdef PNG_READ_SUPPORTED
32#if PNG_ARM_NEON_OPT > 0
33
34#ifdef __ELF__
35#   define ELF
36#else
37#   define ELF @
38#endif
39
40        .arch armv7-a
41        .fpu  neon
42
43.macro  func    name, export=0
44    .macro endfunc
45ELF     .size   \name, . - \name
46        .endfunc
47        .purgem endfunc
48    .endm
49        .text
50    .if \export
51        .global \name
52    .endif
53ELF     .type   \name, STT_FUNC
54        .func   \name
55\name:
56.endm
57
58func    png_read_filter_row_sub4_neon, export=1
59        ldr             r3,  [r0, #4]           @ rowbytes
60        vmov.i8         d3,  #0
611:
62        vld4.32         {d4[],d5[],d6[],d7[]},    [r1,:128]
63        vadd.u8         d0,  d3,  d4
64        vadd.u8         d1,  d0,  d5
65        vadd.u8         d2,  d1,  d6
66        vadd.u8         d3,  d2,  d7
67        vst4.32         {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
68        subs            r3,  r3,  #16
69        bgt             1b
70
71        bx              lr
72endfunc
73
74func    png_read_filter_row_sub3_neon, export=1
75        ldr             r3,  [r0, #4]           @ rowbytes
76        vmov.i8         d3,  #0
77        mov             r0,  r1
78        mov             r2,  #3
79        mov             r12, #12
80        vld1.8          {q11},    [r0], r12
811:
82        vext.8          d5,  d22, d23, #3
83        vadd.u8         d0,  d3,  d22
84        vext.8          d6,  d22, d23, #6
85        vadd.u8         d1,  d0,  d5
86        vext.8          d7,  d23, d23, #1
87        vld1.8          {q11},    [r0], r12
88        vst1.32         {d0[0]},  [r1,:32], r2
89        vadd.u8         d2,  d1,  d6
90        vst1.32         {d1[0]},  [r1], r2
91        vadd.u8         d3,  d2,  d7
92        vst1.32         {d2[0]},  [r1], r2
93        vst1.32         {d3[0]},  [r1], r2
94        subs            r3,  r3,  #12
95        bgt             1b
96
97        bx              lr
98endfunc
99
100func    png_read_filter_row_up_neon, export=1
101        ldr             r3,  [r0, #4]           @ rowbytes
1021:
103        vld1.8          {q0}, [r1,:128]
104        vld1.8          {q1}, [r2,:128]!
105        vadd.u8         q0,  q0,  q1
106        vst1.8          {q0}, [r1,:128]!
107        subs            r3,  r3,  #16
108        bgt             1b
109
110        bx              lr
111endfunc
112
113func    png_read_filter_row_avg4_neon, export=1
114        ldr             r12, [r0, #4]           @ rowbytes
115        vmov.i8         d3,  #0
1161:
117        vld4.32         {d4[],d5[],d6[],d7[]},    [r1,:128]
118        vld4.32         {d16[],d17[],d18[],d19[]},[r2,:128]!
119        vhadd.u8        d0,  d3,  d16
120        vadd.u8         d0,  d0,  d4
121        vhadd.u8        d1,  d0,  d17
122        vadd.u8         d1,  d1,  d5
123        vhadd.u8        d2,  d1,  d18
124        vadd.u8         d2,  d2,  d6
125        vhadd.u8        d3,  d2,  d19
126        vadd.u8         d3,  d3,  d7
127        vst4.32         {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
128        subs            r12, r12, #16
129        bgt             1b
130
131        bx              lr
132endfunc
133
134func    png_read_filter_row_avg3_neon, export=1
135        push            {r4,lr}
136        ldr             r12, [r0, #4]           @ rowbytes
137        vmov.i8         d3,  #0
138        mov             r0,  r1
139        mov             r4,  #3
140        mov             lr,  #12
141        vld1.8          {q11},    [r0], lr
1421:
143        vld1.8          {q10},    [r2], lr
144        vext.8          d5,  d22, d23, #3
145        vhadd.u8        d0,  d3,  d20
146        vext.8          d17, d20, d21, #3
147        vadd.u8         d0,  d0,  d22
148        vext.8          d6,  d22, d23, #6
149        vhadd.u8        d1,  d0,  d17
150        vext.8          d18, d20, d21, #6
151        vadd.u8         d1,  d1,  d5
152        vext.8          d7,  d23, d23, #1
153        vld1.8          {q11},    [r0], lr
154        vst1.32         {d0[0]},  [r1,:32], r4
155        vhadd.u8        d2,  d1,  d18
156        vst1.32         {d1[0]},  [r1], r4
157        vext.8          d19, d21, d21, #1
158        vadd.u8         d2,  d2,  d6
159        vhadd.u8        d3,  d2,  d19
160        vst1.32         {d2[0]},  [r1], r4
161        vadd.u8         d3,  d3,  d7
162        vst1.32         {d3[0]},  [r1], r4
163        subs            r12, r12, #12
164        bgt             1b
165
166        pop             {r4,pc}
167endfunc
168
169.macro  paeth           rx,  ra,  rb,  rc
170        vaddl.u8        q12, \ra, \rb           @ a + b
171        vaddl.u8        q15, \rc, \rc           @ 2*c
172        vabdl.u8        q13, \rb, \rc           @ pa
173        vabdl.u8        q14, \ra, \rc           @ pb
174        vabd.u16        q15, q12, q15           @ pc
175        vcle.u16        q12, q13, q14           @ pa <= pb
176        vcle.u16        q13, q13, q15           @ pa <= pc
177        vcle.u16        q14, q14, q15           @ pb <= pc
178        vand            q12, q12, q13           @ pa <= pb && pa <= pc
179        vmovn.u16       d28, q14
180        vmovn.u16       \rx, q12
181        vbsl            d28, \rb, \rc
182        vbsl            \rx, \ra, d28
183.endm
184
185func    png_read_filter_row_paeth4_neon, export=1
186        ldr             r12, [r0, #4]           @ rowbytes
187        vmov.i8         d3,  #0
188        vmov.i8         d20, #0
1891:
190        vld4.32         {d4[],d5[],d6[],d7[]},    [r1,:128]
191        vld4.32         {d16[],d17[],d18[],d19[]},[r2,:128]!
192        paeth           d0,  d3,  d16, d20
193        vadd.u8         d0,  d0,  d4
194        paeth           d1,  d0,  d17, d16
195        vadd.u8         d1,  d1,  d5
196        paeth           d2,  d1,  d18, d17
197        vadd.u8         d2,  d2,  d6
198        paeth           d3,  d2,  d19, d18
199        vmov            d20, d19
200        vadd.u8         d3,  d3,  d7
201        vst4.32         {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
202        subs            r12, r12, #16
203        bgt             1b
204
205        bx              lr
206endfunc
207
208func    png_read_filter_row_paeth3_neon, export=1
209        push            {r4,lr}
210        ldr             r12, [r0, #4]           @ rowbytes
211        vmov.i8         d3,  #0
212        vmov.i8         d4,  #0
213        mov             r0,  r1
214        mov             r4,  #3
215        mov             lr,  #12
216        vld1.8          {q11},    [r0], lr
2171:
218        vld1.8          {q10},    [r2], lr
219        paeth           d0,  d3,  d20, d4
220        vext.8          d5,  d22, d23, #3
221        vadd.u8         d0,  d0,  d22
222        vext.8          d17, d20, d21, #3
223        paeth           d1,  d0,  d17, d20
224        vst1.32         {d0[0]},  [r1,:32], r4
225        vext.8          d6,  d22, d23, #6
226        vadd.u8         d1,  d1,  d5
227        vext.8          d18, d20, d21, #6
228        paeth           d2,  d1,  d18, d17
229        vext.8          d7,  d23, d23, #1
230        vld1.8          {q11},    [r0], lr
231        vst1.32         {d1[0]},  [r1], r4
232        vadd.u8         d2,  d2,  d6
233        vext.8          d19, d21, d21, #1
234        paeth           d3,  d2,  d19, d18
235        vst1.32         {d2[0]},  [r1], r4
236        vmov            d4,  d19
237        vadd.u8         d3,  d3,  d7
238        vst1.32         {d3[0]},  [r1], r4
239        subs            r12, r12, #12
240        bgt             1b
241
242        pop             {r4,pc}
243endfunc
244#endif /* PNG_ARM_NEON_OPT > 0 */
245#endif /* PNG_READ_SUPPORTED */
246#endif /* PNG_ARM_NEON_IMPLEMENTATION == 2 (assembler) */
247