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