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