1 2/* filter_neon.S - NEON optimised filter functions 3 * 4 * Copyright (c) 2014,2017 Glenn Randers-Pehrson 5 * Written by Mans Rullgard, 2011. 6 * Last changed in libpng 1.6.31 [July 27, 2017] 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 PNG_READ_SUPPORTED 24 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: 29 */ 30#if PNG_ARM_NEON_IMPLEMENTATION == 2 /* hand-coded assembler */ 31 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 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. 54 */ 55 .align 2 56 57 .if \export 58 .global \name 59 .endif 60ELF .type \name, STT_FUNC 61 .func \name 62\name: 63.endm 64 65func png_read_filter_row_sub4_neon, export=1 66 ldr r3, [r0, #4] @ rowbytes 67 vmov.i8 d3, #0 681: 69 vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128] 70 vadd.u8 d0, d3, d4 71 vadd.u8 d1, d0, d5 72 vadd.u8 d2, d1, d6 73 vadd.u8 d3, d2, d7 74 vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]! 75 subs r3, r3, #16 76 bgt 1b 77 78 bx lr 79endfunc 80 81func png_read_filter_row_sub3_neon, export=1 82 ldr r3, [r0, #4] @ rowbytes 83 vmov.i8 d3, #0 84 mov r0, r1 85 mov r2, #3 86 mov r12, #12 87 vld1.8 {q11}, [r0], r12 881: 89 vext.8 d5, d22, d23, #3 90 vadd.u8 d0, d3, d22 91 vext.8 d6, d22, d23, #6 92 vadd.u8 d1, d0, d5 93 vext.8 d7, d23, d23, #1 94 vld1.8 {q11}, [r0], r12 95 vst1.32 {d0[0]}, [r1,:32], r2 96 vadd.u8 d2, d1, d6 97 vst1.32 {d1[0]}, [r1], r2 98 vadd.u8 d3, d2, d7 99 vst1.32 {d2[0]}, [r1], r2 100 vst1.32 {d3[0]}, [r1], r2 101 subs r3, r3, #12 102 bgt 1b 103 104 bx lr 105endfunc 106 107func png_read_filter_row_up_neon, export=1 108 ldr r3, [r0, #4] @ rowbytes 1091: 110 vld1.8 {q0}, [r1,:128] 111 vld1.8 {q1}, [r2,:128]! 112 vadd.u8 q0, q0, q1 113 vst1.8 {q0}, [r1,:128]! 114 subs r3, r3, #16 115 bgt 1b 116 117 bx lr 118endfunc 119 120func png_read_filter_row_avg4_neon, export=1 121 ldr r12, [r0, #4] @ rowbytes 122 vmov.i8 d3, #0 1231: 124 vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128] 125 vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]! 126 vhadd.u8 d0, d3, d16 127 vadd.u8 d0, d0, d4 128 vhadd.u8 d1, d0, d17 129 vadd.u8 d1, d1, d5 130 vhadd.u8 d2, d1, d18 131 vadd.u8 d2, d2, d6 132 vhadd.u8 d3, d2, d19 133 vadd.u8 d3, d3, d7 134 vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]! 135 subs r12, r12, #16 136 bgt 1b 137 138 bx lr 139endfunc 140 141func png_read_filter_row_avg3_neon, export=1 142 push {r4,lr} 143 ldr r12, [r0, #4] @ rowbytes 144 vmov.i8 d3, #0 145 mov r0, r1 146 mov r4, #3 147 mov lr, #12 148 vld1.8 {q11}, [r0], lr 1491: 150 vld1.8 {q10}, [r2], lr 151 vext.8 d5, d22, d23, #3 152 vhadd.u8 d0, d3, d20 153 vext.8 d17, d20, d21, #3 154 vadd.u8 d0, d0, d22 155 vext.8 d6, d22, d23, #6 156 vhadd.u8 d1, d0, d17 157 vext.8 d18, d20, d21, #6 158 vadd.u8 d1, d1, d5 159 vext.8 d7, d23, d23, #1 160 vld1.8 {q11}, [r0], lr 161 vst1.32 {d0[0]}, [r1,:32], r4 162 vhadd.u8 d2, d1, d18 163 vst1.32 {d1[0]}, [r1], r4 164 vext.8 d19, d21, d21, #1 165 vadd.u8 d2, d2, d6 166 vhadd.u8 d3, d2, d19 167 vst1.32 {d2[0]}, [r1], r4 168 vadd.u8 d3, d3, d7 169 vst1.32 {d3[0]}, [r1], r4 170 subs r12, r12, #12 171 bgt 1b 172 173 pop {r4,pc} 174endfunc 175 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 186 vmovn.u16 d28, q14 187 vmovn.u16 \rx, q12 188 vbsl d28, \rb, \rc 189 vbsl \rx, \ra, d28 190.endm 191 192func png_read_filter_row_paeth4_neon, export=1 193 ldr r12, [r0, #4] @ rowbytes 194 vmov.i8 d3, #0 195 vmov.i8 d20, #0 1961: 197 vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128] 198 vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]! 199 paeth d0, d3, d16, d20 200 vadd.u8 d0, d0, d4 201 paeth d1, d0, d17, d16 202 vadd.u8 d1, d1, d5 203 paeth d2, d1, d18, d17 204 vadd.u8 d2, d2, d6 205 paeth d3, d2, d19, d18 206 vmov d20, d19 207 vadd.u8 d3, d3, d7 208 vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]! 209 subs r12, r12, #16 210 bgt 1b 211 212 bx lr 213endfunc 214 215func png_read_filter_row_paeth3_neon, export=1 216 push {r4,lr} 217 ldr r12, [r0, #4] @ rowbytes 218 vmov.i8 d3, #0 219 vmov.i8 d4, #0 220 mov r0, r1 221 mov r4, #3 222 mov lr, #12 223 vld1.8 {q11}, [r0], lr 2241: 225 vld1.8 {q10}, [r2], lr 226 paeth d0, d3, d20, d4 227 vext.8 d5, d22, d23, #3 228 vadd.u8 d0, d0, d22 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 233 vadd.u8 d1, d1, d5 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 239 vadd.u8 d2, d2, d6 240 vext.8 d19, d21, d21, #1 241 paeth d3, d2, d19, d18 242 vst1.32 {d2[0]}, [r1], r4 243 vmov d4, d19 244 vadd.u8 d3, d3, d7 245 vst1.32 {d3[0]}, [r1], r4 246 subs r12, r12, #12 247 bgt 1b 248 249 pop {r4,pc} 250endfunc 251#endif /* PNG_ARM_NEON_OPT > 0 */ 252#endif /* PNG_ARM_NEON_IMPLEMENTATION == 2 (assembler) */ 253#endif /* READ */ 254