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