aboutsummaryrefslogtreecommitdiffstats
path: root/package/libs/zlib/patches/001-neon-implementation-of-adler32.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/libs/zlib/patches/001-neon-implementation-of-adler32.patch')
-rw-r--r--package/libs/zlib/patches/001-neon-implementation-of-adler32.patch253
1 files changed, 253 insertions, 0 deletions
diff --git a/package/libs/zlib/patches/001-neon-implementation-of-adler32.patch b/package/libs/zlib/patches/001-neon-implementation-of-adler32.patch
new file mode 100644
index 0000000000..843ef45c7d
--- /dev/null
+++ b/package/libs/zlib/patches/001-neon-implementation-of-adler32.patch
@@ -0,0 +1,253 @@
+From d2f06cd65d7ac39c6dd6761eef162abc946b155b Mon Sep 17 00:00:00 2001
+From: Adenilson Cavalcanti <adenilson.cavalcanti@arm.com>
+Date: Tue, 11 Apr 2017 17:13:02 -0700
+Subject: [PATCH] NEON implementation for Adler32
+
+The checksum is calculated in the uncompressed PNG data
+and can be made much faster by using SIMD.
+
+Tests in ARMv8 yielded an improvement of about 3x
+(e.g. walltime was 350ms x 125ms for a 4096x4096 bytes
+executed 30 times). That results in at least 18% improvement
+in image decoding in Chromium.
+
+Further details at:
+https://bugs.chromium.org/p/chromium/issues/detail?id=688601
+---
+ CMakeLists.txt | 29 +++++++---
+ adler32.c | 5 ++
+ contrib/README.contrib | 3 +
+ contrib/arm/neon_adler32.c | 137 +++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 166 insertions(+), 8 deletions(-)
+ create mode 100644 contrib/arm/neon_adler32.c
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 0fe939df..8e75f664 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -7,6 +7,7 @@ set(VERSION "1.2.11")
+
+ option(ASM686 "Enable building i686 assembly implementation")
+ option(AMD64 "Enable building amd64 assembly implementation")
++option(ARMv8 "Enable building ARM NEON intrinsics implementation")
+
+ set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
+ set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
+@@ -132,14 +133,26 @@ endif()
+ if(CMAKE_COMPILER_IS_GNUCC)
+ if(ASM686)
+ set(ZLIB_ASMS contrib/asm686/match.S)
+- elseif (AMD64)
++ elseif(AMD64)
+ set(ZLIB_ASMS contrib/amd64/amd64-match.S)
+- endif ()
++ elseif(ARMv8)
++ set(ZLIB_ARMv8 contrib/arm/neon_adler32.c)
++ endif()
+
+- if(ZLIB_ASMS)
+- add_definitions(-DASMV)
+- set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE)
+- endif()
++ if(ZLIB_ASMS)
++ add_definitions(-DASMV)
++ set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE)
++ elseif(ZLIB_ARMv8)
++ add_definitions(-DARMv8)
++ set(COMPILER ${CMAKE_C_COMPILER})
++ # NEON is mandatory in ARMv8.
++ if(${COMPILER} MATCHES "aarch64")
++ set_source_files_properties(${ZLIB_ARMv8} PROPERTIES LANGUAGE C COMPILE_FLAGS -march=armv8-a)
++ # But it was optional for ARMv7.
++ elseif(${COMPILER} MATCHES "arm")
++ set_source_files_properties(${ZLIB_ARMv8} PROPERTIES LANGUAGE C COMPILE_FLAGS -mfpu=neon)
++ endif()
++ endif()
+ endif()
+
+ if(MSVC)
+@@ -183,8 +196,8 @@ if(MINGW)
+ set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj)
+ endif(MINGW)
+
+-add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
+-add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
++add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_ARMv8} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
++add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_ARMv8} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
+ set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL)
+ set_target_properties(zlib PROPERTIES SOVERSION 1)
+
+diff --git a/adler32.c b/adler32.c
+index d0be4380..45ebaa4b 100644
+--- a/adler32.c
++++ b/adler32.c
+@@ -136,7 +136,12 @@ uLong ZEXPORT adler32(adler, buf, len)
+ const Bytef *buf;
+ uInt len;
+ {
++#ifdef ARMv8
++# pragma message("Using NEON-ized Adler32.")
++ return NEON_adler32(adler, buf, len);
++#else
+ return adler32_z(adler, buf, len);
++#endif
+ }
+
+ /* ========================================================================= */
+diff --git a/contrib/README.contrib b/contrib/README.contrib
+index a411d5c3..3fd1d202 100644
+--- a/contrib/README.contrib
++++ b/contrib/README.contrib
+@@ -12,6 +12,9 @@ amd64/ by Mikhail Teterin <mi@ALDAN.algebra.com>
+ asm code for AMD64
+ See patch at http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/96393
+
++arm/ by Adenilson Cavalcanti <cavalcantii@chromium.org>
++ ARM optimizations (NEON and ARMv8 code).
++
+ asm686/ by Brian Raiter <breadbox@muppetlabs.com>
+ asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax
+ See http://www.muppetlabs.com/~breadbox/software/assembly.html
+diff --git a/contrib/arm/neon_adler32.c b/contrib/arm/neon_adler32.c
+new file mode 100644
+index 00000000..f173a74f
+--- /dev/null
++++ b/contrib/arm/neon_adler32.c
+@@ -0,0 +1,137 @@
++/* Copyright (C) 1995-2011, 2016 Mark Adler
++ * Copyright (C) 2017 ARM Holdings Inc.
++ * Authors: Adenilson Cavalcanti <adenilson.cavalcanti@arm.com>
++ * Simon Hosie <simon.hosie@arm.com>
++ * This software is provided 'as-is', without any express or implied
++ * warranty. In no event will the authors be held liable for any damages
++ * arising from the use of this software.
++ * Permission is granted to anyone to use this software for any purpose,
++ * including commercial applications, and to alter it and redistribute it
++ * freely, subject to the following restrictions:
++ * 1. The origin of this software must not be misrepresented; you must not
++ * claim that you wrote the original software. If you use this software
++ * in a product, an acknowledgment in the product documentation would be
++ * appreciated but is not required.
++ * 2. Altered source versions must be plainly marked as such, and must not be
++ * misrepresented as being the original software.
++ * 3. This notice may not be removed or altered from any source distribution.
++ */
++
++#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
++#include <arm_neon.h>
++
++static void NEON_accum32(uint32_t *s, const unsigned char *buf,
++ unsigned int len)
++{
++ static const uint8_t taps[32] = {
++ 32, 31, 30, 29, 28, 27, 26, 25,
++ 24, 23, 22, 21, 20, 19, 18, 17,
++ 16, 15, 14, 13, 12, 11, 10, 9,
++ 8, 7, 6, 5, 4, 3, 2, 1 };
++
++ uint32x2_t adacc2, s2acc2, as;
++ uint8x16_t t0 = vld1q_u8(taps), t1 = vld1q_u8(taps + 16);
++
++ uint32x4_t adacc = vdupq_n_u32(0), s2acc = vdupq_n_u32(0);
++ adacc = vsetq_lane_u32(s[0], adacc, 0);
++ s2acc = vsetq_lane_u32(s[1], s2acc, 0);
++
++ while (len >= 2) {
++ uint8x16_t d0 = vld1q_u8(buf), d1 = vld1q_u8(buf + 16);
++ uint16x8_t adler, sum2;
++ s2acc = vaddq_u32(s2acc, vshlq_n_u32(adacc, 5));
++ adler = vpaddlq_u8( d0);
++ adler = vpadalq_u8(adler, d1);
++ sum2 = vmull_u8( vget_low_u8(t0), vget_low_u8(d0));
++ sum2 = vmlal_u8(sum2, vget_high_u8(t0), vget_high_u8(d0));
++ sum2 = vmlal_u8(sum2, vget_low_u8(t1), vget_low_u8(d1));
++ sum2 = vmlal_u8(sum2, vget_high_u8(t1), vget_high_u8(d1));
++ adacc = vpadalq_u16(adacc, adler);
++ s2acc = vpadalq_u16(s2acc, sum2);
++ len -= 2;
++ buf += 32;
++ }
++
++ while (len > 0) {
++ uint8x16_t d0 = vld1q_u8(buf);
++ uint16x8_t adler, sum2;
++ s2acc = vaddq_u32(s2acc, vshlq_n_u32(adacc, 4));
++ adler = vpaddlq_u8(d0);
++ sum2 = vmull_u8( vget_low_u8(t1), vget_low_u8(d0));
++ sum2 = vmlal_u8(sum2, vget_high_u8(t1), vget_high_u8(d0));
++ adacc = vpadalq_u16(adacc, adler);
++ s2acc = vpadalq_u16(s2acc, sum2);
++ buf += 16;
++ len--;
++ }
++
++ adacc2 = vpadd_u32(vget_low_u32(adacc), vget_high_u32(adacc));
++ s2acc2 = vpadd_u32(vget_low_u32(s2acc), vget_high_u32(s2acc));
++ as = vpadd_u32(adacc2, s2acc2);
++ s[0] = vget_lane_u32(as, 0);
++ s[1] = vget_lane_u32(as, 1);
++}
++
++static void NEON_handle_tail(uint32_t *pair, const unsigned char *buf,
++ unsigned int len)
++{
++ /* Oldie K&R code integration. */
++ unsigned int i;
++ for (i = 0; i < len; ++i) {
++ pair[0] += buf[i];
++ pair[1] += pair[0];
++ }
++}
++
++extern unsigned long NEON_adler32(unsigned long adler, const unsigned char *buf,
++ const unsigned int len)
++{
++ /* initial Adler-32 value (deferred check for len == 1 speed) */
++ if (!buf)
++ return 1L;
++
++ /* The largest prime smaller than 65536. */
++ const uint32_t M_BASE = 65521;
++ /* This is the threshold where doing accumulation may overflow. */
++ const int M_NMAX = 5552;
++
++ unsigned long sum2;
++ uint32_t pair[2];
++ int n = M_NMAX;
++ unsigned int done = 0;
++ /* Oldie K&R code integration. */
++ unsigned int i;
++
++ /* Split Adler-32 into component sums, it can be supplied by
++ * the caller sites (e.g. in a PNG file).
++ */
++ sum2 = (adler >> 16) & 0xffff;
++ adler &= 0xffff;
++ pair[0] = adler;
++ pair[1] = sum2;
++
++ for (i = 0; i < len; i += n) {
++ if ((i + n) > len)
++ n = len - i;
++
++ if (n < 16)
++ break;
++
++ NEON_accum32(pair, buf + i, n / 16);
++ pair[0] %= M_BASE;
++ pair[1] %= M_BASE;
++
++ done += (n / 16) * 16;
++ }
++
++ /* Handle the tail elements. */
++ if (done < len) {
++ NEON_handle_tail(pair, (buf + done), len - done);
++ pair[0] %= M_BASE;
++ pair[1] %= M_BASE;
++ }
++
++ /* D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. */
++ return (pair[1] << 16) | pair[0];
++}
++#endif