2 /* filter_neon.S - NEON optimised filter functions
4 * Copyright (c) 2018 Cosmin Truta
5 * Copyright (c) 2014,2017 Glenn Randers-Pehrson
6 * Written by Mans Rullgard, 2011.
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
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.
16 #define PNG_VERSION_INFO_ONLY
17 #include "../pngpriv.h"
19 #if (defined(__linux__) || defined(__FreeBSD__)) && defined(__ELF__)
20 .section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
23 #ifdef PNG_READ_SUPPORTED
25 /* Assembler NEON support - only works for 32-bit ARM (i.e. it does not work for
26 * ARM64). The code in arm/filter_neon_intrinsics.c supports ARM64, however it
27 * only works if -mfpu=neon is specified on the GCC command line. See pngpriv.h
28 * for the logic which sets PNG_USE_ARM_NEON_ASM:
30 #if PNG_ARM_NEON_IMPLEMENTATION == 2 /* hand-coded assembler */
32 #if PNG_ARM_NEON_OPT > 0
43 .macro func name, export=0
45 ELF .size \name, . - \name
51 /* Explicitly specifying alignment here because some versions of
52 * GAS don't align code correctly. This is harmless in correctly
53 * written versions of GAS.
60 ELF .type \name, STT_FUNC
65 func png_read_filter_row_sub4_neon, export=1
66 ldr r3, [r0, #4] @ rowbytes
69 vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
74 vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
81 func png_read_filter_row_sub3_neon, export=1
82 ldr r3, [r0, #4] @ rowbytes
87 vld1.8 {q11}, [r0], r12
89 vext.8 d5, d22, d23, #3
91 vext.8 d6, d22, d23, #6
93 vext.8 d7, d23, d23, #1
94 vld1.8 {q11}, [r0], r12
95 vst1.32 {d0[0]}, [r1,:32], r2
97 vst1.32 {d1[0]}, [r1], r2
99 vst1.32 {d2[0]}, [r1], r2
100 vst1.32 {d3[0]}, [r1], r2
107 func png_read_filter_row_up_neon, export=1
108 ldr r3, [r0, #4] @ rowbytes
110 vld1.8 {q0}, [r1,:128]
111 vld1.8 {q1}, [r2,:128]!
113 vst1.8 {q0}, [r1,:128]!
120 func png_read_filter_row_avg4_neon, export=1
121 ldr r12, [r0, #4] @ rowbytes
124 vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
125 vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]!
134 vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
141 func png_read_filter_row_avg3_neon, export=1
143 ldr r12, [r0, #4] @ rowbytes
148 vld1.8 {q11}, [r0], lr
150 vld1.8 {q10}, [r2], lr
151 vext.8 d5, d22, d23, #3
153 vext.8 d17, d20, d21, #3
155 vext.8 d6, d22, d23, #6
157 vext.8 d18, d20, d21, #6
159 vext.8 d7, d23, d23, #1
160 vld1.8 {q11}, [r0], lr
161 vst1.32 {d0[0]}, [r1,:32], r4
163 vst1.32 {d1[0]}, [r1], r4
164 vext.8 d19, d21, d21, #1
167 vst1.32 {d2[0]}, [r1], r4
169 vst1.32 {d3[0]}, [r1], r4
176 .macro paeth rx, ra, rb, rc
177 vaddl.u8 q12, \ra, \rb @ a + b
178 vaddl.u8 q15, \rc, \rc @ 2*c
179 vabdl.u8 q13, \rb, \rc @ pa
180 vabdl.u8 q14, \ra, \rc @ pb
181 vabd.u16 q15, q12, q15 @ pc
182 vcle.u16 q12, q13, q14 @ pa <= pb
183 vcle.u16 q13, q13, q15 @ pa <= pc
184 vcle.u16 q14, q14, q15 @ pb <= pc
185 vand q12, q12, q13 @ pa <= pb && pa <= pc
192 func png_read_filter_row_paeth4_neon, export=1
193 ldr r12, [r0, #4] @ rowbytes
197 vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
198 vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]!
199 paeth d0, d3, d16, d20
201 paeth d1, d0, d17, d16
203 paeth d2, d1, d18, d17
205 paeth d3, d2, d19, d18
208 vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
215 func png_read_filter_row_paeth3_neon, export=1
217 ldr r12, [r0, #4] @ rowbytes
223 vld1.8 {q11}, [r0], lr
225 vld1.8 {q10}, [r2], lr
226 paeth d0, d3, d20, d4
227 vext.8 d5, d22, d23, #3
229 vext.8 d17, d20, d21, #3
230 paeth d1, d0, d17, d20
231 vst1.32 {d0[0]}, [r1,:32], r4
232 vext.8 d6, d22, d23, #6
234 vext.8 d18, d20, d21, #6
235 paeth d2, d1, d18, d17
236 vext.8 d7, d23, d23, #1
237 vld1.8 {q11}, [r0], lr
238 vst1.32 {d1[0]}, [r1], r4
240 vext.8 d19, d21, d21, #1
241 paeth d3, d2, d19, d18
242 vst1.32 {d2[0]}, [r1], r4
245 vst1.32 {d3[0]}, [r1], r4
251 #endif /* PNG_ARM_NEON_OPT > 0 */
252 #endif /* PNG_ARM_NEON_IMPLEMENTATION == 2 (assembler) */