revert to rt1's zlib

This commit is contained in:
wuggy 2026-07-13 03:46:59 -07:00
commit 175e0de509
207 changed files with 15023 additions and 33924 deletions

1515
modules/zlib/src/ChangeLog Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,69 @@
Mozilla ChangeLog file for zlib
Mozilla.org changes:
- 17 June 2004
Sync'd with 1.2.1 release
see bug #226733
- 17 June 2004
Add mozzconf.h
- 17 June 2004
Turn off ZLIB_DLL to fix static build bustage
- 24 June 2004
do not prototype strerror for VMS in zutil.h
- 25 June 2004
define NO_vsnprintf for VMS in zutil.h
- 21 September 2004
applied patch for DoS vulnerabililty in inflate.c
see bug #258009
- 02 November 2004
Sync'ed with 1.2.2 release
(keeping '#include "mozzconf.h"' in zconf.h)
Our patches of 24, 25 June and 21 Sept are now in the zlib
distribution.
See bug #248644
- 24 July 2005
Sync'ed with 1.2.3 release
(keeping '#include "mozzconf.h"' in zconf.h)
See bugs #299445 and #300349
- 24 July 2005
Added treatment of HAVE_VISIBILITY_PRAGMA in mozzconf.h
- 24 July 2005
Updated zlib.def with new symbols in zlib version 1.2.3
- 13 September 2009
Don't enable zlib's debug output when the Mozilla build is in debug mode (bug 431950)
- 18 September 2010
Sync'ed with 1.2.5 release
(keeping '#include "mozzconf.h"' in zconf.h)
See bug #573137
- 8 February 2012
Sync'ed with 1.2.6 release
(keeping '#include "mozzconf.h"' in zconf.h)
See bug #722391
- 4 May 2012
Sync'ed with 1.2.7 release
(keeping '#include "mozzconf.h"' in zconf.h)
See bug #751697
- 9 May 2013
Sync'ed with 1.2.8 release
(keeping '#include "mozzconf.h"' in zconf.h)
See bug #866964
- 16 January 2017
Sync'ed with 1.2.11 release
(keeping '#include "mozzconf.h"' in zconf.h)
See bug #1328099

368
modules/zlib/src/FAQ Normal file
View file

@ -0,0 +1,368 @@
Frequently Asked Questions about zlib
If your question is not there, please check the zlib home page
http://zlib.net/ which may have more recent information.
The lastest zlib FAQ is at http://zlib.net/zlib_faq.html
1. Is zlib Y2K-compliant?
Yes. zlib doesn't handle dates.
2. Where can I get a Windows DLL version?
The zlib sources can be compiled without change to produce a DLL. See the
file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the
precompiled DLL are found in the zlib web site at http://zlib.net/ .
3. Where can I get a Visual Basic interface to zlib?
See
* http://marknelson.us/1997/01/01/zlib-engine/
* win32/DLL_FAQ.txt in the zlib distribution
4. compress() returns Z_BUF_ERROR.
Make sure that before the call of compress(), the length of the compressed
buffer is equal to the available size of the compressed buffer and not
zero. For Visual Basic, check that this parameter is passed by reference
("as any"), not by value ("as long").
5. deflate() or inflate() returns Z_BUF_ERROR.
Before making the call, make sure that avail_in and avail_out are not zero.
When setting the parameter flush equal to Z_FINISH, also make sure that
avail_out is big enough to allow processing all pending input. Note that a
Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be
made with more input or output space. A Z_BUF_ERROR may in fact be
unavoidable depending on how the functions are used, since it is not
possible to tell whether or not there is more output pending when
strm.avail_out returns with zero. See http://zlib.net/zlib_how.html for a
heavily annotated example.
6. Where's the zlib documentation (man pages, etc.)?
It's in zlib.h . Examples of zlib usage are in the files test/example.c
and test/minigzip.c, with more in examples/ .
7. Why don't you use GNU autoconf or libtool or ...?
Because we would like to keep zlib as a very small and simple package.
zlib is rather portable and doesn't need much configuration.
8. I found a bug in zlib.
Most of the time, such problems are due to an incorrect usage of zlib.
Please try to reproduce the problem with a small program and send the
corresponding source to us at zlib@gzip.org . Do not send multi-megabyte
data files without prior agreement.
9. Why do I get "undefined reference to gzputc"?
If "make test" produces something like
example.o(.text+0x154): undefined reference to `gzputc'
check that you don't have old files libz.* in /usr/lib, /usr/local/lib or
/usr/X11R6/lib. Remove any old versions, then do "make install".
10. I need a Delphi interface to zlib.
See the contrib/delphi directory in the zlib distribution.
11. Can zlib handle .zip archives?
Not by itself, no. See the directory contrib/minizip in the zlib
distribution.
12. Can zlib handle .Z files?
No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt
the code of uncompress on your own.
13. How can I make a Unix shared library?
By default a shared (and a static) library is built for Unix. So:
make distclean
./configure
make
14. How do I install a shared zlib library on Unix?
After the above, then:
make install
However, many flavors of Unix come with a shared zlib already installed.
Before going to the trouble of compiling a shared version of zlib and
trying to install it, you may want to check if it's already there! If you
can #include <zlib.h>, it's there. The -lz option will probably link to
it. You can check the version at the top of zlib.h or with the
ZLIB_VERSION symbol defined in zlib.h .
15. I have a question about OttoPDF.
We are not the authors of OttoPDF. The real author is on the OttoPDF web
site: Joel Hainley, jhainley@myndkryme.com.
16. Can zlib decode Flate data in an Adobe PDF file?
Yes. See http://www.pdflib.com/ . To modify PDF forms, see
http://sourceforge.net/projects/acroformtool/ .
17. Why am I getting this "register_frame_info not found" error on Solaris?
After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib
generates an error such as:
ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so:
symbol __register_frame_info: referenced symbol not found
The symbol __register_frame_info is not part of zlib, it is generated by
the C compiler (cc or gcc). You must recompile applications using zlib
which have this problem. This problem is specific to Solaris. See
http://www.sunfreeware.com for Solaris versions of zlib and applications
using zlib.
18. Why does gzip give an error on a file I make with compress/deflate?
The compress and deflate functions produce data in the zlib format, which
is different and incompatible with the gzip format. The gz* functions in
zlib on the other hand use the gzip format. Both the zlib and gzip formats
use the same compressed data format internally, but have different headers
and trailers around the compressed data.
19. Ok, so why are there two different formats?
The gzip format was designed to retain the directory information about a
single file, such as the name and last modification date. The zlib format
on the other hand was designed for in-memory and communication channel
applications, and has a much more compact header and trailer and uses a
faster integrity check than gzip.
20. Well that's nice, but how do I make a gzip file in memory?
You can request that deflate write the gzip format instead of the zlib
format using deflateInit2(). You can also request that inflate decode the
gzip format using inflateInit2(). Read zlib.h for more details.
21. Is zlib thread-safe?
Yes. However any library routines that zlib uses and any application-
provided memory allocation routines must also be thread-safe. zlib's gz*
functions use stdio library routines, and most of zlib's functions use the
library memory allocation routines by default. zlib's *Init* functions
allow for the application to provide custom memory allocation routines.
Of course, you should only operate on any given zlib or gzip stream from a
single thread at a time.
22. Can I use zlib in my commercial application?
Yes. Please read the license in zlib.h.
23. Is zlib under the GNU license?
No. Please read the license in zlib.h.
24. The license says that altered source versions must be "plainly marked". So
what exactly do I need to do to meet that requirement?
You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In
particular, the final version number needs to be changed to "f", and an
identification string should be appended to ZLIB_VERSION. Version numbers
x.x.x.f are reserved for modifications to zlib by others than the zlib
maintainers. For example, if the version of the base zlib you are altering
is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and
ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also
update the version strings in deflate.c and inftrees.c.
For altered source distributions, you should also note the origin and
nature of the changes in zlib.h, as well as in ChangeLog and README, along
with the dates of the alterations. The origin should include at least your
name (or your company's name), and an email address to contact for help or
issues with the library.
Note that distributing a compiled zlib library along with zlib.h and
zconf.h is also a source distribution, and so you should change
ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes
in zlib.h as you would for a full source distribution.
25. Will zlib work on a big-endian or little-endian architecture, and can I
exchange compressed data between them?
Yes and yes.
26. Will zlib work on a 64-bit machine?
Yes. It has been tested on 64-bit machines, and has no dependence on any
data types being limited to 32-bits in length. If you have any
difficulties, please provide a complete problem report to zlib@gzip.org
27. Will zlib decompress data from the PKWare Data Compression Library?
No. The PKWare DCL uses a completely different compressed data format than
does PKZIP and zlib. However, you can look in zlib's contrib/blast
directory for a possible solution to your problem.
28. Can I access data randomly in a compressed stream?
No, not without some preparation. If when compressing you periodically use
Z_FULL_FLUSH, carefully write all the pending data at those points, and
keep an index of those locations, then you can start decompression at those
points. You have to be careful to not use Z_FULL_FLUSH too often, since it
can significantly degrade compression. Alternatively, you can scan a
deflate stream once to generate an index, and then use that index for
random access. See examples/zran.c .
29. Does zlib work on MVS, OS/390, CICS, etc.?
It has in the past, but we have not heard of any recent evidence. There
were working ports of zlib 1.1.4 to MVS, but those links no longer work.
If you know of recent, successful applications of zlib on these operating
systems, please let us know. Thanks.
30. Is there some simpler, easier to read version of inflate I can look at to
understand the deflate format?
First off, you should read RFC 1951. Second, yes. Look in zlib's
contrib/puff directory.
31. Does zlib infringe on any patents?
As far as we know, no. In fact, that was originally the whole point behind
zlib. Look here for some more information:
http://www.gzip.org/#faq11
32. Can zlib work with greater than 4 GB of data?
Yes. inflate() and deflate() will process any amount of data correctly.
Each call of inflate() or deflate() is limited to input and output chunks
of the maximum value that can be stored in the compiler's "unsigned int"
type, but there is no limit to the number of chunks. Note however that the
strm.total_in and strm_total_out counters may be limited to 4 GB. These
counters are provided as a convenience and are not used internally by
inflate() or deflate(). The application can easily set up its own counters
updated after each call of inflate() or deflate() to count beyond 4 GB.
compress() and uncompress() may be limited to 4 GB, since they operate in a
single call. gzseek() and gztell() may be limited to 4 GB depending on how
zlib is compiled. See the zlibCompileFlags() function in zlib.h.
The word "may" appears several times above since there is a 4 GB limit only
if the compiler's "long" type is 32 bits. If the compiler's "long" type is
64 bits, then the limit is 16 exabytes.
33. Does zlib have any security vulnerabilities?
The only one that we are aware of is potentially in gzprintf(). If zlib is
compiled to use sprintf() or vsprintf(), then there is no protection
against a buffer overflow of an 8K string space (or other value as set by
gzbuffer()), other than the caller of gzprintf() assuring that the output
will not exceed 8K. On the other hand, if zlib is compiled to use
snprintf() or vsnprintf(), which should normally be the case, then there is
no vulnerability. The ./configure script will display warnings if an
insecure variation of sprintf() will be used by gzprintf(). Also the
zlibCompileFlags() function will return information on what variant of
sprintf() is used by gzprintf().
If you don't have snprintf() or vsnprintf() and would like one, you can
find a portable implementation here:
http://www.ijs.si/software/snprintf/
Note that you should be using the most recent version of zlib. Versions
1.1.3 and before were subject to a double-free vulnerability, and versions
1.2.1 and 1.2.2 were subject to an access exception when decompressing
invalid compressed data.
34. Is there a Java version of zlib?
Probably what you want is to use zlib in Java. zlib is already included
as part of the Java SDK in the java.util.zip package. If you really want
a version of zlib written in the Java language, look on the zlib home
page for links: http://zlib.net/ .
35. I get this or that compiler or source-code scanner warning when I crank it
up to maximally-pedantic. Can't you guys write proper code?
Many years ago, we gave up attempting to avoid warnings on every compiler
in the universe. It just got to be a waste of time, and some compilers
were downright silly as well as contradicted each other. So now, we simply
make sure that the code always works.
36. Valgrind (or some similar memory access checker) says that deflate is
performing a conditional jump that depends on an uninitialized value.
Isn't that a bug?
No. That is intentional for performance reasons, and the output of deflate
is not affected. This only started showing up recently since zlib 1.2.x
uses malloc() by default for allocations, whereas earlier versions used
calloc(), which zeros out the allocated memory. Even though the code was
correct, versions 1.2.4 and later was changed to not stimulate these
checkers.
37. Will zlib read the (insert any ancient or arcane format here) compressed
data format?
Probably not. Look in the comp.compression FAQ for pointers to various
formats and associated software.
38. How can I encrypt/decrypt zip files with zlib?
zlib doesn't support encryption. The original PKZIP encryption is very
weak and can be broken with freely available programs. To get strong
encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib
compression. For PKZIP compatible "encryption", look at
http://www.info-zip.org/
39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
"gzip" is the gzip format, and "deflate" is the zlib format. They should
probably have called the second one "zlib" instead to avoid confusion with
the raw deflate compressed data format. While the HTTP 1.1 RFC 2616
correctly points to the zlib specification in RFC 1950 for the "deflate"
transfer encoding, there have been reports of servers and browsers that
incorrectly produce or expect raw deflate data per the deflate
specification in RFC 1951, most notably Microsoft. So even though the
"deflate" transfer encoding using the zlib format would be the more
efficient approach (and in fact exactly what the zlib format was designed
for), using the "gzip" transfer encoding is probably more reliable due to
an unfortunate choice of name on the part of the HTTP 1.1 authors.
Bottom line: use the gzip format for HTTP 1.1 encoding.
40. Does zlib support the new "Deflate64" format introduced by PKWare?
No. PKWare has apparently decided to keep that format proprietary, since
they have not documented it as they have previous compression formats. In
any case, the compression improvements are so modest compared to other more
modern approaches, that it's not worth the effort to implement.
41. I'm having a problem with the zip functions in zlib, can you help?
There are no zip functions in zlib. You are probably using minizip by
Giles Vollant, which is found in the contrib directory of zlib. It is not
part of zlib. In fact none of the stuff in contrib is part of zlib. The
files in there are not supported by the zlib authors. You need to contact
the authors of the respective contribution for help.
42. The match.asm code in contrib is under the GNU General Public License.
Since it's part of zlib, doesn't that mean that all of zlib falls under the
GNU GPL?
No. The files in contrib are not part of zlib. They were contributed by
other authors and are provided as a convenience to the user within the zlib
distribution. Each item in contrib has its own license.
43. Is zlib subject to export controls? What is its ECCN?
zlib is not subject to export controls, and so is classified as EAR99.
44. Can you please sign these lengthy legal documents and fax them back to us
so that we can use your software in our product?
No. Go away. Shoo.

68
modules/zlib/src/INDEX Normal file
View file

@ -0,0 +1,68 @@
CMakeLists.txt cmake build file
ChangeLog history of changes
FAQ Frequently Asked Questions about zlib
INDEX this file
Makefile dummy Makefile that tells you to ./configure
Makefile.in template for Unix Makefile
README guess what
configure configure script for Unix
make_vms.com makefile for VMS
test/example.c zlib usages examples for build testing
test/minigzip.c minimal gzip-like functionality for build testing
test/infcover.c inf*.c code coverage for build coverage testing
treebuild.xml XML description of source file dependencies
zconf.h.cmakein zconf.h template for cmake
zconf.h.in zconf.h template for configure
zlib.3 Man page for zlib
zlib.3.pdf Man page in PDF format
zlib.map Linux symbol information
zlib.pc.in Template for pkg-config descriptor
zlib.pc.cmakein zlib.pc template for cmake
zlib2ansi perl script to convert source files for C++ compilation
amiga/ makefiles for Amiga SAS C
as400/ makefiles for AS/400
doc/ documentation for formats and algorithms
msdos/ makefiles for MSDOS
nintendods/ makefile for Nintendo DS
old/ makefiles for various architectures and zlib documentation
files that have not yet been updated for zlib 1.2.x
qnx/ makefiles for QNX
watcom/ makefiles for OpenWatcom
win32/ makefiles for Windows
zlib public header files (required for library use):
zconf.h
zlib.h
private source files used to build the zlib library:
adler32.c
compress.c
crc32.c
crc32.h
deflate.c
deflate.h
gzclose.c
gzguts.h
gzlib.c
gzread.c
gzwrite.c
infback.c
inffast.c
inffast.h
inffixed.h
inflate.c
inflate.h
inftrees.c
inftrees.h
trees.c
trees.h
uncompr.c
zutil.c
zutil.h
source files for sample programs
See examples/README.examples
unsupported contributions by third parties
See contrib/README.contrib

115
modules/zlib/src/README Normal file
View file

@ -0,0 +1,115 @@
ZLIB DATA COMPRESSION LIBRARY
zlib 1.2.11 is a general purpose data compression library. All the code is
thread safe. The data format used by the zlib library is described by RFCs
(Request for Comments) 1950 to 1952 in the files
http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
rfc1952 (gzip format).
All functions of the compression library are documented in the file zlib.h
(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
of the library is given in the file test/example.c which also tests that
the library is working correctly. Another example is given in the file
test/minigzip.c. The compression library itself is composed of all source
files in the root directory.
To compile all files and run the test program, follow the instructions given at
the top of Makefile.in. In short "./configure; make test", and if that goes
well, "make install" should work for most flavors of Unix. For Windows, use
one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use
make_vms.com.
Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
<info@winimage.com> for the Windows DLL version. The zlib home page is
http://zlib.net/ . Before reporting a problem, please check this site to
verify that you have the latest version of zlib; otherwise get the latest
version and check whether the problem still exists or not.
PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.
Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
issue of Dr. Dobb's Journal; a copy of the article is available at
http://marknelson.us/1997/01/01/zlib-engine/ .
The changes made in version 1.2.11 are documented in the file ChangeLog.
Unsupported third party contributions are provided in directory contrib/ .
zlib is available in Java using the java.util.zip package, documented at
http://java.sun.com/developer/technicalArticles/Programming/compression/ .
A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is available
at CPAN (Comprehensive Perl Archive Network) sites, including
http://search.cpan.org/~pmqs/IO-Compress-Zlib/ .
A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
available in Python 1.5 and later versions, see
http://docs.python.org/library/zlib.html .
zlib is built into tcl: http://wiki.tcl.tk/4610 .
An experimental package to read and write files in .zip format, written on top
of zlib by Gilles Vollant <info@winimage.com>, is available in the
contrib/minizip directory of zlib.
Notes for some targets:
- For Windows DLL versions, please see win32/DLL_FAQ.txt
- For 64-bit Irix, deflate.c must be compiled without any optimization. With
-O, one libpng test fails. The test works in 32 bit mode (with the -n32
compiler flag). The compiler bug has been reported to SGI.
- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
when compiled with cc.
- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
necessary to get gzprintf working correctly. This is done by configure.
- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
other compilers. Use "make test" to check your compiler.
- gzdopen is not supported on RISCOS or BEOS.
- For PalmOs, see http://palmzlib.sourceforge.net/
Acknowledgments:
The deflate format used by zlib was defined by Phil Katz. The deflate and
zlib specifications were written by L. Peter Deutsch. Thanks to all the
people who reported problems and suggested various improvements in zlib; they
are too numerous to cite here.
Copyright notice:
(C) 1995-2017 Jean-loup Gailly and Mark Adler
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.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
If you use the zlib library in a product, we would appreciate *not* receiving
lengthy legal documents to sign. The sources are provided for free but without
warranty of any kind. The library has been entirely written by Jean-loup
Gailly and Mark Adler; it does not include third-party code.
If you redistribute modified sources, we would appreciate that you include in
the file ChangeLog history information documenting your changes. Please read
the FAQ for more information on the distribution of modified source versions.

View file

@ -3,75 +3,214 @@
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zbuild.h"
#include "functable.h"
#include "adler32_p.h"
/* @(#) $Id$ */
#ifdef ZLIB_COMPAT
unsigned long Z_EXPORT PREFIX(adler32_z)(unsigned long adler, const unsigned char *buf, size_t len) {
if (buf == NULL)
return ADLER32_INITIAL_VALUE;
return (unsigned long)FUNCTABLE_CALL(adler32)((uint32_t)adler, buf, len);
}
#include "zutil.h"
local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
#define BASE 65521U /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#define DO16(buf) DO8(buf,0); DO8(buf,8);
/* use NO_DIVIDE if your processor does not do division in hardware --
try it both ways to see which is faster */
#ifdef NO_DIVIDE
/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
(thank you to John Reiser for pointing this out) */
# define CHOP(a) \
do { \
unsigned long tmp = a >> 16; \
a &= 0xffffUL; \
a += (tmp << 4) - tmp; \
} while (0)
# define MOD28(a) \
do { \
CHOP(a); \
if (a >= BASE) a -= BASE; \
} while (0)
# define MOD(a) \
do { \
CHOP(a); \
MOD28(a); \
} while (0)
# define MOD63(a) \
do { /* this assumes a is not negative */ \
z_off64_t tmp = a >> 32; \
a &= 0xffffffffL; \
a += (tmp << 8) - (tmp << 5) + tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
if (a >= BASE) a -= BASE; \
} while (0)
#else
uint32_t Z_EXPORT PREFIX(adler32_z)(uint32_t adler, const unsigned char *buf, size_t len) {
if (buf == NULL)
return ADLER32_INITIAL_VALUE;
return FUNCTABLE_CALL(adler32)(adler, buf, len);
}
# define MOD(a) a %= BASE
# define MOD28(a) a %= BASE
# define MOD63(a) a %= BASE
#endif
#if defined(ADLER32_SIMD_SSSE3)
#include "adler32_simd.h"
#include "x86.h"
#elif defined(ADLER32_SIMD_NEON)
#include "adler32_simd.h"
#endif
/* ========================================================================= */
#ifdef ZLIB_COMPAT
unsigned long Z_EXPORT PREFIX(adler32)(unsigned long adler, const unsigned char *buf, unsigned int len) {
if (buf == NULL)
return ADLER32_INITIAL_VALUE;
return (unsigned long)FUNCTABLE_CALL(adler32)((uint32_t)adler, buf, len);
}
#else
uint32_t Z_EXPORT PREFIX(adler32)(uint32_t adler, const unsigned char *buf, uint32_t len) {
if (buf == NULL)
return ADLER32_INITIAL_VALUE;
return FUNCTABLE_CALL(adler32)(adler, buf, len);
}
uLong ZEXPORT adler32_z(adler, buf, len)
uLong adler;
const Bytef *buf;
z_size_t len;
{
unsigned long sum2;
unsigned n;
#if defined(ADLER32_SIMD_SSSE3)
if (x86_cpu_enable_ssse3 && buf && len >= 64)
return adler32_simd_(adler, buf, len);
#elif defined(ADLER32_SIMD_NEON)
if (buf && len >= 64)
return adler32_simd_(adler, buf, len);
#endif
/* split Adler-32 into component sums */
sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (len == 1) {
adler += buf[0];
if (adler >= BASE)
adler -= BASE;
sum2 += adler;
if (sum2 >= BASE)
sum2 -= BASE;
return adler | (sum2 << 16);
}
#if defined(ADLER32_SIMD_SSSE3)
/*
* Use SSSE3 to compute the adler32. Since this routine can be
* freely used, check CPU features here. zlib convention is to
* call adler32(0, NULL, 0), before making calls to adler32().
* So this is a good early (and infrequent) place to cache CPU
* features for those later, more interesting adler32() calls.
*/
if (buf == Z_NULL) {
if (!len) /* Assume user is calling adler32(0, NULL, 0); */
x86_check_features();
return 1L;
}
#else
/* initial Adler-32 value (deferred check for len == 1 speed) */
if (buf == Z_NULL)
return 1L;
#endif
/* in case short lengths are provided, keep it somewhat fast */
if (len < 16) {
while (len--) {
adler += *buf++;
sum2 += adler;
}
if (adler >= BASE)
adler -= BASE;
MOD28(sum2); /* only added so many BASE's */
return adler | (sum2 << 16);
}
/* do length NMAX blocks -- requires just one modulo operation */
while (len >= NMAX) {
len -= NMAX;
n = NMAX / 16; /* NMAX is divisible by 16 */
do {
DO16(buf); /* 16 sums unrolled */
buf += 16;
} while (--n);
MOD(adler);
MOD(sum2);
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if (len) { /* avoid modulos if none remaining */
while (len >= 16) {
len -= 16;
DO16(buf);
buf += 16;
}
while (len--) {
adler += *buf++;
sum2 += adler;
}
MOD(adler);
MOD(sum2);
}
/* return recombined sums */
return adler | (sum2 << 16);
}
/* ========================================================================= */
static uint32_t adler32_combine_(uint32_t adler1, uint32_t adler2, z_off64_t len2) {
uint32_t sum1;
uint32_t sum2;
uLong ZEXPORT adler32(adler, buf, len)
uLong adler;
const Bytef *buf;
uInt len;
{
return adler32_z(adler, buf, len);
}
/* ========================================================================= */
local uLong adler32_combine_(adler1, adler2, len2)
uLong adler1;
uLong adler2;
z_off64_t len2;
{
unsigned long sum1;
unsigned long sum2;
unsigned rem;
/* for negative len, return invalid adler32 as a clue for debugging */
if (len2 < 0)
return 0xffffffff;
return 0xffffffffUL;
/* the derivation of this formula is left as an exercise for the reader */
len2 %= BASE; /* assumes len2 >= 0 */
MOD63(len2); /* assumes len2 >= 0 */
rem = (unsigned)len2;
sum1 = adler1 & 0xffff;
sum2 = rem * sum1;
sum2 %= BASE;
MOD(sum2);
sum1 += (adler2 & 0xffff) + BASE - 1;
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
if (sum1 >= BASE) sum1 -= BASE;
if (sum1 >= BASE) sum1 -= BASE;
if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);
if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16);
}
/* ========================================================================= */
#ifdef ZLIB_COMPAT
unsigned long Z_EXPORT PREFIX(adler32_combine)(unsigned long adler1, unsigned long adler2, z_off_t len2) {
return (unsigned long)adler32_combine_((uint32_t)adler1, (uint32_t)adler2, len2);
}
unsigned long Z_EXPORT PREFIX4(adler32_combine)(unsigned long adler1, unsigned long adler2, z_off64_t len2) {
return (unsigned long)adler32_combine_((uint32_t)adler1, (uint32_t)adler2, len2);
}
#else
uint32_t Z_EXPORT PREFIX4(adler32_combine)(uint32_t adler1, uint32_t adler2, z_off64_t len2) {
uLong ZEXPORT adler32_combine(adler1, adler2, len2)
uLong adler1;
uLong adler2;
z_off_t len2;
{
return adler32_combine_(adler1, adler2, len2);
}
uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
uLong adler1;
uLong adler2;
z_off64_t len2;
{
return adler32_combine_(adler1, adler2, len2);
}
#endif

View file

@ -1,100 +0,0 @@
/* adler32_p.h -- Private inline functions and macros shared with
* different computation of the Adler-32 checksum
* of a data stream.
* Copyright (C) 1995-2011, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef ADLER32_P_H
#define ADLER32_P_H
#define BASE 65521U /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define NMAX_ALIGNED32 (NMAX & ~31)
/* NMAX rounded down to a multiple of 32 is 5536 */
#define ADLER_DO1(sum1, sum2, buf, i) {(sum1) += buf[(i)]; (sum2) += (sum1);}
#define ADLER_DO2(sum1, sum2, buf, i) {ADLER_DO1(sum1, sum2, buf, i); ADLER_DO1(sum1, sum2, buf, i+1);}
#define ADLER_DO4(sum1, sum2, buf, i) {ADLER_DO2(sum1, sum2, buf, i); ADLER_DO2(sum1, sum2, buf, i+2);}
#define ADLER_DO8(sum1, sum2, buf, i) {ADLER_DO4(sum1, sum2, buf, i); ADLER_DO4(sum1, sum2, buf, i+4);}
#define ADLER_DO16(sum1, sum2, buf) {ADLER_DO8(sum1, sum2, buf, 0); ADLER_DO8(sum1, sum2, buf, 8);}
Z_FORCEINLINE static void adler32_copy_align(uint32_t *Z_RESTRICT adler, uint8_t *dst, const uint8_t *buf, size_t len,
uint32_t *Z_RESTRICT sum2, const int MAX_LEN, const int COPY) {
Z_UNUSED(MAX_LEN);
if (len & 1) {
if (COPY) {
*dst = *buf;
dst += 1;
}
ADLER_DO1(*adler, *sum2, buf, 0);
buf += 1;
}
if (len & 2) {
if (COPY) {
memcpy(dst, buf, 2);
dst += 2;
}
ADLER_DO2(*adler, *sum2, buf, 0);
buf += 2;
}
while (len >= 4) {
if (COPY) {
memcpy(dst, buf, 4);
dst += 4;
}
len -= 4;
ADLER_DO4(*adler, *sum2, buf, 0);
buf += 4;
}
}
Z_FORCEINLINE static uint32_t adler32_copy_tail(uint32_t adler, uint8_t *dst, const uint8_t *buf, size_t len,
uint32_t sum2, const int REBASE, const int MAX_LEN, const int COPY) {
if (len) {
/* DO16 loop for large remainders only (scalar, risc-v). */
if (MAX_LEN >= 32) {
while (len >= 16) {
if (COPY) {
memcpy(dst, buf, 16);
dst += 16;
}
len -= 16;
ADLER_DO16(adler, sum2, buf);
buf += 16;
}
}
/* DO4 loop avoids GCC x86 register pressure from hoisted DO8/DO16 loads. */
while (len >= 4) {
if (COPY) {
memcpy(dst, buf, 4);
dst += 4;
}
len -= 4;
ADLER_DO4(adler, sum2, buf, 0);
buf += 4;
}
if (len & 2) {
if (COPY) {
memcpy(dst, buf, 2);
dst += 2;
}
ADLER_DO2(adler, sum2, buf, 0);
buf += 2;
}
if (len & 1) {
if (COPY)
*dst = *buf;
ADLER_DO1(adler, sum2, buf, 0);
}
}
if (REBASE) {
adler %= BASE;
sum2 %= BASE;
}
/* D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. */
return adler | (sum2 << 16);
}
#endif /* ADLER32_P_H */

View file

@ -0,0 +1,366 @@
/* adler32_simd.c
*
* Copyright 2017 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the Chromium source repository LICENSE file.
*
* Per http://en.wikipedia.org/wiki/Adler-32 the adler32 A value (aka s1) is
* the sum of N input data bytes D1 ... DN,
*
* A = A0 + D1 + D2 + ... + DN
*
* where A0 is the initial value.
*
* SSE2 _mm_sad_epu8() can be used for byte sums (see http://bit.ly/2wpUOeD,
* for example) and accumulating the byte sums can use SSE shuffle-adds (see
* the "Integer" section of http://bit.ly/2erPT8t for details). Arm NEON has
* similar instructions.
*
* The adler32 B value (aka s2) sums the A values from each step:
*
* B0 + (A0 + D1) + (A0 + D1 + D2) + ... + (A0 + D1 + D2 + ... + DN) or
*
* B0 + N.A0 + N.D1 + (N-1).D2 + (N-2).D3 + ... + (N-(N-1)).DN
*
* B0 being the initial value. For 32 bytes (ideal for garden-variety SIMD):
*
* B = B0 + 32.A0 + [D1 D2 D3 ... D32] x [32 31 30 ... 1].
*
* Adjacent blocks of 32 input bytes can be iterated with the expressions to
* compute the adler32 s1 s2 of M >> 32 input bytes [1].
*
* As M grows, the s1 s2 sums grow. If left unchecked, they would eventually
* overflow the precision of their integer representation (bad). However, s1
* and s2 also need to be computed modulo the adler BASE value (reduced). If
* at most NMAX bytes are processed before a reduce, s1 s2 _cannot_ overflow
* a uint32_t type (the NMAX constraint) [2].
*
* [1] the iterative equations for s2 contain constant factors; these can be
* hoisted from the n-blocks do loop of the SIMD code.
*
* [2] zlib adler32_z() uses this fact to implement NMAX-block-based updates
* of the adler s1 s2 of uint32_t type (see adler32.c).
*/
#include "adler32_simd.h"
/* Definitions from adler32.c: largest prime smaller than 65536 */
#define BASE 65521U
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define NMAX 5552
#if defined(ADLER32_SIMD_SSSE3)
#include <tmmintrin.h>
uint32_t ZLIB_INTERNAL adler32_simd_( /* SSSE3 */
uint32_t adler,
const unsigned char *buf,
z_size_t len)
{
/*
* Split Adler-32 into component sums.
*/
uint32_t s1 = adler & 0xffff;
uint32_t s2 = adler >> 16;
/*
* Process the data in blocks.
*/
const unsigned BLOCK_SIZE = 1 << 5;
z_size_t blocks = len / BLOCK_SIZE;
len -= blocks * BLOCK_SIZE;
while (blocks)
{
unsigned n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */
if (n > blocks)
n = (unsigned) blocks;
blocks -= n;
const __m128i tap1 =
_mm_setr_epi8(32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17);
const __m128i tap2 =
_mm_setr_epi8(16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
const __m128i zero =
_mm_setr_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
const __m128i ones =
_mm_set_epi16( 1, 1, 1, 1, 1, 1, 1, 1);
/*
* Process n blocks of data. At most NMAX data bytes can be
* processed before s2 must be reduced modulo BASE.
*/
__m128i v_ps = _mm_set_epi32(0, 0, 0, s1 * n);
__m128i v_s2 = _mm_set_epi32(0, 0, 0, s2);
__m128i v_s1 = _mm_set_epi32(0, 0, 0, 0);
do {
/*
* Load 32 input bytes.
*/
const __m128i bytes1 = _mm_loadu_si128((__m128i*)(buf));
const __m128i bytes2 = _mm_loadu_si128((__m128i*)(buf + 16));
/*
* Add previous block byte sum to v_ps.
*/
v_ps = _mm_add_epi32(v_ps, v_s1);
/*
* Horizontally add the bytes for s1, multiply-adds the
* bytes by [ 32, 31, 30, ... ] for s2.
*/
v_s1 = _mm_add_epi32(v_s1, _mm_sad_epu8(bytes1, zero));
const __m128i mad1 = _mm_maddubs_epi16(bytes1, tap1);
v_s2 = _mm_add_epi32(v_s2, _mm_madd_epi16(mad1, ones));
v_s1 = _mm_add_epi32(v_s1, _mm_sad_epu8(bytes2, zero));
const __m128i mad2 = _mm_maddubs_epi16(bytes2, tap2);
v_s2 = _mm_add_epi32(v_s2, _mm_madd_epi16(mad2, ones));
buf += BLOCK_SIZE;
} while (--n);
v_s2 = _mm_add_epi32(v_s2, _mm_slli_epi32(v_ps, 5));
/*
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
*/
#define S23O1 _MM_SHUFFLE(2,3,0,1) /* A B C D -> B A D C */
#define S1O32 _MM_SHUFFLE(1,0,3,2) /* A B C D -> C D A B */
v_s1 = _mm_add_epi32(v_s1, _mm_shuffle_epi32(v_s1, S23O1));
v_s1 = _mm_add_epi32(v_s1, _mm_shuffle_epi32(v_s1, S1O32));
s1 += _mm_cvtsi128_si32(v_s1);
v_s2 = _mm_add_epi32(v_s2, _mm_shuffle_epi32(v_s2, S23O1));
v_s2 = _mm_add_epi32(v_s2, _mm_shuffle_epi32(v_s2, S1O32));
s2 = _mm_cvtsi128_si32(v_s2);
#undef S23O1
#undef S1O32
/*
* Reduce.
*/
s1 %= BASE;
s2 %= BASE;
}
/*
* Handle leftover data.
*/
if (len) {
if (len >= 16) {
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
len -= 16;
}
while (len--) {
s2 += (s1 += *buf++);
}
if (s1 >= BASE)
s1 -= BASE;
s2 %= BASE;
}
/*
* Return the recombined sums.
*/
return s1 | (s2 << 16);
}
#elif defined(ADLER32_SIMD_NEON)
#include <arm_neon.h>
uint32_t ZLIB_INTERNAL adler32_simd_( /* NEON */
uint32_t adler,
const unsigned char *buf,
z_size_t len)
{
/*
* Split Adler-32 into component sums.
*/
uint32_t s1 = adler & 0xffff;
uint32_t s2 = adler >> 16;
/*
* Serially compute s1 & s2, until the data is 16-byte aligned.
*/
if ((uintptr_t)buf & 15) {
while ((uintptr_t)buf & 15) {
s2 += (s1 += *buf++);
--len;
}
if (s1 >= BASE)
s1 -= BASE;
s2 %= BASE;
}
/*
* Process the data in blocks.
*/
const unsigned BLOCK_SIZE = 1 << 5;
z_size_t blocks = len / BLOCK_SIZE;
len -= blocks * BLOCK_SIZE;
while (blocks)
{
unsigned n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */
if (n > blocks)
n = (unsigned) blocks;
blocks -= n;
/*
* Process n blocks of data. At most NMAX data bytes can be
* processed before s2 must be reduced modulo BASE.
*/
uint32x4_t v_s2 = (uint32x4_t) { 0, 0, 0, s1 * n };
uint32x4_t v_s1 = (uint32x4_t) { 0, 0, 0, 0 };
uint16x8_t v_column_sum_1 = vdupq_n_u16(0);
uint16x8_t v_column_sum_2 = vdupq_n_u16(0);
uint16x8_t v_column_sum_3 = vdupq_n_u16(0);
uint16x8_t v_column_sum_4 = vdupq_n_u16(0);
do {
/*
* Load 32 input bytes.
*/
const uint8x16_t bytes1 = vld1q_u8((uint8_t*)(buf));
const uint8x16_t bytes2 = vld1q_u8((uint8_t*)(buf + 16));
/*
* Add previous block byte sum to v_s2.
*/
v_s2 = vaddq_u32(v_s2, v_s1);
/*
* Horizontally add the bytes for s1.
*/
v_s1 = vpadalq_u16(v_s1, vpadalq_u8(vpaddlq_u8(bytes1), bytes2));
/*
* Vertically add the bytes for s2.
*/
v_column_sum_1 = vaddw_u8(v_column_sum_1, vget_low_u8 (bytes1));
v_column_sum_2 = vaddw_u8(v_column_sum_2, vget_high_u8(bytes1));
v_column_sum_3 = vaddw_u8(v_column_sum_3, vget_low_u8 (bytes2));
v_column_sum_4 = vaddw_u8(v_column_sum_4, vget_high_u8(bytes2));
buf += BLOCK_SIZE;
} while (--n);
v_s2 = vshlq_n_u32(v_s2, 5);
/*
* Multiply-add bytes by [ 32, 31, 30, ... ] for s2.
*/
v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_1),
(uint16x4_t) { 32, 31, 30, 29 });
v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_1),
(uint16x4_t) { 28, 27, 26, 25 });
v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_2),
(uint16x4_t) { 24, 23, 22, 21 });
v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_2),
(uint16x4_t) { 20, 19, 18, 17 });
v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_3),
(uint16x4_t) { 16, 15, 14, 13 });
v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_3),
(uint16x4_t) { 12, 11, 10, 9 });
v_s2 = vmlal_u16(v_s2, vget_low_u16 (v_column_sum_4),
(uint16x4_t) { 8, 7, 6, 5 });
v_s2 = vmlal_u16(v_s2, vget_high_u16(v_column_sum_4),
(uint16x4_t) { 4, 3, 2, 1 });
/*
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
*/
uint32x2_t sum1 = vpadd_u32(vget_low_u32(v_s1), vget_high_u32(v_s1));
uint32x2_t sum2 = vpadd_u32(vget_low_u32(v_s2), vget_high_u32(v_s2));
uint32x2_t s1s2 = vpadd_u32(sum1, sum2);
s1 += vget_lane_u32(s1s2, 0);
s2 += vget_lane_u32(s1s2, 1);
/*
* Reduce.
*/
s1 %= BASE;
s2 %= BASE;
}
/*
* Handle leftover data.
*/
if (len) {
if (len >= 16) {
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
s2 += (s1 += *buf++);
len -= 16;
}
while (len--) {
s2 += (s1 += *buf++);
}
if (s1 >= BASE)
s1 -= BASE;
s2 %= BASE;
}
/*
* Return the recombined sums.
*/
return s1 | (s2 << 16);
}
#endif /* ADLER32_SIMD_SSSE3 */

View file

@ -0,0 +1,16 @@
/* adler32_simd.h
*
* Copyright 2017 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the Chromium source repository LICENSE file.
*/
#include <stdint.h>
#include "zconf.h"
#include "zutil.h"
uint32_t ZLIB_INTERNAL adler32_simd_(
uint32_t adler,
const unsigned char *buf,
z_size_t len);

View file

@ -1,2 +0,0 @@
# ignore Makefiles; they're all automatically generated
Makefile

View file

@ -1,86 +0,0 @@
# Makefile for zlib
# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler
# For conditions of distribution and use, see copyright notice in zlib.h
CC=
CFLAGS=
SFLAGS=
INCLUDES=
SUFFIX=
ARMV8FLAG=
PMULLEOR3FLAG=
NEONFLAG=
ARMV6FLAG=
NOLTOFLAG=
SRCDIR=.
SRCTOP=../..
TOPDIR=$(SRCTOP)
all: \
adler32_neon.o adler32_neon.lo \
arm_features.o arm_features.lo \
chunkset_neon.o chunkset_neon.lo \
compare256_neon.o compare256_neon.lo \
crc32_armv8.o crc32_armv8.lo \
crc32_armv8_pmull_eor3.o crc32_armv8_pmull_eor3.lo \
slide_hash_neon.o slide_hash_neon.lo \
slide_hash_armv6.o slide_hash_armv6.lo \
adler32_neon.o:
$(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_neon.c
adler32_neon.lo:
$(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_neon.c
arm_features.o:
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/arm_features.c
arm_features.lo:
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/arm_features.c
chunkset_neon.o:
$(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_neon.c
chunkset_neon.lo:
$(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_neon.c
compare256_neon.o:
$(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_neon.c
compare256_neon.lo:
$(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_neon.c
crc32_armv8.o:
$(CC) $(CFLAGS) $(ARMV8FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_armv8.c
crc32_armv8.lo:
$(CC) $(SFLAGS) $(ARMV8FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_armv8.c
crc32_armv8_pmull_eor3.o:
$(CC) $(CFLAGS) $(PMULLEOR3FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_armv8_pmull_eor3.c
crc32_armv8_pmull_eor3.lo:
$(CC) $(SFLAGS) $(PMULLEOR3FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_armv8_pmull_eor3.c
slide_hash_neon.o:
$(CC) $(CFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_neon.c
slide_hash_neon.lo:
$(CC) $(SFLAGS) $(NEONFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_neon.c
slide_hash_armv6.o:
$(CC) $(CFLAGS) $(ARMV6FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_armv6.c
slide_hash_armv6.lo:
$(CC) $(SFLAGS) $(ARMV6FLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_armv6.c
mostlyclean: clean
clean:
rm -f *.o *.lo *~
rm -rf objs
rm -f *.gcda *.gcno *.gcov
distclean: clean
rm -f Makefile

View file

@ -1,90 +0,0 @@
#ifndef ARM_ACLE_INTRINS_H
#define ARM_ACLE_INTRINS_H
#include <stdint.h>
#ifdef _MSC_VER
# include <intrin.h>
#elif defined(HAVE_ARM_ACLE_H)
# include <arm_acle.h>
#endif
#ifdef ARM_CRC32
#if defined(ARCH_ARM) && defined(ARCH_64BIT)
# define Z_TARGET_CRC Z_TARGET("+crc")
#else
# define Z_TARGET_CRC
#endif
#ifdef ARM_PMULL_EOR3
# define Z_TARGET_PMULL_EOR3 Z_TARGET("+crc+crypto+sha3")
#else
# define Z_TARGET_PMULL_EOR3
#endif
#if !defined(ARM_CRC32_INTRIN) && !defined(_MSC_VER)
#if defined(ARCH_ARM) && defined(ARCH_64BIT)
static inline uint32_t __crc32b(uint32_t __a, uint8_t __b) {
uint32_t __c;
__asm__("crc32b %w0, %w1, %w2" : "=r" (__c) : "r"(__a), "r"(__b));
return __c;
}
static inline uint32_t __crc32h(uint32_t __a, uint16_t __b) {
uint32_t __c;
__asm__("crc32h %w0, %w1, %w2" : "=r" (__c) : "r"(__a), "r"(__b));
return __c;
}
static inline uint32_t __crc32w(uint32_t __a, uint32_t __b) {
uint32_t __c;
__asm__("crc32w %w0, %w1, %w2" : "=r" (__c) : "r"(__a), "r"(__b));
return __c;
}
static inline uint32_t __crc32d(uint32_t __a, uint64_t __b) {
uint32_t __c;
__asm__("crc32x %w0, %w1, %x2" : "=r" (__c) : "r"(__a), "r"(__b));
return __c;
}
#else
static inline uint32_t __crc32b(uint32_t __a, uint8_t __b) {
uint32_t __c;
__asm__("crc32b %0, %1, %2" : "=r" (__c) : "r"(__a), "r"(__b));
return __c;
}
static inline uint32_t __crc32h(uint32_t __a, uint16_t __b) {
uint32_t __c;
__asm__("crc32h %0, %1, %2" : "=r" (__c) : "r"(__a), "r"(__b));
return __c;
}
static inline uint32_t __crc32w(uint32_t __a, uint32_t __b) {
uint32_t __c;
__asm__("crc32w %0, %1, %2" : "=r" (__c) : "r"(__a), "r"(__b));
return __c;
}
static inline uint32_t __crc32d(uint32_t __a, uint64_t __b) {
return __crc32w (__crc32w (__a, __b & 0xffffffffULL), __b >> 32);
}
#endif
#endif
#endif
#ifdef ARM_SIMD
#ifdef _MSC_VER
typedef uint32_t uint16x2_t;
#define __uqsub16 _arm_uqsub16
#elif !defined(ARM_SIMD_INTRIN)
typedef uint32_t uint16x2_t;
static inline uint16x2_t __uqsub16(uint16x2_t __a, uint16x2_t __b) {
uint16x2_t __c;
__asm__("uqsub16 %0, %1, %2" : "=r" (__c) : "r"(__a), "r"(__b));
return __c;
}
#endif
#endif
#endif // include guard ARM_ACLE_INTRINS_H

View file

@ -1,346 +0,0 @@
/* Copyright (C) 1995-2011, 2016 Mark Adler
* Copyright (C) 2017 ARM Holdings Inc.
* Authors:
* Adenilson Cavalcanti <adenilson.cavalcanti@arm.com>
* Adam Stylinski <kungfujesus06@gmail.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef ARM_NEON
#include "zbuild.h"
#include "neon_intrins.h"
#include "adler32_p.h"
static const uint16_t ALIGNED_(64) taps[64] = {
64, 63, 62, 61, 60, 59, 58, 57,
56, 55, 54, 53, 52, 51, 50, 49,
48, 47, 46, 45, 44, 43, 42, 41,
40, 39, 38, 37, 36, 35, 34, 33,
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 };
Z_FORCEINLINE static void NEON_accum32_copy(uint32_t *s, uint8_t *dst, const uint8_t *buf, size_t len) {
uint32x4_t adacc = vdupq_n_u32(0);
uint32x4_t s2acc = vdupq_n_u32(0);
uint32x4_t s2acc_0 = vdupq_n_u32(0);
uint32x4_t s2acc_1 = vdupq_n_u32(0);
uint32x4_t s2acc_2 = vdupq_n_u32(0);
adacc = vsetq_lane_u32(s[0], adacc, 0);
s2acc = vsetq_lane_u32(s[1], s2acc, 0);
uint32x4_t s3acc = vdupq_n_u32(0);
uint32x4_t adacc_prev = adacc;
uint16x8_t s2_0, s2_1, s2_2, s2_3;
s2_0 = s2_1 = s2_2 = s2_3 = vdupq_n_u16(0);
uint16x8_t s2_4, s2_5, s2_6, s2_7;
s2_4 = s2_5 = s2_6 = s2_7 = vdupq_n_u16(0);
size_t num_iter = len >> 2;
int rem = len & 3;
for (size_t i = 0; i < num_iter; ++i) {
uint8x16_t d0 = vld1q_u8_ex(buf, 128);
uint8x16_t d1 = vld1q_u8_ex(buf + 16, 128);
uint8x16_t d2 = vld1q_u8_ex(buf + 32, 128);
uint8x16_t d3 = vld1q_u8_ex(buf + 48, 128);
vst1q_u8(dst, d0);
vst1q_u8(dst + 16, d1);
vst1q_u8(dst + 32, d2);
vst1q_u8(dst + 48, d3);
dst += 64;
/* Unfortunately it doesn't look like there's a direct sum 8 bit to 32
* bit instruction, we'll have to make due summing to 16 bits first */
uint16x8x2_t hsum, hsum_fold;
hsum.val[0] = vpaddlq_u8(d0);
hsum.val[1] = vpaddlq_u8(d1);
hsum_fold.val[0] = vpadalq_u8(hsum.val[0], d2);
hsum_fold.val[1] = vpadalq_u8(hsum.val[1], d3);
adacc = vpadalq_u16(adacc, hsum_fold.val[0]);
s3acc = vaddq_u32(s3acc, adacc_prev);
adacc = vpadalq_u16(adacc, hsum_fold.val[1]);
/* If we do straight widening additions to the 16 bit values, we don't incur
* the usual penalties of a pairwise add. We can defer the multiplications
* until the very end. These will not overflow because we are incurring at
* most 408 loop iterations (NMAX / 64), and a given lane is only going to be
* summed into once. This means for the maximum input size, the largest value
* we will see is 255 * 102 = 26010, safely under uint16 max */
s2_0 = vaddw_u8(s2_0, vget_low_u8(d0));
s2_1 = vaddw_high_u8(s2_1, d0);
s2_2 = vaddw_u8(s2_2, vget_low_u8(d1));
s2_3 = vaddw_high_u8(s2_3, d1);
s2_4 = vaddw_u8(s2_4, vget_low_u8(d2));
s2_5 = vaddw_high_u8(s2_5, d2);
s2_6 = vaddw_u8(s2_6, vget_low_u8(d3));
s2_7 = vaddw_high_u8(s2_7, d3);
adacc_prev = adacc;
buf += 64;
}
s3acc = vshlq_n_u32(s3acc, 6);
if (rem) {
uint32x4_t s3acc_0 = vdupq_n_u32(0);
while (rem--) {
uint8x16_t d0 = vld1q_u8_ex(buf, 128);
vst1q_u8(dst, d0);
dst += 16;
uint16x8_t adler;
adler = vpaddlq_u8(d0);
s2_6 = vaddw_u8(s2_6, vget_low_u8(d0));
s2_7 = vaddw_high_u8(s2_7, d0);
adacc = vpadalq_u16(adacc, adler);
s3acc_0 = vaddq_u32(s3acc_0, adacc_prev);
adacc_prev = adacc;
buf += 16;
}
s3acc_0 = vshlq_n_u32(s3acc_0, 4);
s3acc = vaddq_u32(s3acc_0, s3acc);
}
uint16x8x4_t t0_t3 = vld1q_u16_x4_ex(taps, 256);
uint16x8x4_t t4_t7 = vld1q_u16_x4_ex(taps + 32, 256);
s2acc = vmlal_high_u16(s2acc, t0_t3.val[0], s2_0);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[0]), vget_low_u16(s2_0));
s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[1], s2_1);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[1]), vget_low_u16(s2_1));
s2acc = vmlal_high_u16(s2acc, t0_t3.val[2], s2_2);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[2]), vget_low_u16(s2_2));
s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[3], s2_3);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[3]), vget_low_u16(s2_3));
s2acc = vmlal_high_u16(s2acc, t4_t7.val[0], s2_4);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[0]), vget_low_u16(s2_4));
s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[1], s2_5);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[1]), vget_low_u16(s2_5));
s2acc = vmlal_high_u16(s2acc, t4_t7.val[2], s2_6);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[2]), vget_low_u16(s2_6));
s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[3], s2_7);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[3]), vget_low_u16(s2_7));
s2acc = vaddq_u32(s2acc_0, s2acc);
s2acc_2 = vaddq_u32(s2acc_1, s2acc_2);
s2acc = vaddq_u32(s2acc, s2acc_2);
uint32x2_t adacc2, s2acc2, as;
s2acc = vaddq_u32(s2acc, s3acc);
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);
}
Z_FORCEINLINE static void NEON_accum32(uint32_t *s, const uint8_t *buf, size_t len) {
uint32x4_t adacc = vdupq_n_u32(0);
uint32x4_t s2acc = vdupq_n_u32(0);
uint32x4_t s2acc_0 = vdupq_n_u32(0);
uint32x4_t s2acc_1 = vdupq_n_u32(0);
uint32x4_t s2acc_2 = vdupq_n_u32(0);
adacc = vsetq_lane_u32(s[0], adacc, 0);
s2acc = vsetq_lane_u32(s[1], s2acc, 0);
uint32x4_t s3acc = vdupq_n_u32(0);
uint32x4_t adacc_prev = adacc;
uint16x8_t s2_0, s2_1, s2_2, s2_3;
s2_0 = s2_1 = s2_2 = s2_3 = vdupq_n_u16(0);
uint16x8_t s2_4, s2_5, s2_6, s2_7;
s2_4 = s2_5 = s2_6 = s2_7 = vdupq_n_u16(0);
size_t num_iter = len >> 2;
int rem = len & 3;
for (size_t i = 0; i < num_iter; ++i) {
uint8x16x4_t d0_d3 = vld1q_u8_x4_ex(buf, 256);
/* Unfortunately it doesn't look like there's a direct sum 8 bit to 32
* bit instruction, we'll have to make due summing to 16 bits first */
uint16x8x2_t hsum, hsum_fold;
hsum.val[0] = vpaddlq_u8(d0_d3.val[0]);
hsum.val[1] = vpaddlq_u8(d0_d3.val[1]);
hsum_fold.val[0] = vpadalq_u8(hsum.val[0], d0_d3.val[2]);
hsum_fold.val[1] = vpadalq_u8(hsum.val[1], d0_d3.val[3]);
adacc = vpadalq_u16(adacc, hsum_fold.val[0]);
s3acc = vaddq_u32(s3acc, adacc_prev);
adacc = vpadalq_u16(adacc, hsum_fold.val[1]);
/* If we do straight widening additions to the 16 bit values, we don't incur
* the usual penalties of a pairwise add. We can defer the multiplications
* until the very end. These will not overflow because we are incurring at
* most 408 loop iterations (NMAX / 64), and a given lane is only going to be
* summed into once. This means for the maximum input size, the largest value
* we will see is 255 * 102 = 26010, safely under uint16 max */
s2_0 = vaddw_u8(s2_0, vget_low_u8(d0_d3.val[0]));
s2_1 = vaddw_high_u8(s2_1, d0_d3.val[0]);
s2_2 = vaddw_u8(s2_2, vget_low_u8(d0_d3.val[1]));
s2_3 = vaddw_high_u8(s2_3, d0_d3.val[1]);
s2_4 = vaddw_u8(s2_4, vget_low_u8(d0_d3.val[2]));
s2_5 = vaddw_high_u8(s2_5, d0_d3.val[2]);
s2_6 = vaddw_u8(s2_6, vget_low_u8(d0_d3.val[3]));
s2_7 = vaddw_high_u8(s2_7, d0_d3.val[3]);
adacc_prev = adacc;
buf += 64;
}
s3acc = vshlq_n_u32(s3acc, 6);
if (rem) {
uint32x4_t s3acc_0 = vdupq_n_u32(0);
while (rem--) {
uint8x16_t d0 = vld1q_u8_ex(buf, 128);
uint16x8_t adler;
adler = vpaddlq_u8(d0);
s2_6 = vaddw_u8(s2_6, vget_low_u8(d0));
s2_7 = vaddw_high_u8(s2_7, d0);
adacc = vpadalq_u16(adacc, adler);
s3acc_0 = vaddq_u32(s3acc_0, adacc_prev);
adacc_prev = adacc;
buf += 16;
}
s3acc_0 = vshlq_n_u32(s3acc_0, 4);
s3acc = vaddq_u32(s3acc_0, s3acc);
}
uint16x8x4_t t0_t3 = vld1q_u16_x4_ex(taps, 256);
uint16x8x4_t t4_t7 = vld1q_u16_x4_ex(taps + 32, 256);
s2acc = vmlal_high_u16(s2acc, t0_t3.val[0], s2_0);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[0]), vget_low_u16(s2_0));
s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[1], s2_1);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[1]), vget_low_u16(s2_1));
s2acc = vmlal_high_u16(s2acc, t0_t3.val[2], s2_2);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.val[2]), vget_low_u16(s2_2));
s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.val[3], s2_3);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.val[3]), vget_low_u16(s2_3));
s2acc = vmlal_high_u16(s2acc, t4_t7.val[0], s2_4);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[0]), vget_low_u16(s2_4));
s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[1], s2_5);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[1]), vget_low_u16(s2_5));
s2acc = vmlal_high_u16(s2acc, t4_t7.val[2], s2_6);
s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.val[2]), vget_low_u16(s2_6));
s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.val[3], s2_7);
s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.val[3]), vget_low_u16(s2_7));
s2acc = vaddq_u32(s2acc_0, s2acc);
s2acc_2 = vaddq_u32(s2acc_1, s2acc_2);
s2acc = vaddq_u32(s2acc, s2acc_2);
uint32x2_t adacc2, s2acc2, as;
s2acc = vaddq_u32(s2acc, s3acc);
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);
}
Z_FORCEINLINE static uint32_t adler32_copy_impl(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len, const int COPY) {
/* split Adler-32 into component sums */
uint32_t sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (UNLIKELY(len == 1))
return adler32_copy_tail(adler, dst, src, 1, sum2, 1, 1, COPY);
/* in case short lengths are provided, keep it somewhat fast */
if (UNLIKELY(len < 16))
return adler32_copy_tail(adler, dst, src, len, sum2, 1, 15, COPY);
uint32_t pair[2];
/* Split Adler-32 into component sums, it can be supplied by
* the caller sites (e.g. in a PNG file).
*/
pair[0] = adler;
pair[1] = sum2;
/* If memory is not SIMD aligned, do scalar sums to an aligned
* offset, provided that doing so doesn't completely eliminate
* SIMD operation. Aligned loads are still faster on ARM, even
* when there's no explicit aligned load instruction. Note:
* the code currently emits an alignment hint in the instruction
* for exactly 256 bits when supported by the compiler. Several ARM
* SIPs have small penalties for cacheline crossing loads as well (so
* really 512 bits is the optimal alignment of the buffer). 32 bytes
* should strike a balance, though. The Cortex-A8 and Cortex-A9
* processors are documented to benefit from 128 bit and 64 bit
* alignment, but it's unclear which other SIPs will benefit from it.
* In the copying variant we use fallback to 4x loads and 4x stores,
* as ld1x4 seems to block ILP when stores are in the mix */
size_t align_diff = MIN(ALIGN_DIFF(src, 32), len);
size_t n = NMAX_ALIGNED32;
if (align_diff) {
adler32_copy_align(&pair[0], dst, src, align_diff, &pair[1], 31, COPY);
if (COPY)
dst += align_diff;
src += align_diff;
len -= align_diff;
n = ALIGN_DOWN(n - align_diff, 32);
}
while (len >= 16) {
n = MIN(len, n);
if (COPY)
NEON_accum32_copy(pair, dst, src, n >> 4);
else
NEON_accum32(pair, src, n >> 4);
pair[0] %= BASE;
pair[1] %= BASE;
size_t k = (n >> 4) << 4;
src += k;
if (COPY)
dst += k;
len -= k;
n = NMAX_ALIGNED32;
}
/* Process tail (len < 16). */
return adler32_copy_tail(pair[0], dst, src, len, pair[1], len != 0 || align_diff, 15, COPY);
}
Z_INTERNAL uint32_t adler32_neon(uint32_t adler, const uint8_t *src, size_t len) {
return adler32_copy_impl(adler, NULL, src, len, 0);
}
Z_INTERNAL uint32_t adler32_copy_neon(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) {
#if OPTIMAL_CMP >= 32
return adler32_copy_impl(adler, dst, src, len, 1);
#else
/* Without unaligned access, interleaved stores get decomposed into byte ops */
adler = adler32_neon(adler, src, len);
memcpy(dst, src, len);
return adler;
#endif
}
#endif

View file

@ -1,334 +0,0 @@
#ifdef ARM_FEATURES
#include "zbuild.h"
#include "arm_features.h"
#if defined(HAVE_SYS_AUXV_H)
# include <sys/auxv.h>
# ifdef ARM_ASM_HWCAP
# include <asm/hwcap.h>
# endif
#elif defined(__FreeBSD__) && defined(ARCH_64BIT)
# include <machine/armreg.h>
# ifndef ID_AA64ISAR0_CRC32_VAL
# define ID_AA64ISAR0_CRC32_VAL ID_AA64ISAR0_CRC32
# endif
#elif defined(__OpenBSD__) && defined(ARCH_64BIT)
# include <machine/armreg.h>
# include <machine/cpu.h>
# include <sys/sysctl.h>
# include <sys/types.h>
#elif defined(__APPLE__)
# if !defined(_DARWIN_C_SOURCE)
# define _DARWIN_C_SOURCE /* enable types aliases (eg u_int) */
# endif
# include <sys/sysctl.h>
#elif defined(_WIN32)
# include <windows.h>
#endif
static int arm_has_crc32(void) {
int has_crc32 = 0;
#if defined(__ARM_FEATURE_CRC32)
/* Compile-time check */
has_crc32 = 1;
#elif defined(__linux__) && defined(HAVE_SYS_AUXV_H)
# ifdef HWCAP_CRC32
has_crc32 = (getauxval(AT_HWCAP) & HWCAP_CRC32) != 0;
# elif defined(HWCAP2_CRC32)
has_crc32 = (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0;
# endif
#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(HAVE_SYS_AUXV_H)
# ifdef HWCAP_CRC32
unsigned long hwcap = 0;
elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
has_crc32 = (hwcap & HWCAP_CRC32) != 0;
# elif defined(HWCAP2_CRC32)
unsigned long hwcap2 = 0;
elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2));
has_crc32 = (hwcap2 & HWCAP2_CRC32) != 0;
# endif
#elif defined(__FreeBSD__) && defined(ARCH_64BIT)
has_crc32 = getenv("QEMU_EMULATING") == NULL
&& ID_AA64ISAR0_CRC32_VAL(READ_SPECIALREG(id_aa64isar0_el1)) >= ID_AA64ISAR0_CRC32_BASE;
#elif defined(__OpenBSD__) && defined(ARCH_64BIT)
int isar0_mib[] = { CTL_MACHDEP, CPU_ID_AA64ISAR0 };
uint64_t isar0 = 0;
size_t len = sizeof(isar0);
if (sysctl(isar0_mib, 2, &isar0, &len, NULL, 0) != -1) {
has_crc32 = ID_AA64ISAR0_CRC32(isar0) >= ID_AA64ISAR0_CRC32_BASE;
}
#elif defined(__APPLE__)
int has_feat = 0;
size_t size = sizeof(has_feat);
has_crc32 = sysctlbyname("hw.optional.armv8_crc32", &has_feat, &size, NULL, 0) == 0
&& has_feat == 1;
#elif defined(_WIN32)
has_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
#endif
return has_crc32;
}
static int arm_has_pmull(void) {
int has_pmull = 0;
#if defined(__ARM_FEATURE_CRYPTO) || defined(__ARM_FEATURE_AES)
/* Compile-time check */
has_pmull = 1;
#elif defined(__linux__) && defined(HAVE_SYS_AUXV_H)
# ifdef HWCAP_PMULL
has_pmull = (getauxval(AT_HWCAP) & HWCAP_PMULL) != 0;
# elif defined(HWCAP_AES)
/* PMULL is part of crypto extension, check for AES as proxy */
has_pmull = (getauxval(AT_HWCAP) & HWCAP_AES) != 0;
# endif
#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(HAVE_SYS_AUXV_H)
# ifdef HWCAP_PMULL
unsigned long hwcap = 0;
elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
has_pmull = (hwcap & HWCAP_PMULL) != 0;
# elif defined(HWCAP_AES)
/* PMULL is part of crypto extension, check for AES as proxy */
unsigned long hwcap = 0;
elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
has_pmull = (hwcap & HWCAP_AES) != 0;
# endif
#elif defined(__FreeBSD__) && defined(ARCH_64BIT)
/* Check for AES feature as PMULL is part of crypto extension */
has_pmull = getenv("QEMU_EMULATING") == NULL
&& ID_AA64ISAR0_AES_VAL(READ_SPECIALREG(id_aa64isar0_el1)) >= ID_AA64ISAR0_AES_BASE;
#elif defined(__OpenBSD__) && defined(ARCH_64BIT)
int isar0_mib[] = { CTL_MACHDEP, CPU_ID_AA64ISAR0 };
uint64_t isar0 = 0;
size_t len = sizeof(isar0);
if (sysctl(isar0_mib, 2, &isar0, &len, NULL, 0) != -1) {
has_pmull = ID_AA64ISAR0_AES(isar0) >= ID_AA64ISAR0_AES_BASE;
}
#elif defined(__APPLE__)
int has_feat = 0;
size_t size = sizeof(has_feat);
has_pmull = sysctlbyname("hw.optional.arm.FEAT_PMULL", &has_feat, &size, NULL, 0) == 0
&& has_feat == 1;
#elif defined(_WIN32)
/* Windows checks for crypto/AES support */
# ifdef PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE
has_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
# endif
#endif
return has_pmull;
}
static int arm_has_eor3(void) {
int has_eor3 = 0;
#if defined(__ARM_FEATURE_SHA3)
/* Compile-time check */
has_eor3 = 1;
#elif defined(__linux__) && defined(HAVE_SYS_AUXV_H)
/* EOR3 is part of SHA3 extension, check HWCAP2_SHA3 */
# ifdef HWCAP2_SHA3
has_eor3 = (getauxval(AT_HWCAP2) & HWCAP2_SHA3) != 0;
# elif defined(HWCAP_SHA3)
has_eor3 = (getauxval(AT_HWCAP) & HWCAP_SHA3) != 0;
# endif
#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(HAVE_SYS_AUXV_H)
# ifdef HWCAP2_SHA3
unsigned long hwcap2 = 0;
elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2));
has_eor3 = (hwcap2 & HWCAP2_SHA3) != 0;
# elif defined(HWCAP_SHA3)
unsigned long hwcap = 0;
elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
has_eor3 = (hwcap & HWCAP_SHA3) != 0;
# endif
#elif defined(__FreeBSD__) && defined(ARCH_64BIT)
/* FreeBSD: check for SHA3 in id_aa64isar0_el1 */
# ifdef ID_AA64ISAR0_SHA3_VAL
has_eor3 = getenv("QEMU_EMULATING") == NULL
&& ID_AA64ISAR0_SHA3_VAL(READ_SPECIALREG(id_aa64isar0_el1)) >= ID_AA64ISAR0_SHA3_BASE;
# endif
#elif defined(__OpenBSD__) && defined(ARCH_64BIT)
# ifdef ID_AA64ISAR0_SHA3
int isar0_mib[] = { CTL_MACHDEP, CPU_ID_AA64ISAR0 };
uint64_t isar0 = 0;
size_t len = sizeof(isar0);
if (sysctl(isar0_mib, 2, &isar0, &len, NULL, 0) != -1) {
has_eor3 = ID_AA64ISAR0_SHA3(isar0) >= ID_AA64ISAR0_SHA3_IMPL;
}
# endif
#elif defined(__APPLE__)
/* All Apple Silicon (M1+) has SHA3/EOR3 support */
int has_feat = 0;
size_t size = sizeof(has_feat);
has_eor3 = sysctlbyname("hw.optional.arm.FEAT_SHA3", &has_feat, &size, NULL, 0) == 0
&& has_feat == 1;
/* Fallback to legacy name for older macOS versions */
if (!has_eor3) {
size = sizeof(has_feat);
has_eor3 = sysctlbyname("hw.optional.armv8_2_sha3", &has_feat, &size, NULL, 0) == 0
&& has_feat == 1;
}
#elif defined(_WIN32)
# ifdef PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE
has_eor3 = IsProcessorFeaturePresent(PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE);
# endif
#endif
return has_eor3;
}
/* AArch64 has neon. */
#ifdef ARCH_32BIT
static inline int arm_has_neon(void) {
int has_neon = 0;
#if defined(__ARM_NEON__) || defined(__ARM_NEON)
/* Compile-time check */
has_neon = 1;
#elif defined(__linux__) && defined(HAVE_SYS_AUXV_H)
# ifdef HWCAP_ARM_NEON
has_neon = (getauxval(AT_HWCAP) & HWCAP_ARM_NEON) != 0;
# elif defined(HWCAP_NEON)
has_neon = (getauxval(AT_HWCAP) & HWCAP_NEON) != 0;
# endif
#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(HAVE_SYS_AUXV_H)
# ifdef HWCAP_NEON
unsigned long hwcap = 0;
elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
has_neon = (hwcap & HWCAP_NEON) != 0;
# endif
#elif defined(__APPLE__)
int has_feat = 0;
size_t size = sizeof(has_feat);
has_neon = sysctlbyname("hw.optional.neon", &has_feat, &size, NULL, 0) == 0
&& has_feat == 1;
#elif defined(_M_ARM) && defined(WINAPI_FAMILY_PARTITION)
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
has_neon = 1; /* Always supported */
# endif
#endif
return has_neon;
}
#endif
/* AArch64 does not have ARMv6 SIMD. */
#ifdef ARCH_32BIT
static inline int arm_has_simd(void) {
int has_simd = 0;
#if defined(__ARM_FEATURE_SIMD32)
/* Compile-time check for ARMv6 SIMD */
has_simd = 1;
#elif defined(__linux__) && defined(HAVE_SYS_AUXV_H)
const char *platform = (const char *)getauxval(AT_PLATFORM);
has_simd = platform
&& (strncmp(platform, "v6l", 3) == 0
|| strncmp(platform, "v7l", 3) == 0
|| strncmp(platform, "v8l", 3) == 0);
#endif
return has_simd;
}
#endif
#if defined(ARCH_64BIT) && !defined(__APPLE__) && !defined(_WIN32)
/* MIDR_EL1 bit field definitions */
#define MIDR_IMPLEMENTOR(midr) (((midr) & (0xffU << 24)) >> 24)
#define MIDR_PARTNUM(midr) (((midr) & (0xfffU << 4)) >> 4)
/* ARM CPU Implementer IDs */
#define ARM_IMPLEMENTER_ARM 0x41
#define ARM_IMPLEMENTER_QUALCOMM 0x51
#define ARM_IMPLEMENTER_APPLE 0x61
/* ARM CPU Part Numbers */
/* Cortex-X series - Multiple PMULL lanes */
#define ARM_PART_CORTEX_X1 0xd44
#define ARM_PART_CORTEX_X1C 0xd4c
#define ARM_PART_CORTEX_X2 0xd48
#define ARM_PART_CORTEX_X3 0xd4e
#define ARM_PART_CORTEX_X4 0xd82
#define ARM_PART_CORTEX_X925 0xd85
/* Neoverse V/N2 series - Multiple PMULL lanes */
#define ARM_PART_NEOVERSE_N2 0xd49
#define ARM_PART_NEOVERSE_V1 0xd40
#define ARM_PART_NEOVERSE_V2 0xd4f
#define ARM_PART_NEOVERSE_V3 0xd8e
/* Snapdragon X Elite/Plus - Custom core */
#define QUALCOMM_PART_ORYON 0x001
static inline int arm_has_cpuid(void) {
int has_cpuid = 0;
#if defined(__linux__) && defined(HAVE_SYS_AUXV_H)
# ifdef HWCAP_CPUID
has_cpuid = (getauxval(AT_HWCAP) & HWCAP_CPUID) != 0;
# elif defined(HWCAP2_CPUID)
has_cpuid = (getauxval(AT_HWCAP2) & HWCAP2_CPUID) != 0;
# endif
#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(HAVE_SYS_AUXV_H)
# ifdef HWCAP_CPUID
unsigned long hwcap = 0;
elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
has_cpuid = (hwcap & HWCAP_CPUID) != 0;
# endif
#endif
return has_cpuid;
}
#endif
/* Determine if CPU has fast PMULL (multiple execution units) */
static inline int arm_cpu_has_fast_pmull(void) {
int has_fast_pmull = 0;
#if defined(__APPLE__)
/* On macOS, all Apple Silicon has fast PMULL */
has_fast_pmull = 1;
#elif defined(ARCH_64BIT) && !defined(_WIN32)
/* We need CPUID feature to read MIDR register */
if (!arm_has_cpuid())
return has_fast_pmull;
uint64_t midr;
__asm__ ("mrs %0, midr_el1" : "=r" (midr));
uint32_t implementer = MIDR_IMPLEMENTOR(midr);
uint32_t part = MIDR_PARTNUM(midr);
if (implementer == ARM_IMPLEMENTER_APPLE) {
/* All Apple Silicon (M1+) have fast PMULL */
has_fast_pmull = 1;
} else if (implementer == ARM_IMPLEMENTER_ARM) {
/* ARM Cortex-X and Neoverse V/N2 series have multi-lane PMULL */
switch (part) {
case ARM_PART_CORTEX_X1:
case ARM_PART_CORTEX_X1C:
case ARM_PART_CORTEX_X2:
case ARM_PART_CORTEX_X3:
case ARM_PART_CORTEX_X4:
case ARM_PART_CORTEX_X925:
case ARM_PART_NEOVERSE_N2:
case ARM_PART_NEOVERSE_V1:
case ARM_PART_NEOVERSE_V2:
case ARM_PART_NEOVERSE_V3:
has_fast_pmull = 1;
}
} else if (implementer == ARM_IMPLEMENTER_QUALCOMM) {
/* Qualcomm Oryon (Snapdragon X Elite/Plus) has fast PMULL */
if (part == QUALCOMM_PART_ORYON)
has_fast_pmull = 1;
}
#endif
return has_fast_pmull;
}
void Z_INTERNAL arm_check_features(struct arm_cpu_features *features) {
#ifdef ARCH_64BIT
features->has_simd = 0; /* never available */
features->has_neon = 1; /* always available */
#else
features->has_simd = arm_has_simd();
features->has_neon = arm_has_neon();
#endif
features->has_crc32 = arm_has_crc32();
features->has_pmull = arm_has_pmull();
features->has_eor3 = arm_has_eor3();
features->has_fast_pmull = features->has_pmull && arm_cpu_has_fast_pmull();
}
#endif

View file

@ -1,19 +0,0 @@
/* arm_features.h -- check for ARM features.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef ARM_FEATURES_H_
#define ARM_FEATURES_H_
struct arm_cpu_features {
int has_simd;
int has_neon;
int has_crc32;
int has_pmull;
int has_eor3;
int has_fast_pmull;
};
void Z_INTERNAL arm_check_features(struct arm_cpu_features *features);
#endif /* ARM_FEATURES_H_ */

View file

@ -1,89 +0,0 @@
/* arm_functions.h -- ARM implementations for arch-specific functions.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef ARM_FUNCTIONS_H_
#define ARM_FUNCTIONS_H_
#include "arm_natives.h"
#ifdef ARM_NEON
uint32_t adler32_neon(uint32_t adler, const uint8_t *buf, size_t len);
uint32_t adler32_copy_neon(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len);
uint8_t* chunkmemset_safe_neon(uint8_t *out, uint8_t *from, size_t len, size_t left);
uint32_t compare256_neon(const uint8_t *src0, const uint8_t *src1);
void inflate_fast_neon(PREFIX3(stream) *strm, uint32_t start);
uint32_t longest_match_neon(deflate_state *const s, uint32_t cur_match);
uint32_t longest_match_roll_neon(deflate_state *const s, uint32_t cur_match);
void slide_hash_neon(deflate_state *s);
#endif
#ifndef ARM_NEON_NATIVE
# define ADLER32_FALLBACK
# define CHUNKSET_FALLBACK
# define COMPARE256_FALLBACK
# ifndef ARM_SIMD_NATIVE
# define SLIDE_HASH_FALLBACK
# endif
#endif
#ifdef ARM_CRC32
uint32_t crc32_armv8(uint32_t crc, const uint8_t *buf, size_t len);
uint32_t crc32_copy_armv8(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len);
#endif
#ifdef ARM_PMULL_EOR3
uint32_t crc32_armv8_pmull_eor3(uint32_t crc, const uint8_t *buf, size_t len);
uint32_t crc32_copy_armv8_pmull_eor3(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len);
#endif
#if !defined(ARM_CRC32_NATIVE) && !defined(ARM_PMULL_EOR3_NATIVE)
# define CRC32_BRAID_FALLBACK
#endif
#ifdef ARM_SIMD
void slide_hash_armv6(deflate_state *s);
#endif
#ifdef DISABLE_RUNTIME_CPU_DETECTION
// ARM - SIMD
# ifdef ARM_SIMD_NATIVE
# undef native_slide_hash
# define native_slide_hash slide_hash_armv6
# endif
// ARM - NEON
# ifdef ARM_NEON_NATIVE
# undef native_adler32
# define native_adler32 adler32_neon
# undef native_adler32_copy
# define native_adler32_copy adler32_copy_neon
# undef native_chunkmemset_safe
# define native_chunkmemset_safe chunkmemset_safe_neon
# undef native_compare256
# define native_compare256 compare256_neon
# undef native_inflate_fast
# define native_inflate_fast inflate_fast_neon
# undef native_longest_match
# define native_longest_match longest_match_neon
# undef native_longest_match_roll
# define native_longest_match_roll longest_match_roll_neon
# undef native_slide_hash
# define native_slide_hash slide_hash_neon
# endif
// ARM - CRC32
# ifdef ARM_CRC32_NATIVE
# undef native_crc32
# define native_crc32 crc32_armv8
# undef native_crc32_copy
# define native_crc32_copy crc32_copy_armv8
# endif
// ARM - PMULL EOR3
# ifdef ARM_PMULL_EOR3_NATIVE
# undef native_crc32
# define native_crc32 crc32_armv8_pmull_eor3
# undef native_crc32_copy
# define native_crc32_copy crc32_copy_armv8_pmull_eor3
# endif
#endif
#endif /* ARM_FUNCTIONS_H_ */

View file

@ -1,31 +0,0 @@
/* arm_natives.h -- ARM compile-time feature detection macros.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef ARM_NATIVES_H_
#define ARM_NATIVES_H_
#if defined(__ARM_FEATURE_SIMD32)
# ifdef ARM_SIMD
# define ARM_SIMD_NATIVE
# endif
#endif
/* NEON is guaranteed on ARM64 (like SSE2 on x86-64) */
#if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ARCH_64BIT)
# ifdef ARM_NEON
# define ARM_NEON_NATIVE
# endif
#endif
/* CRC32 is optional in ARMv8.0, mandatory in ARMv8.1+ */
#if defined(__ARM_FEATURE_CRC32) || (defined(__ARM_ARCH) && __ARM_ARCH >= 801)
# ifdef ARM_CRC32
# define ARM_CRC32_NATIVE
# endif
#endif
#if defined(__ARM_FEATURE_CRC32) && defined(__ARM_FEATURE_CRYPTO) && defined(__ARM_FEATURE_SHA3)
# ifdef ARM_PMULL_EOR3
# define ARM_PMULL_EOR3_NATIVE
# endif
#endif
#endif /* ARM_NATIVES_H_ */

View file

@ -1,81 +0,0 @@
/* chunkset_neon.c -- NEON inline functions to copy small data chunks.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef ARM_NEON
#include "zbuild.h"
#include "zsanitizer.h"
#include "zmemory.h"
#include "neon_intrins.h"
#include "arch/shared/chunk_128bit_perm_idx_lut.h"
typedef uint8x16_t chunk_t;
#define HAVE_CHUNKMEMSET_2
#define HAVE_CHUNKMEMSET_4
#define HAVE_CHUNKMEMSET_8
#define HAVE_CHUNK_MAG
static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) {
*chunk = vreinterpretq_u8_u16(vdupq_n_u16(zng_memread_2(from)));
}
static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) {
*chunk = vreinterpretq_u8_u32(vdupq_n_u32(zng_memread_4(from)));
}
static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) {
*chunk = vreinterpretq_u8_u64(vdupq_n_u64(zng_memread_8(from)));
}
#define CHUNKSIZE chunksize_neon
#define CHUNKCOPY chunkcopy_neon
#define CHUNKUNROLL chunkunroll_neon
#define CHUNKMEMSET chunkmemset_neon
#define CHUNKMEMSET_SAFE chunkmemset_safe_neon
static inline void loadchunk(uint8_t const *s, chunk_t *chunk) {
*chunk = vld1q_u8(s);
}
static inline void storechunk(uint8_t *out, chunk_t *chunk) {
vst1q_u8(out, *chunk);
}
static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) {
lut_rem_pair lut_rem = perm_idx_lut[dist - 3];
*chunk_rem = lut_rem.remval;
/* See note in chunkset_ssse3.c for why this is ok */
__msan_unpoison(buf + dist, 16 - dist);
/* This version of table is only available on aarch64 */
#if defined(ARCH_ARM) && defined(ARCH_64BIT)
uint8x16_t ret_vec = vld1q_u8(buf);
uint8x16_t perm_vec = vld1q_u8_ex(permute_table + lut_rem.idx, 128);
return vqtbl1q_u8(ret_vec, perm_vec);
#else
uint8x8_t ret0, ret1, a, b, perm_vec0, perm_vec1;
perm_vec0 = vld1_u8_ex(permute_table + lut_rem.idx, 64);
perm_vec1 = vld1_u8_ex(permute_table + lut_rem.idx + 8, 64);
a = vld1_u8(buf);
b = vld1_u8(buf + 8);
ret0 = vtbl1_u8(a, perm_vec0);
uint8x8x2_t ab;
ab.val[0] = a;
ab.val[1] = b;
ret1 = vtbl2_u8(ab, perm_vec1);
return vcombine_u8(ret0, ret1);
#endif
}
#include "chunkset_tpl.h"
#define INFLATE_FAST inflate_fast_neon
#include "inffast_tpl.h"
#endif

View file

@ -1,56 +0,0 @@
/* compare256_neon.c - NEON version of compare256
* Copyright (C) 2022 Nathan Moinvaziri
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zbuild.h"
#include "zmemory.h"
#include "deflate.h"
#include "fallback_builtins.h"
#if defined(ARM_NEON)
#include "neon_intrins.h"
static inline uint32_t compare256_neon_static(const uint8_t *src0, const uint8_t *src1) {
uint32_t len = 0;
do {
uint8x16_t a, b, cmp;
uint64_t lane;
a = vld1q_u8(src0);
b = vld1q_u8(src1);
cmp = veorq_u8(a, b);
lane = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 0);
if (lane)
return len + zng_first_diff_byte64(lane);
len += 8;
lane = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 1);
if (lane)
return len + zng_first_diff_byte64(lane);
len += 8;
src0 += 16, src1 += 16;
} while (len < 256);
return 256;
}
Z_INTERNAL uint32_t compare256_neon(const uint8_t *src0, const uint8_t *src1) {
return compare256_neon_static(src0, src1);
}
#define LONGEST_MATCH longest_match_neon
#define COMPARE256 compare256_neon_static
#include "match_tpl.h"
#define LONGEST_MATCH_ROLL
#define LONGEST_MATCH longest_match_roll_neon
#define COMPARE256 compare256_neon_static
#include "match_tpl.h"
#endif

View file

@ -1,30 +0,0 @@
/* crc32_armv8.c -- compute the CRC-32 of a data stream
* Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
* Copyright (C) 2016 Yang Zhang
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef ARM_CRC32
#include "zbuild.h"
#include "acle_intrins.h"
#include "crc32_armv8_p.h"
#include "arch/shared/crc32_hw_copy_impl_tpl.h"
Z_INTERNAL Z_TARGET_CRC uint32_t crc32_armv8(uint32_t crc, const uint8_t *buf, size_t len) {
return crc32_hw_copy_impl(crc, NULL, buf, len, 0);
}
Z_INTERNAL Z_TARGET_CRC uint32_t crc32_copy_armv8(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) {
#if OPTIMAL_CMP >= 32
return crc32_hw_copy_impl(crc, dst, src, len, 1);
#else
/* Without unaligned access, interleaved stores get decomposed into byte ops */
crc = crc32_armv8(crc, src, len);
memcpy(dst, src, len);
return crc;
#endif
}
#endif

View file

@ -1,18 +0,0 @@
/* crc32_armv8_p.h -- Private shared inline ARMv8 CRC32 functions
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef CRC32_ARMV8_P_H
#define CRC32_ARMV8_P_H
#include "zbuild.h"
#include "acle_intrins.h"
#define CRC32B(crc, val) __crc32b((crc), (val))
#define CRC32H(crc, val) __crc32h((crc), (val))
#define CRC32W(crc, val) __crc32w((crc), (val))
#define CRC32D(crc, val) __crc32d((crc), (val))
#include "arch/shared/crc32_hw_common_tpl.h"
#endif /* CRC32_ARMV8_P_H */

View file

@ -1,366 +0,0 @@
/* crc32_armv8_pmull_eor3.c -- ARMv8 CRC32 using PMULL + EOR3 (SHA3 extension)
* Copyright (C) 2025 Peter Cawley
* https://github.com/corsix/fast-crc32
* For conditions of distribution and use, see copyright notice in zlib.h
*
* This uses EOR3 (3-way XOR) from ARMv8.2-A SHA3 extension to save instructions.
* Uses 3-way parallel scalar CRC + 9 PMULL vector lanes, processing 192 bytes/iter.
*/
#ifdef ARM_PMULL_EOR3
#include "zbuild.h"
#include "zutil.h"
#include "acle_intrins.h"
#include "neon_intrins.h"
#include "crc32_armv8_p.h"
/* Carryless multiply low 64 bits: a[0] * b[0] */
static inline uint64x2_t clmul_lo(uint64x2_t a, uint64x2_t b) {
#ifdef _MSC_VER
return vreinterpretq_u64_p128(vmull_p64(
vget_low_p64(vreinterpret_p64_u64(a)),
vget_low_p64(vreinterpret_p64_u64(b))));
#else
return vreinterpretq_u64_p128(vmull_p64(
vget_lane_p64(vreinterpret_p64_u64(vget_low_u64(a)), 0),
vget_lane_p64(vreinterpret_p64_u64(vget_low_u64(b)), 0)));
#endif
}
/* Carryless multiply high 64 bits: a[1] * b[1] */
static inline uint64x2_t clmul_hi(uint64x2_t a, uint64x2_t b) {
return vreinterpretq_u64_p128(vmull_high_p64(vreinterpretq_p64_u64(a), vreinterpretq_p64_u64(b)));
}
/* Carryless multiply of two 32-bit scalars: a * b (returns 64-bit result in 128-bit vector) */
static inline uint64x2_t clmul_scalar(uint32_t a, uint32_t b) {
#ifdef _MSC_VER
return vreinterpretq_u64_p128(vmull_p64(vdup_n_p64((poly64_t)a), vdup_n_p64((poly64_t)b)));
#else
return vreinterpretq_u64_p128(vmull_p64((poly64_t)a, (poly64_t)b));
#endif
}
/* Compute x^n mod P (CRC-32 polynomial) in log(n) time, where P = 0x104c11db7 */
static uint32_t xnmodp(uint64_t n) {
uint64_t stack = ~(uint64_t)1;
uint32_t acc, low;
for (; n > 191; n = (n >> 1) - 16) {
stack = (stack << 1) + (n & 1);
}
stack = ~stack;
acc = ((uint32_t)0x80000000) >> (n & 31);
for (n >>= 5; n; --n) {
acc = __crc32w(acc, 0);
}
while ((low = stack & 1), stack >>= 1) {
poly8x8_t x = vreinterpret_p8_u64(vmov_n_u64(acc));
uint64_t y = vgetq_lane_u64(vreinterpretq_u64_p16(vmull_p8(x, x)), 0);
acc = __crc32d(0, y << low);
}
return acc;
}
/* Shift CRC forward by nbytes: equivalent to appending nbytes of zeros to the data stream */
static inline uint64x2_t crc_shift(uint32_t crc, size_t nbytes) {
Assert(nbytes >= 5, "crc_shift requires nbytes >= 5");
return clmul_scalar(crc, xnmodp(nbytes * 8 - 33));
}
Z_FORCEINLINE static Z_TARGET_PMULL_EOR3 uint32_t crc32_copy_impl(uint32_t crc, uint8_t *dst, const uint8_t *src,
size_t len, const int COPY) {
uint32_t crc0 = ~crc;
if (UNLIKELY(len == 1)) {
if (COPY)
*dst = *src;
crc0 = __crc32b(crc0, *src);
return ~crc0;
}
/* Align to 16-byte boundary for vector path */
uintptr_t align_diff = ALIGN_DIFF(src, 16);
if (align_diff)
crc0 = crc32_hw_align(crc0, &dst, &src, &len, align_diff, COPY);
/* 3-way scalar CRC + 9-way PMULL folding (192 bytes/iter) */
if (len >= 192) {
size_t blk = len / 192; /* Number of 192-byte blocks */
size_t klen = blk * 16; /* Scalar stride per CRC lane */
const uint8_t *end = src + len;
const uint8_t *src0 = src;
const uint8_t *src1 = src + klen;
const uint8_t *src2 = src + klen * 2;
const uint8_t *srcv = src + klen * 3; /* Vector data starts after scalar lanes */
uint32_t crc1 = 0, crc2 = 0;
uint64x2_t vc0, vc1, vc2;
uint64_t vc;
/* Load first 9 vector chunks (144 bytes) */
uint64x2_t x0 = vld1q_u64_ex((const uint64_t*)srcv, 128), y0;
uint64x2_t x1 = vld1q_u64_ex((const uint64_t*)(srcv + 16), 128), y1;
uint64x2_t x2 = vld1q_u64_ex((const uint64_t*)(srcv + 32), 128), y2;
uint64x2_t x3 = vld1q_u64_ex((const uint64_t*)(srcv + 48), 128), y3;
uint64x2_t x4 = vld1q_u64_ex((const uint64_t*)(srcv + 64), 128), y4;
uint64x2_t x5 = vld1q_u64_ex((const uint64_t*)(srcv + 80), 128), y5;
uint64x2_t x6 = vld1q_u64_ex((const uint64_t*)(srcv + 96), 128), y6;
uint64x2_t x7 = vld1q_u64_ex((const uint64_t*)(srcv + 112), 128), y7;
uint64x2_t x8 = vld1q_u64_ex((const uint64_t*)(srcv + 128), 128), y8;
uint64x2_t k;
/* k = {x^144 mod P, x^144+64 mod P} for 144-byte fold */
{ static const uint64_t ALIGNED_(16) k_[] = {0x26b70c3d, 0x3f41287a}; k = vld1q_u64_ex(k_, 128); }
/* Per-region dst pointers */
uint8_t *dst0 = dst;
uint8_t *dst1 = NULL;
uint8_t *dst2 = NULL;
uint8_t *dst_v = NULL;
if (COPY) {
dst1 = dst + klen;
dst2 = dst + klen * 2;
dst_v = dst + klen * 3;
vst1q_u8(dst_v, vreinterpretq_u8_u64(x0));
vst1q_u8(dst_v + 16, vreinterpretq_u8_u64(x1));
vst1q_u8(dst_v + 32, vreinterpretq_u8_u64(x2));
vst1q_u8(dst_v + 48, vreinterpretq_u8_u64(x3));
vst1q_u8(dst_v + 64, vreinterpretq_u8_u64(x4));
vst1q_u8(dst_v + 80, vreinterpretq_u8_u64(x5));
vst1q_u8(dst_v + 96, vreinterpretq_u8_u64(x6));
vst1q_u8(dst_v + 112, vreinterpretq_u8_u64(x7));
vst1q_u8(dst_v + 128, vreinterpretq_u8_u64(x8));
dst_v += 144;
}
srcv += 144;
/* Fold 9 vectors + 3-way parallel scalar CRC */
if (blk > 1) {
/* Only form a limit pointer when we have at least 2 blocks. */
const uint8_t *limit = src0 + klen - 32;
while (src0 <= limit) {
/* Fold all 9 vector lanes using PMULL */
y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k);
y1 = clmul_lo(x1, k), x1 = clmul_hi(x1, k);
y2 = clmul_lo(x2, k), x2 = clmul_hi(x2, k);
y3 = clmul_lo(x3, k), x3 = clmul_hi(x3, k);
y4 = clmul_lo(x4, k), x4 = clmul_hi(x4, k);
y5 = clmul_lo(x5, k), x5 = clmul_hi(x5, k);
y6 = clmul_lo(x6, k), x6 = clmul_hi(x6, k);
y7 = clmul_lo(x7, k), x7 = clmul_hi(x7, k);
y8 = clmul_lo(x8, k), x8 = clmul_hi(x8, k);
/* EOR3: combine hi*k, lo*k, and new data in one instruction */
{
uint64x2_t d0 = vld1q_u64_ex((const uint64_t*)srcv, 128);
uint64x2_t d1 = vld1q_u64_ex((const uint64_t*)(srcv + 16), 128);
uint64x2_t d2 = vld1q_u64_ex((const uint64_t*)(srcv + 32), 128);
uint64x2_t d3 = vld1q_u64_ex((const uint64_t*)(srcv + 48), 128);
uint64x2_t d4 = vld1q_u64_ex((const uint64_t*)(srcv + 64), 128);
uint64x2_t d5 = vld1q_u64_ex((const uint64_t*)(srcv + 80), 128);
uint64x2_t d6 = vld1q_u64_ex((const uint64_t*)(srcv + 96), 128);
uint64x2_t d7 = vld1q_u64_ex((const uint64_t*)(srcv + 112), 128);
uint64x2_t d8 = vld1q_u64_ex((const uint64_t*)(srcv + 128), 128);
if (COPY) {
vst1q_u8(dst_v, vreinterpretq_u8_u64(d0));
vst1q_u8(dst_v + 16, vreinterpretq_u8_u64(d1));
vst1q_u8(dst_v + 32, vreinterpretq_u8_u64(d2));
vst1q_u8(dst_v + 48, vreinterpretq_u8_u64(d3));
vst1q_u8(dst_v + 64, vreinterpretq_u8_u64(d4));
vst1q_u8(dst_v + 80, vreinterpretq_u8_u64(d5));
vst1q_u8(dst_v + 96, vreinterpretq_u8_u64(d6));
vst1q_u8(dst_v + 112, vreinterpretq_u8_u64(d7));
vst1q_u8(dst_v + 128, vreinterpretq_u8_u64(d8));
dst_v += 144;
}
x0 = veor3q_u64(x0, y0, d0);
x1 = veor3q_u64(x1, y1, d1);
x2 = veor3q_u64(x2, y2, d2);
x3 = veor3q_u64(x3, y3, d3);
x4 = veor3q_u64(x4, y4, d4);
x5 = veor3q_u64(x5, y5, d5);
x6 = veor3q_u64(x6, y6, d6);
x7 = veor3q_u64(x7, y7, d7);
x8 = veor3q_u64(x8, y8, d8);
}
/* 3-way parallel scalar CRC (16 bytes each) */
{
uint64_t s0a = *(const uint64_t*)src0;
uint64_t s0b = *(const uint64_t*)(src0 + 8);
uint64_t s1a = *(const uint64_t*)src1;
uint64_t s1b = *(const uint64_t*)(src1 + 8);
uint64_t s2a = *(const uint64_t*)src2;
uint64_t s2b = *(const uint64_t*)(src2 + 8);
if (COPY) {
memcpy(dst0, &s0a, 8);
memcpy(dst0 + 8, &s0b, 8);
dst0 += 16;
memcpy(dst1, &s1a, 8);
memcpy(dst1 + 8, &s1b, 8);
dst1 += 16;
memcpy(dst2, &s2a, 8);
memcpy(dst2 + 8, &s2b, 8);
dst2 += 16;
}
crc0 = __crc32d(crc0, s0a);
crc0 = __crc32d(crc0, s0b);
crc1 = __crc32d(crc1, s1a);
crc1 = __crc32d(crc1, s1b);
crc2 = __crc32d(crc2, s2a);
crc2 = __crc32d(crc2, s2b);
}
src0 += 16;
src1 += 16;
src2 += 16;
srcv += 144;
}
}
/* Reduce 9 vectors to 1 using tree reduction */
/* Step 1: x0 = fold(x0, x1), shift x2..x8 down */
{ static const uint64_t ALIGNED_(16) k_[] = {0xae689191, 0xccaa009e}; k = vld1q_u64_ex(k_, 128); }
y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k);
x0 = veor3q_u64(x0, y0, x1);
x1 = x2, x2 = x3, x3 = x4, x4 = x5, x5 = x6, x6 = x7, x7 = x8;
/* Step 2: fold pairs (x0,x1), (x2,x3), (x4,x5), (x6,x7) */
y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k);
y2 = clmul_lo(x2, k), x2 = clmul_hi(x2, k);
y4 = clmul_lo(x4, k), x4 = clmul_hi(x4, k);
y6 = clmul_lo(x6, k), x6 = clmul_hi(x6, k);
x0 = veor3q_u64(x0, y0, x1);
x2 = veor3q_u64(x2, y2, x3);
x4 = veor3q_u64(x4, y4, x5);
x6 = veor3q_u64(x6, y6, x7);
/* Step 3: fold pairs (x0,x2), (x4,x6) */
{ static const uint64_t ALIGNED_(16) k_[] = {0xf1da05aa, 0x81256527}; k = vld1q_u64_ex(k_, 128); }
y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k);
y4 = clmul_lo(x4, k), x4 = clmul_hi(x4, k);
x0 = veor3q_u64(x0, y0, x2);
x4 = veor3q_u64(x4, y4, x6);
/* Step 4: final fold (x0, x4) -> x0 */
{ static const uint64_t ALIGNED_(16) k_[] = {0x8f352d95, 0x1d9513d7}; k = vld1q_u64_ex(k_, 128); }
y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k);
x0 = veor3q_u64(x0, y0, x4);
/* Process final scalar chunk */
{
uint64_t s0a = *(const uint64_t*)src0;
uint64_t s0b = *(const uint64_t*)(src0 + 8);
uint64_t s1a = *(const uint64_t*)src1;
uint64_t s1b = *(const uint64_t*)(src1 + 8);
uint64_t s2a = *(const uint64_t*)src2;
uint64_t s2b = *(const uint64_t*)(src2 + 8);
if (COPY) {
memcpy(dst0, &s0a, 8);
memcpy(dst0 + 8, &s0b, 8);
memcpy(dst1, &s1a, 8);
memcpy(dst1 + 8, &s1b, 8);
memcpy(dst2, &s2a, 8);
memcpy(dst2 + 8, &s2b, 8);
}
crc0 = __crc32d(crc0, s0a);
crc0 = __crc32d(crc0, s0b);
crc1 = __crc32d(crc1, s1a);
crc1 = __crc32d(crc1, s1b);
crc2 = __crc32d(crc2, s2a);
crc2 = __crc32d(crc2, s2b);
}
/* Shift and combine 3 scalar CRCs */
vc0 = crc_shift(crc0, klen * 2 + blk * 144);
vc1 = crc_shift(crc1, klen + blk * 144);
vc2 = crc_shift(crc2, blk * 144);
vc = vgetq_lane_u64(veor3q_u64(vc0, vc1, vc2), 0);
/* Final reduction: 128-bit vector + scalar CRCs -> 32-bit */
crc0 = __crc32d(0, vgetq_lane_u64(x0, 0));
crc0 = __crc32d(crc0, vc ^ vgetq_lane_u64(x0, 1));
if (COPY)
dst += blk * 192;
src = srcv;
len = end - srcv;
}
/* 3-way scalar CRC (24 bytes/iter) */
if (len >= 80) {
size_t klen = ((len - 8) / 24) * 8; /* Stride for 3-way parallel */
const uint8_t *buf0 = src;
const uint8_t *buf1 = src + klen;
const uint8_t *buf2 = src + klen * 2;
uint32_t crc1 = 0, crc2 = 0;
uint64x2_t vc0, vc1;
uint64_t vc;
/* Per-lane dst pointers */
uint8_t *dst0 = dst;
uint8_t *dst1 = NULL;
uint8_t *dst2 = NULL;
if (COPY) {
dst1 = dst + klen;
dst2 = dst + klen * 2;
}
/* 3-way parallel scalar CRC */
do {
uint64_t v0 = *(const uint64_t*)buf0;
uint64_t v1 = *(const uint64_t*)buf1;
uint64_t v2 = *(const uint64_t*)buf2;
if (COPY) {
memcpy(dst0, &v0, 8);
dst0 += 8;
memcpy(dst1, &v1, 8);
dst1 += 8;
memcpy(dst2, &v2, 8);
dst2 += 8;
}
crc0 = __crc32d(crc0, v0);
crc1 = __crc32d(crc1, v1);
crc2 = __crc32d(crc2, v2);
buf0 += 8;
buf1 += 8;
buf2 += 8;
len -= 24;
} while (len >= 32);
/* Combine the 3 CRCs */
vc0 = crc_shift(crc0, klen * 2 + 8);
vc1 = crc_shift(crc1, klen + 8);
vc = vgetq_lane_u64(veorq_u64(vc0, vc1), 0);
/* Process final 8 bytes with combined CRC */
crc0 = crc2;
{
uint64_t vf = *(const uint64_t*)buf2;
if (COPY)
memcpy(dst2, &vf, 8);
crc0 = __crc32d(crc0, vf ^ vc);
}
src = buf2 + 8;
len -= 8;
if (COPY)
dst = dst2 + 8;
}
/* Process remaining bytes */
return crc32_hw_tail(crc0, dst, src, len, COPY);
}
Z_INTERNAL Z_TARGET_PMULL_EOR3 uint32_t crc32_armv8_pmull_eor3(uint32_t crc, const uint8_t *buf, size_t len) {
return crc32_copy_impl(crc, NULL, buf, len, 0);
}
Z_INTERNAL Z_TARGET_PMULL_EOR3 uint32_t crc32_copy_armv8_pmull_eor3(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) {
#if OPTIMAL_CMP >= 32
return crc32_copy_impl(crc, dst, src, len, 1);
#else
/* Without unaligned access, interleaved stores get decomposed into byte ops */
crc = crc32_armv8_pmull_eor3(crc, src, len);
memcpy(dst, src, len);
return crc;
#endif
}
#endif

View file

@ -1,79 +0,0 @@
#ifndef ARM_NEON_INTRINS_H
#define ARM_NEON_INTRINS_H
#if defined(_MSC_VER) && defined(ARCH_ARM) && defined(ARCH_64BIT)
/* arm64_neon.h is MSVC specific */
# include <arm64_neon.h>
#else
# include <arm_neon.h>
#endif
#if defined(ARM_NEON) && defined(ARCH_ARM) && defined(ARCH_32BIT)
/* Compatibility shim for the _high family of functions */
#define vmull_high_u8(a, b) vmull_u8(vget_high_u8(a), vget_high_u8(b))
#define vmlal_high_u8(a, b, c) vmlal_u8(a, vget_high_u8(b), vget_high_u8(c))
#define vmlal_high_u16(a, b, c) vmlal_u16(a, vget_high_u16(b), vget_high_u16(c))
#define vaddw_high_u8(a, b) vaddw_u8(a, vget_high_u8(b))
#endif
#ifdef ARM_NEON
#define vqsubq_u16_x4_x1(out, a, b) do { \
out.val[0] = vqsubq_u16(a.val[0], b); \
out.val[1] = vqsubq_u16(a.val[1], b); \
out.val[2] = vqsubq_u16(a.val[2], b); \
out.val[3] = vqsubq_u16(a.val[3], b); \
} while (0)
# if defined(ARCH_ARM) && defined(ARCH_32BIT) && defined(__clang__) && \
(!defined(__clang_major__) || __clang_major__ < 20)
/* Clang versions before 20 have too strict of an
* alignment requirement (:256) for x4 NEON intrinsics */
# undef ARM_NEON_HASLD4
# undef vld1q_u16_x4
# undef vld1q_u8_x4
# undef vst1q_u16_x4
# endif
# ifndef ARM_NEON_HASLD4
static inline uint16x8x4_t vld1q_u16_x4(uint16_t const *a) {
uint16x8x4_t ret;
ret.val[0] = vld1q_u16(a);
ret.val[1] = vld1q_u16(a+8);
ret.val[2] = vld1q_u16(a+16);
ret.val[3] = vld1q_u16(a+24);
return ret;
}
static inline uint8x16x4_t vld1q_u8_x4(uint8_t const *a) {
uint8x16x4_t ret;
ret.val[0] = vld1q_u8(a);
ret.val[1] = vld1q_u8(a+16);
ret.val[2] = vld1q_u8(a+32);
ret.val[3] = vld1q_u8(a+48);
return ret;
}
static inline void vst1q_u16_x4(uint16_t *p, uint16x8x4_t a) {
vst1q_u16(p, a.val[0]);
vst1q_u16(p + 8, a.val[1]);
vst1q_u16(p + 16, a.val[2]);
vst1q_u16(p + 24, a.val[3]);
}
# endif // HASLD4 check
# ifndef _MSC_VER
# define vld1_u8_ex(p, align) vld1_u8(HINT_ALIGNED((p), (align)/8))
# define vld1q_u8_ex(p, align) vld1q_u8(HINT_ALIGNED((p), (align)/8))
# define vld1q_u64_ex(p, align) vld1q_u64(HINT_ALIGNED((p), (align)/8))
# endif
# if !defined(_MSC_VER) || !defined(ARM_NEON_HASLD4)
# define vld1q_u8_x4_ex(p, align) vld1q_u8_x4(HINT_ALIGNED((p), (align)/8))
# define vld1q_u16_x4_ex(p, align) vld1q_u16_x4(HINT_ALIGNED((p), (align)/8))
# define vst1q_u16_x4_ex(p, a, align) vst1q_u16_x4(HINT_ALIGNED((p), (align)/8), a)
# endif
#endif
#endif // include guard ARM_NEON_INTRINS_H

View file

@ -1,49 +0,0 @@
/* slide_hash_armv6.c -- Optimized hash table shifting for ARMv6 with support for SIMD instructions
* Copyright (C) 2023 Cameron Cawley
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef ARM_SIMD
#include "zbuild.h"
#include "acle_intrins.h"
#include "deflate.h"
/* SIMD version of hash_chain rebase */
static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) {
Z_REGISTER uint16x2_t v;
uint16x2_t p0, p1, p2, p3;
Z_REGISTER size_t n;
size_t size = entries*sizeof(table[0]);
Assert((size % (sizeof(uint16x2_t) * 4) == 0), "hash table size err");
Assert(sizeof(Pos) == 2, "Wrong Pos size");
v = wsize | (wsize << 16);
n = size / (sizeof(uint16x2_t) * 4);
do {
p0 = *((const uint16x2_t *)(table));
p1 = *((const uint16x2_t *)(table+2));
p2 = *((const uint16x2_t *)(table+4));
p3 = *((const uint16x2_t *)(table+6));
p0 = __uqsub16(p0, v);
p1 = __uqsub16(p1, v);
p2 = __uqsub16(p2, v);
p3 = __uqsub16(p3, v);
*((uint16x2_t *)(table)) = p0;
*((uint16x2_t *)(table+2)) = p1;
*((uint16x2_t *)(table+4)) = p2;
*((uint16x2_t *)(table+6)) = p3;
table += 8;
} while (--n);
}
Z_INTERNAL void slide_hash_armv6(deflate_state *s) {
Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t");
uint16_t wsize = (uint16_t)s->w_size;
slide_hash_chain(s->head, HASH_SIZE, wsize);
slide_hash_chain(s->prev, wsize, wsize);
}
#endif

View file

@ -1,48 +0,0 @@
/* slide_hash_neon.c -- Optimized hash table shifting for ARM with support for NEON instructions
* Copyright (C) 2017-2020 Mika T. Lindqvist
*
* Authors:
* Mika T. Lindqvist <postmaster@raasu.org>
* Jun He <jun.he@arm.com>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef ARM_NEON
#include "zbuild.h"
#include "neon_intrins.h"
#include "deflate.h"
/* SIMD version of hash_chain rebase */
static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) {
Z_REGISTER uint16x8_t v;
uint16x8x4_t p0, p1;
Z_REGISTER size_t n;
size_t size = entries*sizeof(table[0]);
Assert((size % sizeof(uint16x8_t) * 8 == 0), "hash table size err");
Assert(sizeof(Pos) == 2, "Wrong Pos size");
v = vdupq_n_u16(wsize);
n = size / (sizeof(uint16x8_t) * 8);
do {
p0 = vld1q_u16_x4_ex(table, 256);
p1 = vld1q_u16_x4_ex(table+32, 256);
vqsubq_u16_x4_x1(p0, p0, v);
vqsubq_u16_x4_x1(p1, p1, v);
vst1q_u16_x4_ex(table, p0, 256);
vst1q_u16_x4_ex(table+32, p1, 256);
table += 64;
} while (--n);
}
Z_INTERNAL void slide_hash_neon(deflate_state *s) {
Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t");
uint16_t wsize = (uint16_t)s->w_size;
slide_hash_chain(s->head, HASH_SIZE, wsize);
slide_hash_chain(s->prev, wsize, wsize);
}
#endif

View file

@ -1,68 +0,0 @@
# Makefile for zlib-ng
# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler
# Copyright (C) 2024 Hans Kristian Rosbach
# For conditions of distribution and use, see copyright notice in zlib.h
CC=
CFLAGS=
SFLAGS=
INCLUDES=
SRCDIR=.
SRCTOP=../..
TOPDIR=$(SRCTOP)
all: \
adler32_c.o adler32_c.lo \
chunkset_c.o chunkset_c.lo \
compare256_c.o compare256_c.lo \
crc32_braid_c.o crc32_braid_c.lo \
crc32_chorba_c.o crc32_chorba_c.lo \
slide_hash_c.o slide_hash_c.lo
adler32_c.o: $(SRCDIR)/adler32_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/adler32_p.h
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_c.c
adler32_c.lo: $(SRCDIR)/adler32_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/adler32_p.h
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_c.c
chunkset_c.o: $(SRCDIR)/chunkset_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/chunkset_tpl.h $(SRCTOP)/inffast_tpl.h
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_c.c
chunkset_c.lo: $(SRCDIR)/chunkset_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/chunkset_tpl.h $(SRCTOP)/inffast_tpl.h
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_c.c
compare256_c.o: $(SRCDIR)/compare256_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/zendian.h $(SRCTOP)/zmemory.h $(SRCTOP)/deflate.h $(SRCTOP)/fallback_builtins.h
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_c.c
compare256_c.lo: $(SRCDIR)/compare256_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/zendian.h $(SRCTOP)/zmemory.h $(SRCTOP)/deflate.h $(SRCTOP)/fallback_builtins.h
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_c.c
crc32_braid_c.o: $(SRCDIR)/crc32_braid_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/crc32_braid_p.h $(SRCTOP)/crc32_braid_tbl.h
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_braid_c.c
crc32_braid_c.lo: $(SRCDIR)/crc32_braid_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/crc32_braid_p.h $(SRCTOP)/crc32_braid_tbl.h
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_braid_c.c
crc32_chorba_c.o: $(SRCDIR)/crc32_chorba_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/crc32_braid_p.h $(SRCTOP)/crc32_braid_tbl.h
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_chorba_c.c
crc32_chorba_c.lo: $(SRCDIR)/crc32_chorba_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/crc32_braid_p.h $(SRCTOP)/crc32_braid_tbl.h
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_chorba_c.c
slide_hash_c.o: $(SRCDIR)/slide_hash_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/deflate.h
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_c.c
slide_hash_c.lo: $(SRCDIR)/slide_hash_c.c $(SRCTOP)/zbuild.h $(SRCTOP)/deflate.h
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_c.c
mostlyclean: clean
clean:
rm -f *.o *.lo *~
rm -rf objs
rm -f *.gcda *.gcno *.gcov
distclean: clean
rm -f Makefile

View file

@ -1,61 +0,0 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2011, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zbuild.h"
#include "arch_functions.h"
#ifdef ADLER32_FALLBACK
#include "functable.h"
#include "adler32_p.h"
Z_INTERNAL uint32_t adler32_c(uint32_t adler, const uint8_t *buf, size_t len) {
uint32_t sum2;
unsigned n;
/* split Adler-32 into component sums */
sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (UNLIKELY(len == 1))
return adler32_copy_tail(adler, NULL, buf, 1, sum2, 1, 1, 0);
/* in case short lengths are provided, keep it somewhat fast */
if (UNLIKELY(len < 16))
return adler32_copy_tail(adler, NULL, buf, len, sum2, 1, 15, 0);
/* do length NMAX blocks -- requires just one modulo operation */
while (len >= NMAX) {
len -= NMAX;
#ifdef UNROLL_MORE
n = NMAX / 16; /* NMAX is divisible by 16 */
#else
n = NMAX / 8; /* NMAX is divisible by 8 */
#endif
do {
#ifdef UNROLL_MORE
ADLER_DO16(adler, sum2, buf); /* 16 sums unrolled */
buf += 16;
#else
ADLER_DO8(adler, sum2, buf, 0); /* 8 sums unrolled */
buf += 8;
#endif
} while (--n);
adler %= BASE;
sum2 %= BASE;
}
/* do remaining bytes (less than NMAX, still just one modulo) */
return adler32_copy_tail(adler, NULL, buf, len, sum2, len != 0, NMAX - 1, 0);
}
Z_INTERNAL uint32_t adler32_copy_c(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) {
adler = FUNCTABLE_CALL(adler32)(adler, src, len);
memcpy(dst, src, len);
return adler;
}
#endif /* ADLER32_FALLBACK */

View file

@ -1,46 +0,0 @@
/* chunkset.c -- inline functions to copy small data chunks.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zbuild.h"
#include "arch_functions.h"
#ifdef CHUNKSET_FALLBACK
#include "zmemory.h"
typedef uint64_t chunk_t;
#define HAVE_CHUNKMEMSET_4
#define HAVE_CHUNKMEMSET_8
static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) {
uint32_t tmp = zng_memread_4(from);
*chunk = tmp | ((chunk_t)tmp << 32);
}
static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) {
*chunk = zng_memread_8(from);
}
static inline void loadchunk(uint8_t const *s, chunk_t *chunk) {
*chunk = zng_memread_8(s);
}
static inline void storechunk(uint8_t *out, chunk_t *chunk) {
zng_memwrite_8(out, *chunk);
}
#define CHUNKSIZE chunksize_c
#define CHUNKCOPY chunkcopy_c
#define CHUNKUNROLL chunkunroll_c
#define CHUNKMEMSET chunkmemset_c
#define CHUNKMEMSET_SAFE chunkmemset_safe_c
#include "chunkset_tpl.h"
#define INFLATE_FAST inflate_fast_c
#include "inffast_tpl.h"
#endif /* CHUNKSET_FALLBACK */

View file

@ -1,92 +0,0 @@
/* compare256.c -- 256 byte memory comparison with match length return
* Copyright (C) 2020 Nathan Moinvaziri
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zbuild.h"
#include "arch_functions.h"
#ifdef COMPARE256_FALLBACK
#include "zendian.h"
#include "deflate.h"
#include "fallback_builtins.h"
/* 8-bit integer comparison for hardware without unaligned loads */
static inline uint32_t compare256_8_static(const uint8_t *src0, const uint8_t *src1) {
uint32_t len = 0;
do {
if (src0[0] != src1[0])
return len;
if (src0[1] != src1[1])
return len + 1;
if (src0[2] != src1[2])
return len + 2;
if (src0[3] != src1[3])
return len + 3;
if (src0[4] != src1[4])
return len + 4;
if (src0[5] != src1[5])
return len + 5;
if (src0[6] != src1[6])
return len + 6;
if (src0[7] != src1[7])
return len + 7;
src0 += 8, src1 += 8, len += 8;
} while (len < 256);
return 256;
}
/* 64-bit integer comparison for hardware with unaligned loads */
static inline uint32_t compare256_64_static(const uint8_t *src0, const uint8_t *src1) {
uint32_t len = 0;
do {
uint64_t sv = zng_memread_8(src0);
uint64_t mv = zng_memread_8(src1);
uint64_t diff = sv ^ mv;
if (diff)
return len + zng_first_diff_byte64(diff);
src0 += 8, src1 += 8, len += 8;
sv = zng_memread_8(src0);
mv = zng_memread_8(src1);
diff = sv ^ mv;
if (diff)
return len + zng_first_diff_byte64(diff);
src0 += 8, src1 += 8, len += 8;
} while (len < 256);
return 256;
}
#if OPTIMAL_CMP == 8
# define COMPARE256 compare256_8_static
#else
# define COMPARE256 compare256_64_static
#endif
Z_INTERNAL uint32_t compare256_8(const uint8_t *src0, const uint8_t *src1) {
return compare256_8_static(src0, src1);
}
Z_INTERNAL uint32_t compare256_64(const uint8_t *src0, const uint8_t *src1) {
return compare256_64_static(src0, src1);
}
Z_INTERNAL uint32_t compare256_c(const uint8_t *src0, const uint8_t *src1) {
return COMPARE256(src0, src1);
}
// Generate longest_match_c
#define LONGEST_MATCH longest_match_c
#include "match_tpl.h"
// Generate longest_match_roll_c
#define LONGEST_MATCH_ROLL
#define LONGEST_MATCH longest_match_roll_c
#include "match_tpl.h"
#endif /* COMPARE256_FALLBACK */

View file

@ -1,220 +0,0 @@
/* crc32_braid.c -- compute the CRC-32 of a data stream
* Copyright (C) 1995-2022 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*
* This interleaved implementation of a CRC makes use of pipelined multiple
* arithmetic-logic units, commonly found in modern CPU cores. It is due to
* Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution.
*/
#include "zbuild.h"
#include "arch_functions.h"
/* Used by chorba fallback and by arch-specific implementations (s390 vx, risc-v zbc). */
#ifdef CRC32_BRAID_FALLBACK
#include "crc32_braid_p.h"
#include "crc32_braid_tbl.h"
#include "crc32_p.h"
/*
A CRC of a message is computed on BRAID_N braids of words in the message, where
each word consists of BRAID_W bytes (4 or 8). If BRAID_N is 3, for example, then
three running sparse CRCs are calculated respectively on each braid, at these
indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ...
This is done starting at a word boundary, and continues until as many blocks of
BRAID_N * BRAID_W bytes as are available have been processed. The results are
combined into a single CRC at the end. For this code, BRAID_N must be in the
range 1..6 and BRAID_W must be 4 or 8. The upper limit on BRAID_N can be increased
if desired by adding more #if blocks, extending the patterns apparent in the code.
In addition, crc32 tables would need to be regenerated, if the maximum BRAID_N
value is increased.
BRAID_N and BRAID_W are chosen empirically by benchmarking the execution time
on a given processor. The choices for BRAID_N and BRAID_W below were based on
testing on Intel Kaby Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC
POWER9, and MIPS64 Octeon II processors.
The Intel, AMD, and ARM processors were all fastest with BRAID_N=5, BRAID_W=8.
The Sparc, PowerPC, and MIPS64 were all fastest at BRAID_N=5, BRAID_W=4.
They were all tested with either gcc or clang, all using the -O3 optimization
level. Your mileage may vary.
*/
/* ========================================================================= */
#ifdef BRAID_W
/*
Return the CRC of the BRAID_W bytes in the word_t data, taking the
least-significant byte of the word as the first byte of data, without any pre
or post conditioning. This is used to combine the CRCs of each braid.
*/
# if BYTE_ORDER == LITTLE_ENDIAN
static uint32_t crc_word(z_word_t data) {
int k;
for (k = 0; k < BRAID_W; k++)
data = (data >> 8) ^ crc_table[data & 0xff];
return (uint32_t)data;
}
# elif BYTE_ORDER == BIG_ENDIAN
static z_word_t crc_word(z_word_t data) {
int k;
for (k = 0; k < BRAID_W; k++)
data = (data << 8) ^
crc_big_table[(data >> ((BRAID_W - 1) << 3)) & 0xff];
return data;
}
# endif /* BYTE_ORDER */
#endif /* BRAID_W */
/* ========================================================================= */
Z_INTERNAL uint32_t crc32_braid(uint32_t crc, const uint8_t *buf, size_t len) {
crc = ~crc;
#ifdef BRAID_W
/* If provided enough bytes, do a braided CRC calculation. */
if (len >= BRAID_N * BRAID_W + BRAID_W - 1) {
size_t blks;
z_word_t const *words;
int k;
/* Compute the CRC up to a z_word_t boundary. */
size_t align_diff = (size_t)MIN(ALIGN_DIFF(buf, BRAID_W), len);
if (align_diff) {
crc = crc32_copy_small(crc, NULL, buf, align_diff, BRAID_W - 1, 0);
len -= align_diff;
buf += align_diff;
}
/* Compute the CRC on as many BRAID_N z_word_t blocks as are available. */
blks = len / (BRAID_N * BRAID_W);
len -= blks * BRAID_N * BRAID_W;
words = (z_word_t const *)buf;
z_word_t crc0, word0, comb;
#if BRAID_N > 1
z_word_t crc1, word1;
#if BRAID_N > 2
z_word_t crc2, word2;
#if BRAID_N > 3
z_word_t crc3, word3;
#if BRAID_N > 4
z_word_t crc4, word4;
#if BRAID_N > 5
z_word_t crc5, word5;
#endif
#endif
#endif
#endif
#endif
/* Initialize the CRC for each braid. */
crc0 = Z_WORD_FROM_LE(crc);
#if BRAID_N > 1
crc1 = 0;
#if BRAID_N > 2
crc2 = 0;
#if BRAID_N > 3
crc3 = 0;
#if BRAID_N > 4
crc4 = 0;
#if BRAID_N > 5
crc5 = 0;
#endif
#endif
#endif
#endif
#endif
/* Process the first blks-1 blocks, computing the CRCs on each braid independently. */
while (--blks) {
/* Load the word for each braid into registers. */
word0 = crc0 ^ words[0];
#if BRAID_N > 1
word1 = crc1 ^ words[1];
#if BRAID_N > 2
word2 = crc2 ^ words[2];
#if BRAID_N > 3
word3 = crc3 ^ words[3];
#if BRAID_N > 4
word4 = crc4 ^ words[4];
#if BRAID_N > 5
word5 = crc5 ^ words[5];
#endif
#endif
#endif
#endif
#endif
words += BRAID_N;
/* Compute and update the CRC for each word. The loop should get unrolled. */
crc0 = BRAID_TABLE[0][word0 & 0xff];
#if BRAID_N > 1
crc1 = BRAID_TABLE[0][word1 & 0xff];
#if BRAID_N > 2
crc2 = BRAID_TABLE[0][word2 & 0xff];
#if BRAID_N > 3
crc3 = BRAID_TABLE[0][word3 & 0xff];
#if BRAID_N > 4
crc4 = BRAID_TABLE[0][word4 & 0xff];
#if BRAID_N > 5
crc5 = BRAID_TABLE[0][word5 & 0xff];
#endif
#endif
#endif
#endif
#endif
for (k = 1; k < BRAID_W; k++) {
crc0 ^= BRAID_TABLE[k][(word0 >> (k << 3)) & 0xff];
#if BRAID_N > 1
crc1 ^= BRAID_TABLE[k][(word1 >> (k << 3)) & 0xff];
#if BRAID_N > 2
crc2 ^= BRAID_TABLE[k][(word2 >> (k << 3)) & 0xff];
#if BRAID_N > 3
crc3 ^= BRAID_TABLE[k][(word3 >> (k << 3)) & 0xff];
#if BRAID_N > 4
crc4 ^= BRAID_TABLE[k][(word4 >> (k << 3)) & 0xff];
#if BRAID_N > 5
crc5 ^= BRAID_TABLE[k][(word5 >> (k << 3)) & 0xff];
#endif
#endif
#endif
#endif
#endif
}
}
/* Process the last block, combining the CRCs of the BRAID_N braids at the same time. */
comb = crc_word(crc0 ^ words[0]);
#if BRAID_N > 1
comb = crc_word(crc1 ^ words[1] ^ comb);
#if BRAID_N > 2
comb = crc_word(crc2 ^ words[2] ^ comb);
#if BRAID_N > 3
comb = crc_word(crc3 ^ words[3] ^ comb);
#if BRAID_N > 4
comb = crc_word(crc4 ^ words[4] ^ comb);
#if BRAID_N > 5
comb = crc_word(crc5 ^ words[5] ^ comb);
#endif
#endif
#endif
#endif
#endif
words += BRAID_N;
Assert(comb <= UINT32_MAX, "comb should fit in uint32_t");
crc = (uint32_t)Z_WORD_FROM_LE(comb);
/* Update the pointer to the remaining bytes to process. */
buf = (const unsigned char *)words;
}
#endif /* BRAID_W */
/* Complete the computation of the CRC on any remaining bytes. */
return ~crc32_copy_small(crc, NULL, buf, len, (BRAID_N * BRAID_W) - 1, 0);
}
Z_INTERNAL uint32_t crc32_copy_braid(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) {
crc = crc32_braid(crc, src, len);
memcpy(dst, src, len);
return crc;
}
#endif /* CRC32_BRAID_FALLBACK */

File diff suppressed because it is too large Load diff

View file

@ -1,80 +0,0 @@
/* generic_functions.h -- generic C implementations for arch-specific functions.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef GENERIC_FUNCTIONS_H_
#define GENERIC_FUNCTIONS_H_
typedef uint32_t (*adler32_func)(uint32_t adler, const uint8_t *buf, size_t len);
typedef uint32_t (*adler32_copy_func)(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len);
typedef uint32_t (*compare256_func)(const uint8_t *src0, const uint8_t *src1);
typedef uint32_t (*crc32_func)(uint32_t crc, const uint8_t *buf, size_t len);
typedef uint32_t (*crc32_copy_func)(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len);
typedef void (*slide_hash_func)(deflate_state *s);
#ifdef ADLER32_FALLBACK
uint32_t adler32_c(uint32_t adler, const uint8_t *buf, size_t len);
uint32_t adler32_copy_c(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len);
#endif
#ifdef CHUNKSET_FALLBACK
uint8_t* chunkmemset_safe_c(uint8_t *out, uint8_t *from, size_t len, size_t left);
#endif
#ifdef COMPARE256_FALLBACK
uint32_t compare256_8(const uint8_t *src0, const uint8_t *src1);
uint32_t compare256_64(const uint8_t *src0, const uint8_t *src1);
uint32_t compare256_c(const uint8_t *src0, const uint8_t *src1);
#endif
#ifdef CRC32_BRAID_FALLBACK
uint32_t crc32_braid(uint32_t crc, const uint8_t *buf, size_t len);
uint32_t crc32_copy_braid(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len);
#endif
/* Chorba is available whenever braid is needed as a fallback and hasn't been disabled. */
#if defined(CRC32_BRAID_FALLBACK) && !defined(WITHOUT_CHORBA)
# define CRC32_CHORBA_FALLBACK
#endif
#ifdef CRC32_CHORBA_FALLBACK
uint32_t crc32_chorba(uint32_t crc, const uint8_t *buf, size_t len);
uint32_t crc32_copy_chorba(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len);
#endif
#ifdef CHUNKSET_FALLBACK
void inflate_fast_c(PREFIX3(stream) *strm, uint32_t start);
#endif
#ifdef COMPARE256_FALLBACK
uint32_t longest_match_c(deflate_state *const s, uint32_t cur_match);
uint32_t longest_match_roll_c(deflate_state *const s, uint32_t cur_match);
#endif
#ifdef SLIDE_HASH_FALLBACK
void slide_hash_c(deflate_state *s);
#endif
#ifdef DISABLE_RUNTIME_CPU_DETECTION
// Generic fallbacks when no native implementation exists
# ifdef ADLER32_FALLBACK
# define native_adler32 adler32_c
# define native_adler32_copy adler32_copy_c
# endif
# ifdef CHUNKSET_FALLBACK
# define native_chunkmemset_safe chunkmemset_safe_c
# define native_inflate_fast inflate_fast_c
# endif
# ifdef COMPARE256_FALLBACK
# define native_compare256 compare256_c
# define native_longest_match longest_match_c
# define native_longest_match_roll longest_match_roll_c
# endif
# ifdef CRC32_CHORBA_FALLBACK
# define native_crc32 crc32_chorba
# define native_crc32_copy crc32_copy_chorba
# elif defined(CRC32_BRAID_FALLBACK)
# define native_crc32 crc32_braid
# define native_crc32_copy crc32_copy_braid
# endif
# ifdef SLIDE_HASH_FALLBACK
# define native_slide_hash slide_hash_c
# endif
#endif
#endif

View file

@ -1,58 +0,0 @@
/* slide_hash.c -- slide hash table C implementation
*
* Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zbuild.h"
#include "arch_functions.h"
#ifdef SLIDE_HASH_FALLBACK
#include "deflate.h"
/* ===========================================================================
* Slide the hash table when sliding the window down (could be avoided with 32
* bit values at the expense of memory usage). We slide even when level == 0 to
* keep the hash table consistent if we switch back to level > 0 later.
*/
static inline void slide_hash_c_chain(Pos *table, uint32_t entries, uint16_t wsize) {
#ifdef NOT_TWEAK_COMPILER
table += entries;
do {
unsigned m;
m = *--table;
*table = (Pos)(m >= wsize ? m-wsize : 0);
/* If entries is not on any hash chain, prev[entries] is garbage but
* its value will never be used.
*/
} while (--entries);
#else
{
/* As of I make this change, gcc (4.8.*) isn't able to vectorize
* this hot loop using saturated-subtraction on x86-64 architecture.
* To avoid this defect, we can change the loop such that
* o. the pointer advance forward, and
* o. demote the variable 'm' to be local to the loop, and
* choose type "Pos" (instead of 'unsigned int') for the
* variable to avoid unnecessary zero-extension.
*/
unsigned int i;
Pos *q = table;
for (i = 0; i < entries; i++) {
Pos m = *q;
Pos t = (Pos)wsize;
*q++ = (Pos)(m >= t ? m-t: 0);
}
}
#endif /* NOT_TWEAK_COMPILER */
}
Z_INTERNAL void slide_hash_c(deflate_state *s) {
uint16_t wsize = (uint16_t)s->w_size;
slide_hash_c_chain(s->head, HASH_SIZE, wsize);
slide_hash_c_chain(s->prev, wsize, wsize);
}
#endif /* SLIDE_HASH_FALLBACK */

View file

@ -1,99 +0,0 @@
# Makefile for zlib-ng
# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler
# Copyright (C) 2024 Hans Kristian Rosbach
# Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
# For conditions of distribution and use, see copyright notice in zlib.h
CC=
CFLAGS=
SFLAGS=
INCLUDES=
SUFFIX=
LSXFLAG=-mlsx
LASXFLAG=-mlasx
SRCDIR=.
SRCTOP=../..
TOPDIR=$(SRCTOP)
all: \
loongarch_features.o loongarch_features.lo \
crc32_la.o crc32_la.lo \
adler32_lasx.o adler32_lasx.lo \
adler32_lsx.o adler32_lsx.lo \
chunkset_lasx.o chunkset_lasx.lo \
chunkset_lsx.o chunkset_lsx.lo \
compare256_lasx.o compare256_lasx.lo \
compare256_lsx.o compare256_lsx.lo \
slide_hash_lasx.o slide_hash_lasx.lo \
slide_hash_lsx.o slide_hash_lsx.lo
loongarch_features.o: $(SRCDIR)/loongarch_features.c
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/loongarch_features.c
loongarch_features.lo: $(SRCDIR)/loongarch_features.c
$(CC) $(SFLAGS) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/loongarch_features.c
crc32_la.o: $(SRCDIR)/crc32_la.c
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_la.c
crc32_la.lo: $(SRCDIR)/crc32_la.c
$(CC) $(SFLAGS) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_la.c
adler32_lasx.o:
$(CC) $(CFLAGS) $(LASXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_lasx.c
adler32_lasx.lo:
$(CC) $(SFLAGS) $(LASXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_lasx.c
adler32_lsx.o:
$(CC) $(CFLAGS) $(LSXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_lsx.c
adler32_lsx.lo:
$(CC) $(SFLAGS) $(LSXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_lsx.c
chunkset_lasx.o:
$(CC) $(CFLAGS) $(LASXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_lasx.c
chunkset_lasx.lo:
$(CC) $(SFLAGS) $(LASXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_lasx.c
chunkset_lsx.o:
$(CC) $(CFLAGS) $(LSXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_lsx.c
chunkset_lsx.lo:
$(CC) $(SFLAGS) $(LSXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_lsx.c
compare256_lasx.o:
$(CC) $(CFLAGS) $(LASXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_lasx.c
compare256_lasx.lo:
$(CC) $(SFLAGS) $(LASXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_lasx.c
compare256_lsx.o:
$(CC) $(CFLAGS) $(LSXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_lsx.c
compare256_lsx.lo:
$(CC) $(SFLAGS) $(LSXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_lsx.c
slide_hash_lasx.o:
$(CC) $(CFLAGS) $(LASXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_lasx.c
slide_hash_lasx.lo:
$(CC) $(SFLAGS) $(LASXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_lasx.c
slide_hash_lsx.o:
$(CC) $(CFLAGS) $(LSXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_lsx.c
slide_hash_lsx.lo:
$(CC) $(SFLAGS) $(LSXFLAG) $(NOLTOFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_lsx.c
mostlyclean: clean
clean:
rm -f *.o *.lo *~
rm -rf objs
rm -f *.gcda *.gcno *.gcov
distclean: clean
rm -f Makefile

View file

@ -1,154 +0,0 @@
/* adler32_lasx.c -- compute the Adler-32 checksum of a data stream, based on Intel AVX2 implementation
* Copyright (C) 1995-2011 Mark Adler
* Copyright (C) 2022 Adam Stylinski
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* Authors:
* Brian Bockelman <bockelman@gmail.com>
* Adam Stylinski <kungfujesus06@gmail.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef LOONGARCH_LASX
#include "zbuild.h"
#include "adler32_p.h"
#include <lasxintrin.h>
#include "lasxintrin_ext.h"
/* 32 bit horizontal sum */
static inline uint32_t hsum256(__m256i x) {
__m256i sum1 = __lasx_xvadd_w(x, __lasx_xvbsrl_v(x, 8));
__m256i sum2 = __lasx_xvadd_w(sum1, __lasx_xvpermi_d(sum1, 0x2));
__m256i sum3 = __lasx_xvadd_w(sum2, __lasx_xvbsrl_v(sum2, 4));
return (uint32_t)__lasx_xvpickve2gr_wu(sum3, 0);
}
static inline uint32_t partial_hsum256(__m256i x) {
__m256i sum1 = __lasx_xvadd_w(x, __lasx_xvbsrl_v(x, 8));
__m256i sum2 = __lasx_xvadd_w(sum1, __lasx_xvpermi_d(sum1, 0x2));
return (uint32_t)__lasx_xvpickve2gr_wu(sum2, 0);
}
extern uint32_t adler32_copy_lsx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len);
extern uint32_t adler32_lsx(uint32_t adler, const uint8_t *src, size_t len);
Z_FORCEINLINE static uint32_t adler32_copy_impl(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len, const int COPY) {
uint32_t adler0, adler1;
adler1 = (adler >> 16) & 0xffff;
adler0 = adler & 0xffff;
rem_peel:
if (len < 16) {
return adler32_copy_tail(adler0, dst, src, len, adler1, 1, 15, COPY);
} else if (len < 32) {
if (COPY) {
return adler32_copy_lsx(adler, dst, src, len);
} else {
return adler32_lsx(adler, src, len);
}
}
__m256i vs1, vs2, vs2_0;
const __m256i dot2v = (__m256i)((v32i8){ 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47,
46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33 });
const __m256i dot2v_0 = (__m256i)((v32i8){ 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 });
const __m256i dot3v = __lasx_xvreplgr2vr_h(1);
const __m256i zero = __lasx_xvldi(0);
while (len >= 32) {
vs1 = __lasx_xvinsgr2vr_w(zero, adler0, 0);
vs2 = __lasx_xvinsgr2vr_w(zero, adler1, 0);
__m256i vs1_0 = vs1;
__m256i vs3 = __lasx_xvldi(0);
vs2_0 = vs3;
size_t k = ALIGN_DOWN(MIN(len, NMAX), 32);
len -= k;
while (k >= 64) {
__m256i vbuf = __lasx_xvld(src, 0);
__m256i vbuf_0 = __lasx_xvld(src, 32);
src += 64;
k -= 64;
__m256i vs1_sad = lasx_sad_bu(vbuf, zero);
__m256i vs1_sad2 = lasx_sad_bu(vbuf_0, zero);
if (COPY) {
__lasx_xvst(vbuf, dst, 0);
__lasx_xvst(vbuf_0, dst, 32);
dst += 64;
}
vs1 = __lasx_xvadd_w(vs1, vs1_sad);
vs3 = __lasx_xvadd_w(vs3, vs1_0);
__m256i v_short_sum2 = lasx_maddubs_w_h(vbuf, dot2v); // sum 32 uint8s to 16 shorts
__m256i v_short_sum2_0 = lasx_maddubs_w_h(vbuf_0, dot2v_0); // sum 32 uint8s to 16 shorts
__m256i vsum2 = lasx_madd_w_h(v_short_sum2, dot3v); // sum 16 shorts to 8 uint32s
__m256i vsum2_0 = lasx_madd_w_h(v_short_sum2_0, dot3v); // sum 16 shorts to 8 uint32s
vs1 = __lasx_xvadd_w(vs1_sad2, vs1);
vs2 = __lasx_xvadd_w(vsum2, vs2);
vs2_0 = __lasx_xvadd_w(vsum2_0, vs2_0);
vs1_0 = vs1;
}
vs2 = __lasx_xvadd_w(vs2_0, vs2);
vs3 = __lasx_xvslli_w(vs3, 6);
vs2 = __lasx_xvadd_w(vs3, vs2);
vs3 = __lasx_xvldi(0);
while (k >= 32) {
/*
vs1 = adler + sum(c[i])
vs2 = sum2 + 32 vs1 + sum( (32-i+1) c[i] )
*/
__m256i vbuf = __lasx_xvld(src, 0);
src += 32;
k -= 32;
__m256i vs1_sad = lasx_sad_bu(vbuf, zero); // Sum of abs diff, resulting in 2 x int32's
if (COPY) {
__lasx_xvst(vbuf, dst, 0);
dst += 32;
}
vs1 = __lasx_xvadd_w(vs1, vs1_sad);
vs3 = __lasx_xvadd_w(vs3, vs1_0);
__m256i v_short_sum2 = lasx_maddubs_w_h(vbuf, dot2v_0); // sum 32 uint8s to 16 shorts
__m256i vsum2 = lasx_madd_w_h(v_short_sum2, dot3v); // sum 16 shorts to 8 uint32s
vs2 = __lasx_xvadd_w(vsum2, vs2);
vs1_0 = vs1;
}
/* Defer the multiplication with 32 to outside of the loop */
vs3 = __lasx_xvslli_w(vs3, 5);
vs2 = __lasx_xvadd_w(vs2, vs3);
adler0 = partial_hsum256(vs1) % BASE;
adler1 = hsum256(vs2) % BASE;
}
adler = adler0 | (adler1 << 16);
if (len) {
goto rem_peel;
}
return adler;
}
Z_INTERNAL uint32_t adler32_lasx(uint32_t adler, const uint8_t *src, size_t len) {
return adler32_copy_impl(adler, NULL, src, len, 0);
}
Z_INTERNAL uint32_t adler32_copy_lasx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) {
return adler32_copy_impl(adler, dst, src, len, 1);
}
#endif

View file

@ -1,147 +0,0 @@
/* adler32_lsx.c -- compute the Adler-32 checksum of a data stream, based on Intel SSE4.2 implementation
* Copyright (C) 1995-2011 Mark Adler
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* Authors:
* Adam Stylinski <kungfujesus06@gmail.com>
* Brian Bockelman <bockelman@gmail.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef LOONGARCH_LSX
#include "zbuild.h"
#include "adler32_p.h"
#include <lsxintrin.h>
#include "lsxintrin_ext.h"
static inline uint32_t partial_hsum(__m128i x) {
__m128i second_int = __lsx_vbsrl_v(x, 8);
__m128i sum = __lsx_vadd_w(x, second_int);
return __lsx_vpickve2gr_w(sum, 0);
}
static inline uint32_t hsum(__m128i x) {
__m128i sum1 = __lsx_vilvh_d(x, x);
__m128i sum2 = __lsx_vadd_w(x, sum1);
__m128i sum3 = __lsx_vshuf4i_w(sum2, 0x01);
__m128i sum4 = __lsx_vadd_w(sum2, sum3);
return __lsx_vpickve2gr_w(sum4, 0);
}
Z_FORCEINLINE static uint32_t adler32_copy_impl(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len, const int COPY) {
uint32_t adler0, adler1;
adler1 = (adler >> 16) & 0xffff;
adler0 = adler & 0xffff;
rem_peel:
if (len < 16)
return adler32_copy_tail(adler0, dst, src, len, adler1, 1, 15, COPY);
__m128i vbuf, vbuf_0;
__m128i vs1_0, vs3, vs1, vs2, vs2_0, v_sad_sum1, v_short_sum2, v_short_sum2_0,
v_sad_sum2, vsum2, vsum2_0;
__m128i zero = __lsx_vldi(0);
const __m128i dot2v = (__m128i)((v16i8){ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17 });
const __m128i dot2v_0 = (__m128i)((v16i8){ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 });
const __m128i dot3v = __lsx_vreplgr2vr_h(1);
size_t k;
while (len >= 16) {
k = ALIGN_DOWN(MIN(len, NMAX), 16);
len -= k;
vs1 = __lsx_vinsgr2vr_w(zero, adler0, 0);
vs2 = __lsx_vinsgr2vr_w(zero, adler1, 0);
vs3 = __lsx_vldi(0);
vs2_0 = __lsx_vldi(0);
vs1_0 = vs1;
while (k >= 32) {
/*
vs1 = adler + sum(c[i])
vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] )
*/
vbuf = __lsx_vld(src, 0);
vbuf_0 = __lsx_vld(src, 16);
src += 32;
k -= 32;
v_sad_sum1 = lsx_sad_bu(vbuf, zero);
v_sad_sum2 = lsx_sad_bu(vbuf_0, zero);
if (COPY) {
__lsx_vst(vbuf, dst, 0);
__lsx_vst(vbuf_0, dst, 16);
dst += 32;
}
v_short_sum2 = __lsx_vsadd_h(__lsx_vmulwev_h_bu_b(vbuf, dot2v), __lsx_vmulwod_h_bu_b(vbuf, dot2v));
v_short_sum2_0 = __lsx_vsadd_h(__lsx_vmulwev_h_bu_b(vbuf_0, dot2v_0), __lsx_vmulwod_h_bu_b(vbuf_0, dot2v_0));
vs1 = __lsx_vadd_w(v_sad_sum1, vs1);
vs3 = __lsx_vadd_w(vs1_0, vs3);
vsum2 = __lsx_vmaddwod_w_h(__lsx_vmulwev_w_h(v_short_sum2, dot3v), v_short_sum2, dot3v);
vsum2_0 = __lsx_vmaddwod_w_h(__lsx_vmulwev_w_h(v_short_sum2_0, dot3v), v_short_sum2_0, dot3v);
vs1 = __lsx_vadd_w(v_sad_sum2, vs1);
vs2 = __lsx_vadd_w(vsum2, vs2);
vs2_0 = __lsx_vadd_w(vsum2_0, vs2_0);
vs1_0 = vs1;
}
vs2 = __lsx_vadd_w(vs2_0, vs2);
vs3 = __lsx_vslli_w(vs3, 5);
vs2 = __lsx_vadd_w(vs3, vs2);
vs3 = __lsx_vldi(0);
while (k >= 16) {
/*
vs1 = adler + sum(c[i])
vs2 = sum2 + 16 vs1 + sum( (16-i+1) c[i] )
*/
vbuf = __lsx_vld(src, 0);
src += 16;
k -= 16;
v_sad_sum1 = lsx_sad_bu(vbuf, zero);
v_short_sum2 = __lsx_vsadd_h(__lsx_vmulwev_h_bu_b(vbuf, dot2v_0), __lsx_vmulwod_h_bu_b(vbuf, dot2v_0));
vs1 = __lsx_vadd_w(v_sad_sum1, vs1);
vs3 = __lsx_vadd_w(vs1_0, vs3);
vsum2 = __lsx_vmaddwod_w_h(__lsx_vmulwev_w_h(v_short_sum2, dot3v), v_short_sum2, dot3v);
vs2 = __lsx_vadd_w(vsum2, vs2);
vs1_0 = vs1;
if (COPY) {
__lsx_vst(vbuf, dst, 0);
dst += 16;
}
}
vs3 = __lsx_vslli_w(vs3, 4);
vs2 = __lsx_vadd_w(vs2, vs3);
adler0 = partial_hsum(vs1) % BASE;
adler1 = hsum(vs2) % BASE;
}
/* If this is true, there's fewer than 16 elements remaining */
if (len) {
goto rem_peel;
}
return adler0 | (adler1 << 16);
}
Z_INTERNAL uint32_t adler32_lsx(uint32_t adler, const uint8_t *src, size_t len) {
return adler32_copy_impl(adler, NULL, src, len, 0);
}
Z_INTERNAL uint32_t adler32_copy_lsx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) {
return adler32_copy_impl(adler, dst, src, len, 1);
}
#endif

View file

@ -1,126 +0,0 @@
/* chunkset_lasx.c -- LASX inline functions to copy small data chunks, based on Intel AVX2 implementation
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef LOONGARCH_LASX
#include "zbuild.h"
#include "zsanitizer.h"
#include "zmemory.h"
#include <lasxintrin.h>
#include "lasxintrin_ext.h"
#include "lsxintrin_ext.h"
#include "arch/shared/chunk_256bit_perm_idx_lut.h"
typedef __m256i chunk_t;
typedef __m128i halfchunk_t;
#define HAVE_CHUNKMEMSET_2
#define HAVE_CHUNKMEMSET_4
#define HAVE_CHUNKMEMSET_8
#define HAVE_CHUNKMEMSET_16
#define HAVE_CHUNK_MAG
#define HAVE_HALF_CHUNK
static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) {
*chunk = __lasx_xvreplgr2vr_h(zng_memread_2(from));
}
static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) {
*chunk = __lasx_xvreplgr2vr_w(zng_memread_4(from));
}
static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) {
*chunk = __lasx_xvreplgr2vr_d(zng_memread_8(from));
}
static inline void chunkmemset_16(uint8_t *from, chunk_t *chunk) {
*chunk = lasx_broadcast_128(__lsx_vld(from, 0));
}
static inline void loadchunk(uint8_t const *s, chunk_t *chunk) {
*chunk = __lasx_xvld(s, 0);
}
static inline void storechunk(uint8_t *out, chunk_t *chunk) {
__lasx_xvst(*chunk, out, 0);
}
static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) {
lut_rem_pair lut_rem = perm_idx_lut[dist - 3];
__m256i ret_vec;
/* While technically we only need to read 4 or 8 bytes into this vector register for a lot of cases, GCC is
* compiling this to a shared load for all branches, preferring the simpler code. Given that the buf value isn't in
* GPRs to begin with the 256 bit load is _probably_ just as inexpensive */
*chunk_rem = lut_rem.remval;
/* See note in chunkset_ssse3.c for why this is ok */
__msan_unpoison(buf + dist, 32 - dist);
if (dist < 16) {
/* This simpler case still requires us to shuffle in 128 bit lanes, so we must apply a static offset after
* broadcasting the first vector register to both halves. This is _marginally_ faster than doing two separate
* shuffles and combining the halves later */
__m256i perm_vec = __lasx_xvld(permute_table+lut_rem.idx, 0);
__m128i ret_vec0 = __lsx_vld(buf, 0);
ret_vec = __lasx_concat_128(ret_vec0, ret_vec0);
ret_vec = lasx_shuffle_b(ret_vec, perm_vec);
} else {
__m128i ret_vec0 = __lsx_vld(buf, 0);
__m128i ret_vec1 = __lsx_vld(buf, 16);
/* Take advantage of the fact that only the latter half of the 256 bit vector will actually differ */
__m128i perm_vec1 = __lsx_vld(permute_table + lut_rem.idx, 0);
__m128i xlane_permutes = __lsx_vslt_b(perm_vec1, __lsx_vreplgr2vr_b(16));
__m128i xlane_res = lsx_shuffle_b(ret_vec0, perm_vec1);
/* Since we can't wrap twice, we can simply keep the later half exactly how it is instead of having to _also_
* shuffle those values */
__m128i latter_half = __lsx_vbitsel_v(ret_vec1, xlane_res, xlane_permutes);
ret_vec = __lasx_concat_128(ret_vec0, latter_half);
}
return ret_vec;
}
static inline void loadhalfchunk(uint8_t const *s, halfchunk_t *chunk) {
*chunk = __lsx_vld(s, 0);
}
static inline void storehalfchunk(uint8_t *out, halfchunk_t *chunk) {
__lsx_vst(*chunk, out, 0);
}
static inline chunk_t halfchunk2whole(halfchunk_t *chunk) {
/* We zero extend mostly to appease some memory sanitizers. These bytes are ultimately
* unlikely to be actually written or read from */
return lasx_zext_128(*chunk);
}
static inline halfchunk_t GET_HALFCHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) {
lut_rem_pair lut_rem = perm_idx_lut[dist - 3];
__m128i perm_vec, ret_vec;
__msan_unpoison(buf + dist, 16 - dist);
ret_vec = __lsx_vld(buf, 0);
*chunk_rem = half_rem_vals[dist - 3];
perm_vec = __lsx_vld(permute_table + lut_rem.idx, 0);
ret_vec = lsx_shuffle_b(ret_vec, perm_vec);
return ret_vec;
}
#define CHUNKSIZE chunksize_lasx
#define CHUNKCOPY chunkcopy_lasx
#define CHUNKUNROLL chunkunroll_lasx
#define CHUNKMEMSET chunkmemset_lasx
#define CHUNKMEMSET_SAFE chunkmemset_safe_lasx
#include "chunkset_tpl.h"
#define INFLATE_FAST inflate_fast_lasx
#include "inffast_tpl.h"
#endif

View file

@ -1,74 +0,0 @@
/* chunkset_lsx.c -- LSX inline functions to copy small data chunks, based on Intel SSSE3 implementation
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef LOONGARCH_LSX
#include "zbuild.h"
#include "zsanitizer.h"
#include "zmemory.h"
#include <lsxintrin.h>
#include "lsxintrin_ext.h"
#include "arch/shared/chunk_128bit_perm_idx_lut.h"
typedef __m128i chunk_t;
#define HAVE_CHUNKMEMSET_2
#define HAVE_CHUNKMEMSET_4
#define HAVE_CHUNKMEMSET_8
#define HAVE_CHUNK_MAG
static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) {
*chunk = __lsx_vreplgr2vr_h(zng_memread_2(from));
}
static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) {
*chunk = __lsx_vreplgr2vr_w(zng_memread_4(from));
}
static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) {
*chunk = __lsx_vreplgr2vr_d(zng_memread_8(from));
}
static inline void loadchunk(uint8_t const *s, chunk_t *chunk) {
*chunk = __lsx_vld(s, 0);
}
static inline void storechunk(uint8_t *out, chunk_t *chunk) {
__lsx_vst(*chunk, out, 0);
}
static inline chunk_t GET_CHUNK_MAG(uint8_t *buf, size_t *chunk_rem, size_t dist) {
lut_rem_pair lut_rem = perm_idx_lut[dist - 3];
__m128i perm_vec, ret_vec;
/* Important to note:
* This is _not_ to subvert the memory sanitizer but to instead unpoison some
* bytes we willingly and purposefully load uninitialized that we swizzle over
* in a vector register, anyway. If what we assume is wrong about what is used,
* the memory sanitizer will still usefully flag it */
__msan_unpoison(buf + dist, 16 - dist);
ret_vec = __lsx_vld(buf, 0);
*chunk_rem = lut_rem.remval;
perm_vec = __lsx_vld(permute_table + lut_rem.idx, 0);
ret_vec = lsx_shuffle_b(ret_vec, perm_vec);
return ret_vec;
}
#define CHUNKSIZE chunksize_lsx
#define CHUNKMEMSET chunkmemset_lsx
#define CHUNKMEMSET_SAFE chunkmemset_safe_lsx
#define CHUNKCOPY chunkcopy_lsx
#define CHUNKUNROLL chunkunroll_lsx
#include "chunkset_tpl.h"
#define INFLATE_FAST inflate_fast_lsx
#include "inffast_tpl.h"
#endif

View file

@ -1,60 +0,0 @@
/* compare256_lasx.c -- LASX version of compare256, based on Intel AVX2 implementation
* Copyright Mika T. Lindqvist <postmaster@raasu.org>
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zbuild.h"
#include "zendian.h"
#include "zmemory.h"
#include "deflate.h"
#include "fallback_builtins.h"
#ifdef LOONGARCH_LASX
#include <lasxintrin.h>
#include "lasxintrin_ext.h"
static inline uint32_t compare256_lasx_static(const uint8_t *src0, const uint8_t *src1) {
uint32_t len = 0;
do {
__m256i ymm_src0, ymm_src1, ymm_cmp;
ymm_src0 = __lasx_xvld(src0, 0);
ymm_src1 = __lasx_xvld(src1, 0);
ymm_cmp = __lasx_xvseq_b(ymm_src0, ymm_src1); /* non-identical bytes = 00, identical bytes = FF */
unsigned mask = (unsigned)lasx_movemask_b(ymm_cmp);
if (mask != 0xFFFFFFFF)
return len + zng_ctz32(~mask); /* Invert bits so identical = 0 */
src0 += 32, src1 += 32, len += 32;
ymm_src0 = __lasx_xvld(src0, 0);
ymm_src1 = __lasx_xvld(src1, 0);
ymm_cmp = __lasx_xvseq_b(ymm_src0, ymm_src1);
mask = (unsigned)lasx_movemask_b(ymm_cmp);
if (mask != 0xFFFFFFFF)
return len + zng_ctz32(~mask);
src0 += 32, src1 += 32, len += 32;
} while (len < 256);
return 256;
}
Z_INTERNAL uint32_t compare256_lasx(const uint8_t *src0, const uint8_t *src1) {
return compare256_lasx_static(src0, src1);
}
#define LONGEST_MATCH longest_match_lasx
#define COMPARE256 compare256_lasx_static
#include "match_tpl.h"
#define LONGEST_MATCH_ROLL
#define LONGEST_MATCH longest_match_roll_lasx
#define COMPARE256 compare256_lasx_static
#include "match_tpl.h"
#endif

View file

@ -1,88 +0,0 @@
/* compare256_lsx.c -- LSX version of compare256, based on Intel SSE implementation
* Copyright Adam Stylinski <kungfujesus06@gmail.com>
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zbuild.h"
#include "zendian.h"
#include "zmemory.h"
#include "deflate.h"
#include "fallback_builtins.h"
#ifdef LOONGARCH_LSX
#include <lsxintrin.h>
#include "lsxintrin_ext.h"
static inline uint32_t compare256_lsx_static(const uint8_t *src0, const uint8_t *src1) {
__m128i xmm_src0, xmm_src1, xmm_cmp;
/* Do the first load unaligned, than all subsequent ones we have at least
* one aligned load. Sadly aligning both loads is probably unrealistic */
xmm_src0 = __lsx_vld(src0, 0);
xmm_src1 = __lsx_vld(src1, 0);
xmm_cmp = __lsx_vseq_b(xmm_src0, xmm_src1);
unsigned mask = (unsigned)lsx_movemask_b(xmm_cmp);
/* Compiler _may_ turn this branch into a ptest + movemask,
* since a lot of those uops are shared and fused */
if (mask != 0xFFFF)
return zng_ctz32(~mask);
const uint8_t *last0 = src0 + 240;
const uint8_t *last1 = src1 + 240;
int align_offset = ((uintptr_t)src0) & 15;
int align_adv = 16 - align_offset;
uint32_t len = align_adv;
src0 += align_adv;
src1 += align_adv;
for (int i = 0; i < 15; i++) {
xmm_src0 = __lsx_vld(src0, 0);
xmm_src1 = __lsx_vld(src1, 0);
xmm_cmp = __lsx_vseq_b(xmm_src0, xmm_src1);
mask = (unsigned)lsx_movemask_b(xmm_cmp);
/* Compiler _may_ turn this branch into a ptest + movemask,
* since a lot of those uops are shared and fused */
if (mask != 0xFFFF)
return len + zng_ctz32(~mask);
len += 16, src0 += 16, src1 += 16;
}
if (align_offset) {
xmm_src0 = __lsx_vld(last0, 0);
xmm_src1 = __lsx_vld(last1, 0);
xmm_cmp = __lsx_vseq_b(xmm_src0, xmm_src1);
mask = (unsigned)lsx_movemask_b(xmm_cmp);
if (mask != 0xFFFF)
return 240 + zng_ctz32(~mask);
}
return 256;
}
Z_INTERNAL uint32_t compare256_lsx(const uint8_t *src0, const uint8_t *src1) {
return compare256_lsx_static(src0, src1);
}
#define LONGEST_MATCH longest_match_lsx
#define COMPARE256 compare256_lsx_static
#include "match_tpl.h"
#define LONGEST_MATCH_ROLL
#define LONGEST_MATCH longest_match_roll_lsx
#define COMPARE256 compare256_lsx_static
#include "match_tpl.h"
#endif

View file

@ -1,31 +0,0 @@
/* crc32_la.c - LoongArch version of crc32
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef LOONGARCH_CRC
#include "zbuild.h"
#include <larchintrin.h>
#define Z_TARGET_CRC
#define CRC32B(crc, val) (uint32_t)__crc_w_b_w((char)(val), (int)(crc))
#define CRC32H(crc, val) (uint32_t)__crc_w_h_w((short)(val), (int)(crc))
#define CRC32W(crc, val) (uint32_t)__crc_w_w_w((int)(val), (int)(crc))
#define CRC32D(crc, val) (uint32_t)__crc_w_d_w((long int)(val), (int)(crc))
#include "arch/shared/crc32_hw_common_tpl.h"
#include "arch/shared/crc32_hw_copy_impl_tpl.h"
Z_INTERNAL uint32_t crc32_loongarch64(uint32_t crc, const uint8_t *buf, size_t len) {
return crc32_hw_copy_impl(crc, NULL, buf, len, 0);
}
Z_INTERNAL uint32_t crc32_copy_loongarch64(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) {
return crc32_hw_copy_impl(crc, dst, src, len, 1);
}
#endif

View file

@ -1,61 +0,0 @@
/* lasxintrin_ext.h
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef LASXINTRIN_EXT_H
#define LASXINTRIN_EXT_H
#include <lsxintrin.h>
#include <lasxintrin.h>
static inline __m256i lasx_zext_128(__m128i src) {
#ifdef __loongarch_asx_sx_conv
return __lasx_insert_128_lo(__lasx_xvldi(0), src);
#else
__m256i dest = __lasx_xvldi(0);
__asm__ volatile ("xvpermi.q %u0,%u2,0x30\n" : "=f"(dest) : "0"(dest), "f"(src));
return dest;
#endif
}
#ifndef __loongarch_asx_sx_conv
static inline __m256i __lasx_concat_128(__m128i lo, __m128i hi) {
__m256i dest;
__asm__ volatile ("xvpermi.q %u0,%u2,0x02\n" : "=f"(dest) : "0"(lo), "f"(hi));
return dest;
}
#endif
static inline __m256i lasx_broadcast_128(__m128i in) {
return __lasx_concat_128(in, in);
}
static inline __m256i lasx_sad_bu(__m256i a, __m256i b) {
__m256i tmp = __lasx_xvabsd_bu(a, b);
tmp = __lasx_xvhaddw_hu_bu(tmp, tmp);
tmp = __lasx_xvhaddw_wu_hu(tmp, tmp);
return __lasx_xvhaddw_du_wu(tmp, tmp);
}
static inline __m256i lasx_maddubs_w_h(__m256i a, __m256i b) {
return __lasx_xvsadd_h(__lasx_xvmulwod_h_bu_b(a, b), __lasx_xvmulwev_h_bu_b(a, b));
}
static inline __m256i lasx_madd_w_h(__m256i a, __m256i b) {
return __lasx_xvmaddwod_w_h(__lasx_xvmulwev_w_h(a, b), a, b);
}
static inline int lasx_movemask_b(__m256i v) {
v = __lasx_xvmskltz_b(v);
return __lasx_xvpickve2gr_w(v, 0) | (__lasx_xvpickve2gr_w(v, 4) << 16);
}
/* See: lsx_shuffle_b */
static inline __m256i lasx_shuffle_b(__m256i a, __m256i b) {
__m256i msb_mask = __lasx_xvslti_b(b, 0);
__m256i dst = __lasx_xvshuf_b(a, a, __lasx_xvandi_b(b, 0xF));
return __lasx_xvand_v(dst, __lasx_xvnor_v(msb_mask, msb_mask));
}
#endif // include guard LASXINTRIN_EXT_H

View file

@ -1,31 +0,0 @@
/* loongarch_features.c -- check for LoongArch features.
*
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef LOONGARCH_FEATURES
#include "zbuild.h"
#include "loongarch_features.h"
#include <larchintrin.h>
/*
* https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html
*
* Word number Bit number Annotation Implication
* 0x1 25 CRC 1 indicates support for CRC instruction
* 0x1 6 LSX 1 indicates support for 128-bit vector extension
* 0x1 7 LASX 1 indicates support for 256-bit vector expansion
*/
void Z_INTERNAL loongarch_check_features(struct loongarch_cpu_features *features) {
unsigned int w1 = __cpucfg(0x1);
features->has_crc = w1 & 0x2000000;
features->has_lsx = w1 & 0x40;
features->has_lasx = w1 & 0x80;
}
#endif

View file

@ -1,19 +0,0 @@
/* loongarch_features.h -- check for LoongArch features.
*
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef LOONGARCH_FEATURES_H_
#define LOONGARCH_FEATURES_H_
struct loongarch_cpu_features {
int has_crc;
int has_lsx;
int has_lasx;
};
void Z_INTERNAL loongarch_check_features(struct loongarch_cpu_features *features);
#endif /* LOONGARCH_FEATURES_H_ */

View file

@ -1,97 +0,0 @@
/* loongarch_functions.h -- LoongArch implementations for arch-specific functions.
*
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef LOONGARCH_FUNCTIONS_H_
#define LOONGARCH_FUNCTIONS_H_
#include "loongarch_natives.h"
#ifdef LOONGARCH_CRC
uint32_t crc32_loongarch64(uint32_t crc, const uint8_t *buf, size_t len);
uint32_t crc32_copy_loongarch64(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len);
#endif
#ifndef LOONGARCH_CRC_NATIVE
# define CRC32_BRAID_FALLBACK
#endif
#ifdef LOONGARCH_LSX
uint32_t adler32_lsx(uint32_t adler, const uint8_t *src, size_t len);
uint32_t adler32_copy_lsx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len);
uint8_t* chunkmemset_safe_lsx(uint8_t *out, uint8_t *from, size_t len, size_t left);
uint32_t compare256_lsx(const uint8_t *src0, const uint8_t *src1);
void inflate_fast_lsx(PREFIX3(stream) *strm, uint32_t start);
uint32_t longest_match_lsx(deflate_state *const s, uint32_t cur_match);
uint32_t longest_match_roll_lsx(deflate_state *const s, uint32_t cur_match);
void slide_hash_lsx(deflate_state *s);
#endif
#ifndef LOONGARCH_LSX_NATIVE
# define ADLER32_FALLBACK
# define CHUNKSET_FALLBACK
# define COMPARE256_FALLBACK
# define SLIDE_HASH_FALLBACK
#endif
#ifdef LOONGARCH_LASX
uint32_t adler32_lasx(uint32_t adler, const uint8_t *src, size_t len);
uint32_t adler32_copy_lasx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len);
uint8_t* chunkmemset_safe_lasx(uint8_t *out, uint8_t *from, size_t len, size_t left);
uint32_t compare256_lasx(const uint8_t *src0, const uint8_t *src1);
void inflate_fast_lasx(PREFIX3(stream) *strm, uint32_t start);
uint32_t longest_match_lasx(deflate_state *const s, uint32_t cur_match);
uint32_t longest_match_roll_lasx(deflate_state *const s, uint32_t cur_match);
void slide_hash_lasx(deflate_state *s);
#endif
#ifdef DISABLE_RUNTIME_CPU_DETECTION
// LOONGARCH - CRC32
# ifdef LOONGARCH_CRC_NATIVE
# undef native_crc32
# define native_crc32 crc32_loongarch64
# undef native_crc32_copy
# define native_crc32_copy crc32_copy_loongarch64
# endif
# ifdef LOONGARCH_LSX_NATIVE
# undef native_adler32
# define native_adler32 adler32_lsx
# undef native_adler32_copy
# define native_adler32_copy adler32_copy_lsx
# undef native_chunkmemset_safe
# define native_chunkmemset_safe chunkmemset_safe_lsx
# undef native_compare256
# define native_compare256 compare256_lsx
# undef native_inflate_fast
# define native_inflate_fast inflate_fast_lsx
# undef native_longest_match
# define native_longest_match longest_match_lsx
# undef native_longest_match_roll
# define native_longest_match_roll longest_match_roll_lsx
# undef native_slide_hash
# define native_slide_hash slide_hash_lsx
# endif
# ifdef LOONGARCH_LASX_NATIVE
# undef native_adler32
# define native_adler32 adler32_lasx
# undef native_adler32_copy
# define native_adler32_copy adler32_copy_lasx
# undef native_chunkmemset_safe
# define native_chunkmemset_safe chunkmemset_safe_lasx
# undef native_compare256
# define native_compare256 compare256_lasx
# undef native_inflate_fast
# define native_inflate_fast inflate_fast_lasx
# undef native_longest_match
# define native_longest_match longest_match_lasx
# undef native_longest_match_roll
# define native_longest_match_roll longest_match_roll_lasx
# undef native_slide_hash
# define native_slide_hash slide_hash_lasx
# endif
#endif
#endif /* LOONGARCH_FUNCTIONS_H_ */

View file

@ -1,25 +0,0 @@
/* loongarch_natives.h -- LoongArch compile-time feature detection macros.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef LOONGARCH_NATIVES_H_
#define LOONGARCH_NATIVES_H_
#if defined(__loongarch__)
// All known CPUs have crc instructions
# ifdef LOONGARCH_CRC
# define LOONGARCH_CRC_NATIVE
# endif
#endif
#if defined(__loongarch_sx)
# ifdef LOONGARCH_LSX
# define LOONGARCH_LSX_NATIVE
# endif
#endif
#if defined(__loongarch_asx)
# ifdef LOONGARCH_LASX
# define LOONGARCH_LASX_NATIVE
# endif
#endif
#endif /* LOONGARCH_NATIVES_H_ */

View file

@ -1,33 +0,0 @@
/* lsxintrin_ext.h
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef LSXINTRIN_EXT_H
#define LSXINTRIN_EXT_H
#include <lsxintrin.h>
static inline __m128i lsx_sad_bu(__m128i a, __m128i b) {
__m128i tmp = __lsx_vabsd_bu(a, b);
tmp = __lsx_vhaddw_hu_bu(tmp, tmp);
tmp = __lsx_vhaddw_wu_hu(tmp, tmp);
return __lsx_vhaddw_du_wu(tmp, tmp);
}
static inline int lsx_movemask_b(__m128i v) {
return __lsx_vpickve2gr_w(__lsx_vmskltz_b(v), 0);
}
static inline __m128i lsx_shuffle_b(__m128i a, __m128i b) {
/* most significant bit is set - negative 8-bit integer */
__m128i msb_mask = __lsx_vslti_b(b, 0);
/* shuffle, clear msb in indices vector b */
__m128i dst = __lsx_vshuf_b(a, a, __lsx_vandi_b(b, 0xF));
/* invert and apply mask - clear dst-element if b-msb is set */
return __lsx_vand_v(dst, __lsx_vnor_v(msb_mask, msb_mask));
}
#endif // include guard LSXINTRIN_EXT_H

View file

@ -1,49 +0,0 @@
/*
* LASX optimized hash slide, based on Intel AVX2 implementation
*
* Copyright (C) 2017 Intel Corporation
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* Authors:
* Arjan van de Ven <arjan@linux.intel.com>
* Jim Kukunas <james.t.kukunas@linux.intel.com>
* Mika T. Lindqvist <postmaster@raasu.org>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef LOONGARCH_LASX
#include "zbuild.h"
#include "deflate.h"
#include <lasxintrin.h>
static inline void slide_hash_chain(Pos *table, uint32_t entries, const __m256i wsize) {
table += entries;
table -= 32;
do {
__m256i value1, value2, result1, result2;
value1 = __lasx_xvld(table, 0);
value2 = __lasx_xvld(table, 32);
result1 = __lasx_xvssub_hu(value1, wsize);
result2 = __lasx_xvssub_hu(value2, wsize);
__lasx_xvst(result1, table, 0);
__lasx_xvst(result2, table, 32);
table -= 32;
entries -= 32;
} while (entries > 0);
}
Z_INTERNAL void slide_hash_lasx(deflate_state *s) {
Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t");
uint16_t wsize = (uint16_t)s->w_size;
const __m256i ymm_wsize = __lasx_xvreplgr2vr_h((short)wsize);
slide_hash_chain(s->head, HASH_SIZE, ymm_wsize);
slide_hash_chain(s->prev, wsize, ymm_wsize);
}
#endif

View file

@ -1,54 +0,0 @@
/*
* LSX optimized hash slide, based on Intel SSE implementation
*
* Copyright (C) 2017 Intel Corporation
* Copyright (C) 2025 Vladislav Shchapov <vladislav@shchapov.ru>
* Authors:
* Arjan van de Ven <arjan@linux.intel.com>
* Jim Kukunas <james.t.kukunas@linux.intel.com>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef LOONGARCH_LSX
#include "zbuild.h"
#include "deflate.h"
#include <lsxintrin.h>
#include <assert.h>
static inline void slide_hash_chain(Pos *table, uint32_t entries, const __m128i wsize) {
table += entries;
table -= 16;
/* ZALLOC allocates this pointer unless the user chose a custom allocator.
* Our alloc function is aligned to 64 byte boundaries */
do {
__m128i value0, value1, result0, result1;
value0 = __lsx_vld(table, 0);
value1 = __lsx_vld(table, 16);
result0 = __lsx_vssub_hu(value0, wsize);
result1 = __lsx_vssub_hu(value1, wsize);
__lsx_vst(result0, table, 0);
__lsx_vst(result1, table, 16);
table -= 16;
entries -= 16;
} while (entries > 0);
}
Z_INTERNAL void slide_hash_lsx(deflate_state *s) {
Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t");
uint16_t wsize = (uint16_t)s->w_size;
const __m128i xmm_wsize = __lsx_vreplgr2vr_h((short)wsize);
assert(((uintptr_t)s->head & 15) == 0);
assert(((uintptr_t)s->prev & 15) == 0);
slide_hash_chain(s->head, HASH_SIZE, xmm_wsize);
slide_hash_chain(s->prev, wsize, xmm_wsize);
}
#endif

View file

@ -1,93 +0,0 @@
# Makefile for POWER-specific files
# Copyright (C) 2020 Matheus Castanho <msc@linux.ibm.com>, IBM
# Copyright (C) 2021 Mika T. Lindqvist <postmaster@raasu.org>
# For conditions of distribution and use, see copyright notice in zlib.h
CC=
CFLAGS=
SFLAGS=
INCLUDES=
SUFFIX=
P8FLAGS=-mcpu=power8
P9FLAGS=-mcpu=power9
PPCFLAGS=-maltivec
NOLTOFLAG=
SRCDIR=.
SRCTOP=../..
TOPDIR=$(SRCTOP)
all: power_features.o \
power_features.lo \
adler32_power8.o \
adler32_power8.lo \
adler32_vmx.o \
adler32_vmx.lo \
chunkset_power8.o \
chunkset_power8.lo \
compare256_power9.o \
compare256_power9.lo \
crc32_power8.o \
crc32_power8.lo \
slide_hash_power8.o \
slide_hash_power8.lo \
slide_hash_vmx.o \
slide_hash_vmx.lo
power_features.o:
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/power_features.c
power_features.lo:
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/power_features.c
adler32_power8.o:
$(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_power8.c
adler32_power8.lo:
$(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_power8.c
adler32_vmx.o:
$(CC) $(CFLAGS) $(PPCFLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_vmx.c
adler32_vmx.lo:
$(CC) $(SFLAGS) $(PPCFLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_vmx.c
chunkset_power8.o:
$(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_power8.c
chunkset_power8.lo:
$(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_power8.c
compare256_power9.o:
$(CC) $(CFLAGS) $(P9FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_power9.c
compare256_power9.lo:
$(CC) $(SFLAGS) $(P9FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_power9.c
crc32_power8.o:
$(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_power8.c
crc32_power8.lo:
$(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_power8.c
slide_hash_power8.o:
$(CC) $(CFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_power8.c
slide_hash_power8.lo:
$(CC) $(SFLAGS) $(P8FLAGS) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_power8.c
slide_hash_vmx.o:
$(CC) $(CFLAGS) ${PPCFLAGS} $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_vmx.c
slide_hash_vmx.lo:
$(CC) $(SFLAGS) ${PPCFLAGS} $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_vmx.c
mostlyclean: clean
clean:
rm -f *.o *.lo *~
rm -rf objs
rm -f *.gcda *.gcno *.gcov
distclean: clean
rm -f Makefile

View file

@ -1,160 +0,0 @@
/* Adler32 for POWER8 using VSX instructions.
* Copyright (C) 2020 IBM Corporation
* Author: Rogerio Alves <rcardoso@linux.ibm.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*
* Calculate adler32 checksum for 16 bytes at once using POWER8+ VSX (vector)
* instructions.
*
* If adler32 do 1 byte at time on the first iteration s1 is s1_0 (_n means
* iteration n) is the initial value of adler - at start _0 is 1 unless
* adler initial value is different than 1. So s1_1 = s1_0 + c[0] after
* the first calculation. For the iteration s1_2 = s1_1 + c[1] and so on.
* Hence, for iteration N, s1_N = s1_(N-1) + c[N] is the value of s1 on
* after iteration N.
*
* Therefore, for s2 and iteration N, s2_N = s2_0 + N*s1_N + N*c[0] +
* N-1*c[1] + ... + c[N]
*
* In a more general way:
*
* s1_N = s1_0 + sum(i=1 to N)c[i]
* s2_N = s2_0 + N*s1 + sum (i=1 to N)(N-i+1)*c[i]
*
* Where s1_N, s2_N are the values for s1, s2 after N iterations. So if we
* can process N-bit at time we can do this at once.
*
* Since VSX can support 16-bit vector instructions, we can process
* 16-bit at time using N = 16 we have:
*
* s1 = s1_16 = s1_(16-1) + c[16] = s1_0 + sum(i=1 to 16)c[i]
* s2 = s2_16 = s2_0 + 16*s1 + sum(i=1 to 16)(16-i+1)*c[i]
*
* After the first iteration we calculate the adler32 checksum for 16 bytes.
*
* For more background about adler32 please check the RFC:
* https://www.ietf.org/rfc/rfc1950.txt
*/
#ifdef POWER8_VSX
#include "zbuild.h"
#include "adler32_p.h"
#include <altivec.h>
/* Vector across sum unsigned int (saturate). */
static inline vector unsigned int vec_sumsu(vector unsigned int __a, vector unsigned int __b) {
__b = vec_sld(__a, __a, 8);
__b = vec_add(__b, __a);
__a = vec_sld(__b, __b, 4);
__a = vec_add(__a, __b);
return __a;
}
Z_FORCEINLINE static uint32_t adler32_impl(uint32_t adler, const uint8_t *buf, size_t len) {
uint32_t s1 = adler & 0xffff;
uint32_t s2 = (adler >> 16) & 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (UNLIKELY(len == 1))
return adler32_copy_tail(s1, NULL, buf, 1, s2, 1, 1, 0);
/* This is faster than VSX code for len < 64. */
if (len < 64)
return adler32_copy_tail(s1, NULL, buf, len, s2, 1, 63, 0);
/* Use POWER VSX instructions for len >= 64. */
const vector unsigned int v_zeros = { 0 };
const vector unsigned char v_mul = {16, 15, 14, 13, 12, 11, 10, 9, 8, 7,
6, 5, 4, 3, 2, 1};
const vector unsigned char vsh = vec_splat_u8(4);
const vector unsigned int vmask = {0xffffffff, 0x0, 0x0, 0x0};
vector unsigned int vs1 = { 0 };
vector unsigned int vs2 = { 0 };
vector unsigned int vs1_save = { 0 };
vector unsigned int vsum1, vsum2;
vector unsigned char vbuf;
int n;
vs1[0] = s1;
vs2[0] = s2;
/* Do length bigger than NMAX in blocks of NMAX size. */
while (len >= NMAX) {
len -= NMAX;
n = NMAX / 16;
do {
vbuf = vec_xl(0, (unsigned char *) buf);
vsum1 = vec_sum4s(vbuf, v_zeros); /* sum(i=1 to 16) buf[i]. */
/* sum(i=1 to 16) buf[i]*(16-i+1). */
vsum2 = vec_msum(vbuf, v_mul, v_zeros);
/* Save vs1. */
vs1_save = vec_add(vs1_save, vs1);
/* Accumulate the sums. */
vs1 = vec_add(vsum1, vs1);
vs2 = vec_add(vsum2, vs2);
buf += 16;
} while (--n);
/* Once each block of NMAX size. */
vs1 = vec_sumsu(vs1, vsum1);
vs1_save = vec_sll(vs1_save, vsh); /* 16*vs1_save. */
vs2 = vec_add(vs1_save, vs2);
vs2 = vec_sumsu(vs2, vsum2);
/* vs1[0] = (s1_i + sum(i=1 to 16)buf[i]) mod 65521. */
vs1[0] = vs1[0] % BASE;
/* vs2[0] = s2_i + 16*s1_save +
sum(i=1 to 16)(16-i+1)*buf[i] mod 65521. */
vs2[0] = vs2[0] % BASE;
vs1 = vec_and(vs1, vmask);
vs2 = vec_and(vs2, vmask);
vs1_save = v_zeros;
}
/* len is less than NMAX one modulo is needed. */
if (len >= 16) {
while (len >= 16) {
len -= 16;
vbuf = vec_xl(0, (unsigned char *) buf);
vsum1 = vec_sum4s(vbuf, v_zeros); /* sum(i=1 to 16) buf[i]. */
/* sum(i=1 to 16) buf[i]*(16-i+1). */
vsum2 = vec_msum(vbuf, v_mul, v_zeros);
/* Save vs1. */
vs1_save = vec_add(vs1_save, vs1);
/* Accumulate the sums. */
vs1 = vec_add(vsum1, vs1);
vs2 = vec_add(vsum2, vs2);
buf += 16;
}
/* Since the size will be always less than NMAX we do this once. */
vs1 = vec_sumsu(vs1, vsum1);
vs1_save = vec_sll(vs1_save, vsh); /* 16*vs1_save. */
vs2 = vec_add(vs1_save, vs2);
vs2 = vec_sumsu(vs2, vsum2);
}
/* Copy result back to s1, s2 (mod 65521). */
s1 = vs1[0] % BASE;
s2 = vs2[0] % BASE;
/* Process tail (len < 16). */
return adler32_copy_tail(s1, NULL, buf, len, s2, len != 0, 15, 0);
}
Z_INTERNAL uint32_t adler32_power8(uint32_t adler, const uint8_t *buf, size_t len) {
return adler32_impl(adler, buf, len);
}
/* VSX/VMX stores can have higher latency than optimized memcpy on POWER8+ */
Z_INTERNAL uint32_t adler32_copy_power8(uint32_t adler, uint8_t *dst, const uint8_t *buf, size_t len) {
adler = adler32_impl(adler, buf, len);
memcpy(dst, buf, len);
return adler;
}
#endif /* POWER8_VSX */

View file

@ -1,168 +0,0 @@
/* adler32_vmx.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2011 Mark Adler
* Copyright (C) 2017-2023 Mika T. Lindqvist <postmaster@raasu.org>
* Copyright (C) 2021 Adam Stylinski <kungfujesus06@gmail.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef PPC_VMX
#include "zbuild.h"
#include "zendian.h"
#include "adler32_p.h"
#include <altivec.h>
#define vmx_zero() (vec_splat_u32(0))
static void vmx_accum32(uint32_t *s, const uint8_t *buf, size_t len) {
/* Different taps for the separable components of sums */
const vector unsigned char t0 = {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49};
const vector unsigned char t1 = {48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33};
const vector unsigned char t2 = {32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17};
const vector unsigned char t3 = {16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
/* As silly and inefficient as it seems, creating 1 permutation vector to permute
* a 2 element vector from a single load + a subsequent shift is just barely faster
* than doing 2 indexed insertions into zero initialized vectors from unaligned memory. */
const vector unsigned char s0_perm = {0, 1, 2, 3, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
const vector unsigned char shift_vec = vec_sl(vec_splat_u8(8), vec_splat_u8(2));
vector unsigned int adacc, s2acc;
vector unsigned int pair_vec = vec_ld(0, s);
adacc = vec_perm(pair_vec, pair_vec, s0_perm);
#if BYTE_ORDER == LITTLE_ENDIAN
s2acc = vec_sro(pair_vec, shift_vec);
#else
s2acc = vec_slo(pair_vec, shift_vec);
#endif
vector unsigned int zero = vmx_zero();
vector unsigned int s3acc = zero;
vector unsigned int s3acc_0 = zero;
vector unsigned int adacc_prev = adacc;
vector unsigned int adacc_prev_0 = zero;
vector unsigned int s2acc_0 = zero;
vector unsigned int s2acc_1 = zero;
vector unsigned int s2acc_2 = zero;
/* Maintain a running sum of a second half, this might help use break yet another
* data dependency bubble in the sum */
vector unsigned int adacc_0 = zero;
int num_iter = len / 4;
int rem = len & 3;
for (int i = 0; i < num_iter; ++i) {
vector unsigned char d0 = vec_ld(0, buf);
vector unsigned char d1 = vec_ld(16, buf);
vector unsigned char d2 = vec_ld(32, buf);
vector unsigned char d3 = vec_ld(48, buf);
/* The core operation of the loop, basically
* what is being unrolled below */
adacc = vec_sum4s(d0, adacc);
s3acc = vec_add(s3acc, adacc_prev);
s3acc_0 = vec_add(s3acc_0, adacc_prev_0);
s2acc = vec_msum(t0, d0, s2acc);
/* interleave dependent sums in here */
adacc_0 = vec_sum4s(d1, adacc_0);
s2acc_0 = vec_msum(t1, d1, s2acc_0);
adacc = vec_sum4s(d2, adacc);
s2acc_1 = vec_msum(t2, d2, s2acc_1);
s2acc_2 = vec_msum(t3, d3, s2acc_2);
adacc_0 = vec_sum4s(d3, adacc_0);
adacc_prev = adacc;
adacc_prev_0 = adacc_0;
buf += 64;
}
adacc = vec_add(adacc, adacc_0);
s3acc = vec_add(s3acc, s3acc_0);
s3acc = vec_sl(s3acc, vec_splat_u32(6));
if (rem) {
adacc_prev = vec_add(adacc_prev_0, adacc_prev);
adacc_prev = vec_sl(adacc_prev, vec_splat_u32(4));
while (rem--) {
vector unsigned char d0 = vec_ld(0, buf);
adacc = vec_sum4s(d0, adacc);
s3acc = vec_add(s3acc, adacc_prev);
s2acc = vec_msum(t3, d0, s2acc);
adacc_prev = vec_sl(adacc, vec_splat_u32(4));
buf += 16;
}
}
/* Sum up independent second sums */
s2acc = vec_add(s2acc, s2acc_0);
s2acc_2 = vec_add(s2acc_1, s2acc_2);
s2acc = vec_add(s2acc, s2acc_2);
s2acc = vec_add(s2acc, s3acc);
adacc = vec_add(adacc, vec_sld(adacc, adacc, 8));
s2acc = vec_add(s2acc, vec_sld(s2acc, s2acc, 8));
adacc = vec_add(adacc, vec_sld(adacc, adacc, 4));
s2acc = vec_add(s2acc, vec_sld(s2acc, s2acc, 4));
vec_ste(adacc, 0, s);
vec_ste(s2acc, 0, s+1);
}
Z_INTERNAL uint32_t adler32_vmx(uint32_t adler, const uint8_t *buf, size_t len) {
/* Split Adler-32 into component sums */
uint32_t sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (UNLIKELY(len == 1))
return adler32_copy_tail(adler, NULL, buf, 1, sum2, 1, 1, 0);
/* in case short lengths are provided, keep it somewhat fast */
if (UNLIKELY(len < 16))
return adler32_copy_tail(adler, NULL, buf, len, sum2, 1, 15, 0);
uint32_t pair[4] ALIGNED_(16);
pair[0] = adler;
pair[1] = sum2;
pair[2] = 0;
pair[3] = 0;
// Align buffer
size_t align_diff = MIN(ALIGN_DIFF(buf, 16), len);
size_t n = NMAX;
if (align_diff) {
adler32_copy_align(&pair[0], NULL, buf, align_diff, &pair[1], 15, 0);
buf += align_diff;
len -= align_diff;
n -= align_diff;
}
while (len >= 16) {
n = MIN(len, n);
vmx_accum32(pair, buf, n / 16);
pair[0] %= BASE;
pair[1] %= BASE;
size_t k = (n / 16) * 16;
buf += k;
len -= k;
n = NMAX;
}
/* Process tail (len < 16). */
return adler32_copy_tail(pair[0], NULL, buf, len, pair[1], len != 0 || align_diff, 15, 0);
}
/* VMX stores can have higher latency than optimized memcpy */
Z_INTERNAL uint32_t adler32_copy_vmx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) {
adler = adler32_vmx(adler, src, len);
memcpy(dst, src, len);
return adler;
}
#endif

View file

@ -1,50 +0,0 @@
/* chunkset_power8.c -- VSX inline functions to copy small data chunks.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef POWER8_VSX
#include "zbuild.h"
#include "zmemory.h"
#include <altivec.h>
typedef vector unsigned char chunk_t;
#define HAVE_CHUNKMEMSET_2
#define HAVE_CHUNKMEMSET_4
#define HAVE_CHUNKMEMSET_8
static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) {
*chunk = (vector unsigned char)vec_splats(zng_memread_2(from));
}
static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) {
*chunk = (vector unsigned char)vec_splats(zng_memread_4(from));
}
static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) {
*chunk = (vector unsigned char)vec_splats((unsigned long long)zng_memread_8(from));
}
static inline void loadchunk(uint8_t const *s, chunk_t *chunk) {
*chunk = vec_xl(0, s);
}
static inline void storechunk(uint8_t *out, chunk_t *chunk) {
vec_xst(*chunk, 0, out);
}
#define CHUNKSIZE chunksize_power8
#define CHUNKCOPY chunkcopy_power8
#define CHUNKUNROLL chunkunroll_power8
#define CHUNKMEMSET chunkmemset_power8
#define CHUNKMEMSET_SAFE chunkmemset_safe_power8
#include "chunkset_tpl.h"
#define INFLATE_FAST inflate_fast_power8
#include "inffast_tpl.h"
#endif

View file

@ -1,68 +0,0 @@
/* compare256_power9.c - Power9 version of compare256
* Copyright (C) 2019 Matheus Castanho <msc@linux.ibm.com>, IBM
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef POWER9
#include "zbuild.h"
#include "zmemory.h"
#include "deflate.h"
#include "zendian.h"
#include <altivec.h>
/* Older versions of GCC misimplemented semantics for these bit counting builtins.
* https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=3f30f2d1dbb3228b8468b26239fe60c2974ce2ac */
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 12)
#if BYTE_ORDER == LITTLE_ENDIAN
# define zng_vec_vctzlsbb(vc, len) len = __builtin_vec_vctzlsbb(vc)
#else
# define zng_vec_vctzlsbb(vc, len) len = __builtin_vec_vclzlsbb(vc)
#endif
#else
# define zng_vec_vctzlsbb(vc, len) len = vec_cntlz_lsbb(vc)
#endif
static inline uint32_t compare256_power9_static(const uint8_t *src0, const uint8_t *src1) {
uint32_t len = 0, cmplen;
do {
vector unsigned char vsrc0, vsrc1, vc;
vsrc0 = *((vector unsigned char *)src0);
vsrc1 = *((vector unsigned char *)src1);
/* Compare 16 bytes at a time. Each byte of vc will be either
* all ones or all zeroes, depending on the result of the comparison. */
vc = (vector unsigned char)vec_cmpne(vsrc0, vsrc1);
/* Since the index of matching bytes will contain only zeroes
* on vc (since we used cmpne), counting the number of consecutive
* bytes where LSB == 0 is the same as counting the length of the match. */
zng_vec_vctzlsbb(vc, cmplen);
if (cmplen != 16)
return len + cmplen;
src0 += 16, src1 += 16, len += 16;
} while (len < 256);
return 256;
}
Z_INTERNAL uint32_t compare256_power9(const uint8_t *src0, const uint8_t *src1) {
return compare256_power9_static(src0, src1);
}
#define LONGEST_MATCH longest_match_power9
#define COMPARE256 compare256_power9_static
#include "match_tpl.h"
#define LONGEST_MATCH_ROLL
#define LONGEST_MATCH longest_match_roll_power9
#define COMPARE256 compare256_power9_static
#include "match_tpl.h"
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,593 +0,0 @@
/* crc32 for POWER8 using VSX instructions
* Copyright (C) 2021 IBM Corporation
*
* Author: Rogerio Alves <rogealve@br.ibm.com>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*
* Calculate the checksum of data that is 16 byte aligned and a multiple of
* 16 bytes.
*
* The first step is to reduce it to 1024 bits. We do this in 8 parallel
* chunks in order to mask the latency of the vpmsum instructions. If we
* have more than 32 kB of data to checksum we repeat this step multiple
* times, passing in the previous 1024 bits.
*
* The next step is to reduce the 1024 bits to 64 bits. This step adds
* 32 bits of 0s to the end - this matches what a CRC does. We just
* calculate constants that land the data in this 32 bits.
*
* We then use fixed point Barrett reduction to compute a mod n over GF(2)
* for n = CRC using POWER8 instructions. We use x = 32.
*
* http://en.wikipedia.org/wiki/Barrett_reduction
*
* This code uses gcc vector builtins instead using assembly directly.
*/
#ifdef POWER8_VSX_CRC32
#include "zbuild.h"
#include "zendian.h"
#include "crc32_constants.h"
#include "crc32_braid_tbl.h"
#include "power_intrins.h"
#define MAX_SIZE 32768
#define VMX_ALIGN 16
#define VMX_ALIGN_MASK (VMX_ALIGN-1)
static unsigned int crc32_align(unsigned int crc, const unsigned char *p, unsigned long len) {
while (len--)
crc = crc_table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
return crc;
}
static unsigned int ALIGNED_(32) __crc32_vpmsum(unsigned int crc, const void* p, unsigned long len);
Z_INTERNAL uint32_t crc32_power8(uint32_t crc, const unsigned char *p, size_t _len) {
unsigned int prealign;
unsigned int tail;
unsigned long len = (unsigned long) _len;
crc ^= 0xffffffff;
if (len < VMX_ALIGN + VMX_ALIGN_MASK) {
crc = crc32_align(crc, p, len);
goto out;
}
if ((unsigned long)p & VMX_ALIGN_MASK) {
prealign = (unsigned int)ALIGN_DIFF(p, VMX_ALIGN);
crc = crc32_align(crc, p, prealign);
len -= prealign;
p += prealign;
}
crc = __crc32_vpmsum(crc, p, ALIGN_DOWN(len, VMX_ALIGN));
tail = len & VMX_ALIGN_MASK;
if (tail) {
p += ALIGN_DOWN(len, VMX_ALIGN);
crc = crc32_align(crc, p, tail);
}
out:
crc ^= 0xffffffff;
return crc;
}
Z_INTERNAL uint32_t crc32_copy_power8(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) {
crc = crc32_power8(crc, src, len);
memcpy(dst, src, len);
return crc;
}
/* When we have a load-store in a single-dispatch group and address overlap
* such that forward is not allowed (load-hit-store) the group must be flushed.
* A group ending NOP prevents the flush.
*/
#define GROUP_ENDING_NOP __asm__("ori 2,2,0" ::: "memory")
#if BYTE_ORDER == BIG_ENDIAN
#define BYTESWAP_DATA
#endif
#ifdef BYTESWAP_DATA
#define VEC_PERM(vr, va, vb, vc) vr = vec_perm(va, vb, (__vector unsigned char) vc)
#if BYTE_ORDER == LITTLE_ENDIAN
/* Byte reverse permute constant LE. */
static const __vector unsigned long long vperm_const ALIGNED_(16) = { 0x08090A0B0C0D0E0FUL, 0x0001020304050607UL };
#else
static const __vector unsigned long long vperm_const ALIGNED_(16) = { 0x0F0E0D0C0B0A0908UL, 0X0706050403020100UL };
#endif
#else
#define VEC_PERM(vr, va, vb, vc)
#endif
static unsigned int ALIGNED_(32) __crc32_vpmsum(unsigned int crc, const void* p, unsigned long len) {
const __vector unsigned long long vzero = {0,0};
const __vector unsigned long long vones = {0xffffffffffffffffUL, 0xffffffffffffffffUL};
const __vector unsigned long long vmask_32bit =
(__vector unsigned long long)vec_sld((__vector unsigned char)vzero, (__vector unsigned char)vones, 4);
const __vector unsigned long long vmask_64bit =
(__vector unsigned long long)vec_sld((__vector unsigned char)vzero, (__vector unsigned char)vones, 8);
__vector unsigned long long vcrc;
__vector unsigned long long vconst1, vconst2;
/* vdata0-vdata7 will contain our data (p). */
__vector unsigned long long vdata0, vdata1, vdata2, vdata3, vdata4, vdata5, vdata6, vdata7;
/* v0-v7 will contain our checksums */
__vector unsigned long long v0 = {0,0};
__vector unsigned long long v1 = {0,0};
__vector unsigned long long v2 = {0,0};
__vector unsigned long long v3 = {0,0};
__vector unsigned long long v4 = {0,0};
__vector unsigned long long v5 = {0,0};
__vector unsigned long long v6 = {0,0};
__vector unsigned long long v7 = {0,0};
/* Vector auxiliary variables. */
__vector unsigned long long va0, va1, va2, va3, va4, va5, va6, va7;
unsigned int offset; /* Constant table offset. */
unsigned long i; /* Counter. */
unsigned long chunks;
unsigned long block_size;
int next_block = 0;
/* Align by 128 bits. The last 128 bit block will be processed at end. */
unsigned long length = len & 0xFFFFFFFFFFFFFF80UL;
vcrc = (__vector unsigned long long)__builtin_pack_vector_int128(0UL, crc);
/* Short version. */
if (len < 256) {
/* Calculate where in the constant table we need to start. */
offset = 256 - len;
vconst1 = vec_ld(offset, vcrc_short_const);
vdata0 = vec_ld(0, (__vector unsigned long long*) p);
VEC_PERM(vdata0, vdata0, vconst1, vperm_const);
/* xor initial value */
vdata0 = vec_xor(vdata0, vcrc);
vdata0 = (__vector unsigned long long) __builtin_crypto_vpmsumw(
(__vector unsigned int)vdata0, (__vector unsigned int)vconst1);
v0 = vec_xor(v0, vdata0);
for (i = 16; i < len; i += 16) {
vconst1 = vec_ld(offset + i, vcrc_short_const);
vdata0 = vec_ld(i, (__vector unsigned long long*) p);
VEC_PERM(vdata0, vdata0, vconst1, vperm_const);
vdata0 = (__vector unsigned long long) __builtin_crypto_vpmsumw(
(__vector unsigned int)vdata0, (__vector unsigned int)vconst1);
v0 = vec_xor(v0, vdata0);
}
} else {
/* Load initial values. */
vdata0 = vec_ld(0, (__vector unsigned long long*) p);
vdata1 = vec_ld(16, (__vector unsigned long long*) p);
VEC_PERM(vdata0, vdata0, vdata0, vperm_const);
VEC_PERM(vdata1, vdata1, vdata1, vperm_const);
vdata2 = vec_ld(32, (__vector unsigned long long*) p);
vdata3 = vec_ld(48, (__vector unsigned long long*) p);
VEC_PERM(vdata2, vdata2, vdata2, vperm_const);
VEC_PERM(vdata3, vdata3, vdata3, vperm_const);
vdata4 = vec_ld(64, (__vector unsigned long long*) p);
vdata5 = vec_ld(80, (__vector unsigned long long*) p);
VEC_PERM(vdata4, vdata4, vdata4, vperm_const);
VEC_PERM(vdata5, vdata5, vdata5, vperm_const);
vdata6 = vec_ld(96, (__vector unsigned long long*) p);
vdata7 = vec_ld(112, (__vector unsigned long long*) p);
VEC_PERM(vdata6, vdata6, vdata6, vperm_const);
VEC_PERM(vdata7, vdata7, vdata7, vperm_const);
/* xor in initial value */
vdata0 = vec_xor(vdata0, vcrc);
p = (char *)p + 128;
do {
/* Checksum in blocks of MAX_SIZE. */
block_size = length;
if (block_size > MAX_SIZE) {
block_size = MAX_SIZE;
}
length = length - block_size;
/*
* Work out the offset into the constants table to start at. Each
* constant is 16 bytes, and it is used against 128 bytes of input
* data - 128 / 16 = 8
*/
offset = (MAX_SIZE/8) - (block_size/8);
/* We reduce our final 128 bytes in a separate step */
chunks = (block_size/128)-1;
vconst1 = vec_ld(offset, vcrc_const);
va0 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata0,
(__vector unsigned long long)vconst1);
va1 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata1,
(__vector unsigned long long)vconst1);
va2 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata2,
(__vector unsigned long long)vconst1);
va3 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata3,
(__vector unsigned long long)vconst1);
va4 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata4,
(__vector unsigned long long)vconst1);
va5 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata5,
(__vector unsigned long long)vconst1);
va6 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata6,
(__vector unsigned long long)vconst1);
va7 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata7,
(__vector unsigned long long)vconst1);
if (chunks > 1) {
offset += 16;
vconst2 = vec_ld(offset, vcrc_const);
GROUP_ENDING_NOP;
vdata0 = vec_ld(0, (__vector unsigned long long*) p);
VEC_PERM(vdata0, vdata0, vdata0, vperm_const);
vdata1 = vec_ld(16, (__vector unsigned long long*) p);
VEC_PERM(vdata1, vdata1, vdata1, vperm_const);
vdata2 = vec_ld(32, (__vector unsigned long long*) p);
VEC_PERM(vdata2, vdata2, vdata2, vperm_const);
vdata3 = vec_ld(48, (__vector unsigned long long*) p);
VEC_PERM(vdata3, vdata3, vdata3, vperm_const);
vdata4 = vec_ld(64, (__vector unsigned long long*) p);
VEC_PERM(vdata4, vdata4, vdata4, vperm_const);
vdata5 = vec_ld(80, (__vector unsigned long long*) p);
VEC_PERM(vdata5, vdata5, vdata5, vperm_const);
vdata6 = vec_ld(96, (__vector unsigned long long*) p);
VEC_PERM(vdata6, vdata6, vdata6, vperm_const);
vdata7 = vec_ld(112, (__vector unsigned long long*) p);
VEC_PERM(vdata7, vdata7, vdata7, vperm_const);
p = (char *)p + 128;
/*
* main loop. Each iteration calculates the CRC for a 128-byte
* block.
*/
for (i = 0; i < chunks-2; i++) {
vconst1 = vec_ld(offset, vcrc_const);
offset += 16;
GROUP_ENDING_NOP;
v0 = vec_xor(v0, va0);
va0 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata0,
(__vector unsigned long long)vconst2);
vdata0 = vec_ld(0, (__vector unsigned long long*) p);
VEC_PERM(vdata0, vdata0, vdata0, vperm_const);
GROUP_ENDING_NOP;
v1 = vec_xor(v1, va1);
va1 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata1,
(__vector unsigned long long)vconst2);
vdata1 = vec_ld(16, (__vector unsigned long long*) p);
VEC_PERM(vdata1, vdata1, vdata1, vperm_const);
GROUP_ENDING_NOP;
v2 = vec_xor(v2, va2);
va2 = __builtin_crypto_vpmsumd((__vector unsigned long long)
vdata2, (__vector unsigned long long)vconst2);
vdata2 = vec_ld(32, (__vector unsigned long long*) p);
VEC_PERM(vdata2, vdata2, vdata2, vperm_const);
GROUP_ENDING_NOP;
v3 = vec_xor(v3, va3);
va3 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata3,
(__vector unsigned long long)vconst2);
vdata3 = vec_ld(48, (__vector unsigned long long*) p);
VEC_PERM(vdata3, vdata3, vdata3, vperm_const);
vconst2 = vec_ld(offset, vcrc_const);
GROUP_ENDING_NOP;
v4 = vec_xor(v4, va4);
va4 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata4,
(__vector unsigned long long)vconst1);
vdata4 = vec_ld(64, (__vector unsigned long long*) p);
VEC_PERM(vdata4, vdata4, vdata4, vperm_const);
GROUP_ENDING_NOP;
v5 = vec_xor(v5, va5);
va5 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata5,
(__vector unsigned long long)vconst1);
vdata5 = vec_ld(80, (__vector unsigned long long*) p);
VEC_PERM(vdata5, vdata5, vdata5, vperm_const);
GROUP_ENDING_NOP;
v6 = vec_xor(v6, va6);
va6 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata6,
(__vector unsigned long long)vconst1);
vdata6 = vec_ld(96, (__vector unsigned long long*) p);
VEC_PERM(vdata6, vdata6, vdata6, vperm_const);
GROUP_ENDING_NOP;
v7 = vec_xor(v7, va7);
va7 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata7,
(__vector unsigned long long)vconst1);
vdata7 = vec_ld(112, (__vector unsigned long long*) p);
VEC_PERM(vdata7, vdata7, vdata7, vperm_const);
p = (char *)p + 128;
}
/* First cool down */
vconst1 = vec_ld(offset, vcrc_const);
offset += 16;
v0 = vec_xor(v0, va0);
va0 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata0,
(__vector unsigned long long)vconst1);
GROUP_ENDING_NOP;
v1 = vec_xor(v1, va1);
va1 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata1,
(__vector unsigned long long)vconst1);
GROUP_ENDING_NOP;
v2 = vec_xor(v2, va2);
va2 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata2,
(__vector unsigned long long)vconst1);
GROUP_ENDING_NOP;
v3 = vec_xor(v3, va3);
va3 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata3,
(__vector unsigned long long)vconst1);
GROUP_ENDING_NOP;
v4 = vec_xor(v4, va4);
va4 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata4,
(__vector unsigned long long)vconst1);
GROUP_ENDING_NOP;
v5 = vec_xor(v5, va5);
va5 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata5,
(__vector unsigned long long)vconst1);
GROUP_ENDING_NOP;
v6 = vec_xor(v6, va6);
va6 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata6,
(__vector unsigned long long)vconst1);
GROUP_ENDING_NOP;
v7 = vec_xor(v7, va7);
va7 = __builtin_crypto_vpmsumd((__vector unsigned long long)vdata7,
(__vector unsigned long long)vconst1);
}/* else */
/* Second cool down. */
v0 = vec_xor(v0, va0);
v1 = vec_xor(v1, va1);
v2 = vec_xor(v2, va2);
v3 = vec_xor(v3, va3);
v4 = vec_xor(v4, va4);
v5 = vec_xor(v5, va5);
v6 = vec_xor(v6, va6);
v7 = vec_xor(v7, va7);
/*
* vpmsumd produces a 96 bit result in the least significant bits
* of the register. Since we are bit reflected we have to shift it
* left 32 bits so it occupies the least significant bits in the
* bit reflected domain.
*/
v0 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0,
(__vector unsigned char)vzero, 4);
v1 = (__vector unsigned long long)vec_sld((__vector unsigned char)v1,
(__vector unsigned char)vzero, 4);
v2 = (__vector unsigned long long)vec_sld((__vector unsigned char)v2,
(__vector unsigned char)vzero, 4);
v3 = (__vector unsigned long long)vec_sld((__vector unsigned char)v3,
(__vector unsigned char)vzero, 4);
v4 = (__vector unsigned long long)vec_sld((__vector unsigned char)v4,
(__vector unsigned char)vzero, 4);
v5 = (__vector unsigned long long)vec_sld((__vector unsigned char)v5,
(__vector unsigned char)vzero, 4);
v6 = (__vector unsigned long long)vec_sld((__vector unsigned char)v6,
(__vector unsigned char)vzero, 4);
v7 = (__vector unsigned long long)vec_sld((__vector unsigned char)v7,
(__vector unsigned char)vzero, 4);
/* xor with the last 1024 bits. */
va0 = vec_ld(0, (__vector unsigned long long*) p);
VEC_PERM(va0, va0, va0, vperm_const);
va1 = vec_ld(16, (__vector unsigned long long*) p);
VEC_PERM(va1, va1, va1, vperm_const);
va2 = vec_ld(32, (__vector unsigned long long*) p);
VEC_PERM(va2, va2, va2, vperm_const);
va3 = vec_ld(48, (__vector unsigned long long*) p);
VEC_PERM(va3, va3, va3, vperm_const);
va4 = vec_ld(64, (__vector unsigned long long*) p);
VEC_PERM(va4, va4, va4, vperm_const);
va5 = vec_ld(80, (__vector unsigned long long*) p);
VEC_PERM(va5, va5, va5, vperm_const);
va6 = vec_ld(96, (__vector unsigned long long*) p);
VEC_PERM(va6, va6, va6, vperm_const);
va7 = vec_ld(112, (__vector unsigned long long*) p);
VEC_PERM(va7, va7, va7, vperm_const);
p = (char *)p + 128;
vdata0 = vec_xor(v0, va0);
vdata1 = vec_xor(v1, va1);
vdata2 = vec_xor(v2, va2);
vdata3 = vec_xor(v3, va3);
vdata4 = vec_xor(v4, va4);
vdata5 = vec_xor(v5, va5);
vdata6 = vec_xor(v6, va6);
vdata7 = vec_xor(v7, va7);
/* Check if we have more blocks to process */
next_block = 0;
if (length != 0) {
next_block = 1;
/* zero v0-v7 */
v0 = vec_xor(v0, v0);
v1 = vec_xor(v1, v1);
v2 = vec_xor(v2, v2);
v3 = vec_xor(v3, v3);
v4 = vec_xor(v4, v4);
v5 = vec_xor(v5, v5);
v6 = vec_xor(v6, v6);
v7 = vec_xor(v7, v7);
}
length = length + 128;
} while (next_block);
/* Calculate how many bytes we have left. */
length = (len & 127);
/* Calculate where in (short) constant table we need to start. */
offset = 128 - length;
v0 = vec_ld(offset, vcrc_short_const);
v1 = vec_ld(offset + 16, vcrc_short_const);
v2 = vec_ld(offset + 32, vcrc_short_const);
v3 = vec_ld(offset + 48, vcrc_short_const);
v4 = vec_ld(offset + 64, vcrc_short_const);
v5 = vec_ld(offset + 80, vcrc_short_const);
v6 = vec_ld(offset + 96, vcrc_short_const);
v7 = vec_ld(offset + 112, vcrc_short_const);
offset += 128;
v0 = (__vector unsigned long long)__builtin_crypto_vpmsumw(
(__vector unsigned int)vdata0, (__vector unsigned int)v0);
v1 = (__vector unsigned long long)__builtin_crypto_vpmsumw(
(__vector unsigned int)vdata1, (__vector unsigned int)v1);
v2 = (__vector unsigned long long)__builtin_crypto_vpmsumw(
(__vector unsigned int)vdata2, (__vector unsigned int)v2);
v3 = (__vector unsigned long long)__builtin_crypto_vpmsumw(
(__vector unsigned int)vdata3, (__vector unsigned int)v3);
v4 = (__vector unsigned long long)__builtin_crypto_vpmsumw(
(__vector unsigned int)vdata4, (__vector unsigned int)v4);
v5 = (__vector unsigned long long)__builtin_crypto_vpmsumw(
(__vector unsigned int)vdata5, (__vector unsigned int)v5);
v6 = (__vector unsigned long long)__builtin_crypto_vpmsumw(
(__vector unsigned int)vdata6, (__vector unsigned int)v6);
v7 = (__vector unsigned long long)__builtin_crypto_vpmsumw(
(__vector unsigned int)vdata7, (__vector unsigned int)v7);
/* Now reduce the tail (0-112 bytes). */
for (i = 0; i < length; i+=16) {
vdata0 = vec_ld(i,(__vector unsigned long long*)p);
VEC_PERM(vdata0, vdata0, vdata0, vperm_const);
va0 = vec_ld(offset + i,vcrc_short_const);
va0 = (__vector unsigned long long)__builtin_crypto_vpmsumw(
(__vector unsigned int)vdata0, (__vector unsigned int)va0);
v0 = vec_xor(v0, va0);
}
/* xor all parallel chunks together. */
v0 = vec_xor(v0, v1);
v2 = vec_xor(v2, v3);
v4 = vec_xor(v4, v5);
v6 = vec_xor(v6, v7);
v0 = vec_xor(v0, v2);
v4 = vec_xor(v4, v6);
v0 = vec_xor(v0, v4);
}
/* Barrett Reduction */
vconst1 = vec_ld(0, v_Barrett_const);
vconst2 = vec_ld(16, v_Barrett_const);
v1 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0,
(__vector unsigned char)v0, 8);
v0 = vec_xor(v1,v0);
/* shift left one bit */
__vector unsigned char vsht_splat = vec_splat_u8 (1);
v0 = (__vector unsigned long long)vec_sll((__vector unsigned char)v0, vsht_splat);
v0 = vec_and(v0, vmask_64bit);
/*
* The reflected version of Barrett reduction. Instead of bit
* reflecting our data (which is expensive to do), we bit reflect our
* constants and our algorithm, which means the intermediate data in
* our vector registers goes from 0-63 instead of 63-0. We can reflect
* the algorithm because we don't carry in mod 2 arithmetic.
*/
/* bottom 32 bits of a */
v1 = vec_and(v0, vmask_32bit);
/* ma */
v1 = __builtin_crypto_vpmsumd((__vector unsigned long long)v1,
(__vector unsigned long long)vconst1);
/* bottom 32bits of ma */
v1 = vec_and(v1, vmask_32bit);
/* qn */
v1 = __builtin_crypto_vpmsumd((__vector unsigned long long)v1,
(__vector unsigned long long)vconst2);
/* a - qn, subtraction is xor in GF(2) */
v0 = vec_xor (v0, v1);
/*
* Since we are bit reflected, the result (ie the low 32 bits) is in
* the high 32 bits. We just need to shift it left 4 bytes
* V0 [ 0 1 X 3 ]
* V0 [ 0 X 2 3 ]
*/
/* shift result into top 64 bits of */
v0 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0,
(__vector unsigned char)vzero, 4);
#if BYTE_ORDER == BIG_ENDIAN
return v0[0];
#else
return v0[1];
#endif
}
#endif

View file

@ -1,54 +0,0 @@
/* power_features.c - POWER feature check
* Copyright (C) 2020 Matheus Castanho <msc@linux.ibm.com>, IBM
* Copyright (C) 2021-2024 Mika T. Lindqvist <postmaster@raasu.org>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#if defined(PPC_FEATURES) || defined(POWER_FEATURES)
#include "zbuild.h"
#include "power_features.h"
#ifdef HAVE_SYS_AUXV_H
# include <sys/auxv.h>
#endif
#ifdef POWER_NEED_AUXVEC_H
# include <linux/auxvec.h>
#endif
#ifdef __FreeBSD__
# include <machine/cpu.h>
#endif
void Z_INTERNAL power_check_features(struct power_cpu_features *features) {
#ifdef PPC_FEATURES
unsigned long hwcap;
#if defined(__FreeBSD__) || defined(__OpenBSD__)
elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
#else
hwcap = getauxval(AT_HWCAP);
#endif
if (hwcap & PPC_FEATURE_HAS_ALTIVEC)
features->has_altivec = 1;
#endif
#ifdef POWER_FEATURES
unsigned long hwcap2;
#if defined(__FreeBSD__) || defined(__OpenBSD__)
elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2));
#else
hwcap2 = getauxval(AT_HWCAP2);
#endif
#ifdef POWER8_VSX
if (hwcap2 & PPC_FEATURE2_ARCH_2_07)
features->has_arch_2_07 = 1;
#endif
#ifdef POWER9
if (hwcap2 & PPC_FEATURE2_ARCH_3_00)
features->has_arch_3_00 = 1;
#endif
#endif
}
#endif

View file

@ -1,18 +0,0 @@
/* power_features.h -- check for POWER CPU features
* Copyright (C) 2020 Matheus Castanho <msc@linux.ibm.com>, IBM
* Copyright (C) 2021 Mika T. Lindqvist <postmaster@raasu.org>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef POWER_FEATURES_H_
#define POWER_FEATURES_H_
struct power_cpu_features {
int has_altivec;
int has_arch_2_07;
int has_arch_3_00;
};
void Z_INTERNAL power_check_features(struct power_cpu_features *features);
#endif /* POWER_FEATURES_H_ */

View file

@ -1,90 +0,0 @@
/* power_functions.h -- POWER implementations for arch-specific functions.
* Copyright (C) 2020 Matheus Castanho <msc@linux.ibm.com>, IBM
* Copyright (C) 2021 Mika T. Lindqvist <postmaster@raasu.org>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef POWER_FUNCTIONS_H_
#define POWER_FUNCTIONS_H_
#include "power_natives.h"
#ifdef PPC_VMX
uint32_t adler32_vmx(uint32_t adler, const uint8_t *buf, size_t len);
uint32_t adler32_copy_vmx(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len);
void slide_hash_vmx(deflate_state *s);
#endif
#ifdef POWER8_VSX
uint32_t adler32_power8(uint32_t adler, const uint8_t *buf, size_t len);
uint32_t adler32_copy_power8(uint32_t adler, uint8_t *dst, const uint8_t *buf, size_t len);
uint8_t* chunkmemset_safe_power8(uint8_t *out, uint8_t *from, size_t len, size_t left);
uint32_t crc32_power8(uint32_t crc, const uint8_t *buf, size_t len);
uint32_t crc32_copy_power8(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len);
void slide_hash_power8(deflate_state *s);
void inflate_fast_power8(PREFIX3(stream) *strm, uint32_t start);
#endif
#if !defined(PPC_VMX_NATIVE) && !defined(POWER8_VSX_NATIVE)
# define ADLER32_FALLBACK
# define SLIDE_HASH_FALLBACK
#endif
#ifndef POWER8_VSX_NATIVE
# define CHUNKSET_FALLBACK
#endif
#ifndef POWER8_VSX_CRC32_NATIVE
# define CRC32_BRAID_FALLBACK
#endif
#ifdef POWER9
uint32_t compare256_power9(const uint8_t *src0, const uint8_t *src1);
uint32_t longest_match_power9(deflate_state *const s, uint32_t cur_match);
uint32_t longest_match_roll_power9(deflate_state *const s, uint32_t cur_match);
#endif
#ifndef POWER9_NATIVE
# define COMPARE256_FALLBACK
#endif
#ifdef DISABLE_RUNTIME_CPU_DETECTION
// Power - VMX
# ifdef PPC_VMX_NATIVE
# undef native_adler32
# define native_adler32 adler32_vmx
# undef native_adler32_copy
# define native_adler32_copy adler32_copy_vmx
# undef native_slide_hash
# define native_slide_hash slide_hash_vmx
# endif
// Power8 - VSX
# ifdef POWER8_VSX_NATIVE
# undef native_adler32
# define native_adler32 adler32_power8
# undef native_adler32_copy
# define native_adler32_copy adler32_copy_power8
# undef native_chunkmemset_safe
# define native_chunkmemset_safe chunkmemset_safe_power8
# undef native_inflate_fast
# define native_inflate_fast inflate_fast_power8
# undef native_slide_hash
# define native_slide_hash slide_hash_power8
# endif
# ifdef POWER8_VSX_CRC32_NATIVE
# undef native_crc32
# define native_crc32 crc32_power8
# undef native_crc32_copy
# define native_crc32_copy crc32_copy_power8
# endif
// Power9
# ifdef POWER9_NATIVE
# undef native_compare256
# define native_compare256 compare256_power9
# undef native_longest_match
# define native_longest_match longest_match_power9
# undef native_longest_match_roll
# define native_longest_match_roll longest_match_roll_power9
# endif
#endif
#endif /* POWER_FUNCTIONS_H_ */

View file

@ -1,61 +0,0 @@
/* Helper functions to work around issues with clang builtins
* Copyright (C) 2021 IBM Corporation
*
* Authors:
* Daniel Black <daniel@linux.vnet.ibm.com>
* Rogerio Alves <rogealve@br.ibm.com>
* Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef POWER_INTRINS_H
#define POWER_INTRINS_H
#include <altivec.h>
#if defined (__clang__)
/*
* These stubs fix clang incompatibilities with GCC builtins.
*/
#ifndef __builtin_crypto_vpmsumw
#define __builtin_crypto_vpmsumw __builtin_crypto_vpmsumb
#endif
#ifndef __builtin_crypto_vpmsumd
#define __builtin_crypto_vpmsumd __builtin_crypto_vpmsumb
#endif
#ifdef __VSX__
static inline __vector unsigned long long __attribute__((overloadable))
vec_ld(int __a, const __vector unsigned long long* __b) {
return (__vector unsigned long long)__builtin_altivec_lvx(__a, __b);
}
#endif
#endif
/* There's no version of this that operates over unsigned and if casted, it does
* sign extension. Let's write an endian independent version and hope the compiler
* eliminates creating another zero idiom for the zero value if one exists locally */
static inline vector unsigned short vec_unpackl(vector unsigned char a) {
vector unsigned char zero = vec_splat_u8(0);
#if BYTE_ORDER == BIG_ENDIAN
return (vector unsigned short)vec_mergel(zero, a);
#else
return (vector unsigned short)vec_mergel(a, zero);
#endif
}
static inline vector unsigned short vec_unpackh(vector unsigned char a) {
vector unsigned char zero = vec_splat_u8(0);
#if BYTE_ORDER == BIG_ENDIAN
return (vector unsigned short)vec_mergeh(zero, a);
#else
return (vector unsigned short)vec_mergeh(a, zero);
#endif
}
#endif

View file

@ -1,27 +0,0 @@
/* power_natives.h -- POWER compile-time feature detection macros.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef POWER_NATIVES_H_
#define POWER_NATIVES_H_
#if defined(__ALTIVEC__)
# ifdef PPC_VMX
# define PPC_VMX_NATIVE
# endif
#endif
#if defined(_ARCH_PWR8) && defined(__VSX__)
# ifdef POWER8_VSX
# define POWER8_VSX_NATIVE
# endif
# ifdef POWER8_VSX_CRC32
# define POWER8_VSX_CRC32_NATIVE
# endif
#endif
#if defined(_ARCH_PWR9)
# ifdef POWER9
# define POWER9_NATIVE
# endif
#endif
#endif /* POWER_NATIVES_H_ */

View file

@ -1,12 +0,0 @@
/* Optimized slide_hash for POWER processors
* Copyright (C) 2019-2020 IBM Corporation
* Author: Matheus Castanho <msc@linux.ibm.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef POWER8_VSX
#define SLIDE_PPC slide_hash_power8
#include "slide_ppc_tpl.h"
#endif /* POWER8_VSX */

View file

@ -1,10 +0,0 @@
/* Optimized slide_hash for PowerPC processors with VMX instructions
* Copyright (C) 2017-2021 Mika T. Lindqvist <postmaster@raasu.org>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef PPC_VMX
#define SLIDE_PPC slide_hash_vmx
#include "slide_ppc_tpl.h"
#endif /* PPC_VMX */

View file

@ -1,44 +0,0 @@
/* Optimized slide_hash for PowerPC processors
* Copyright (C) 2017-2021 Mika T. Lindqvist <postmaster@raasu.org>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include <altivec.h>
#include "zbuild.h"
#include "deflate.h"
static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) {
const vector unsigned short vmx_wsize = vec_splats(wsize);
Pos *p = table;
do {
/* Do the pointer arithmetic early to hopefully overlap the vector unit */
Pos *q = p;
p += 32;
vector unsigned short value0, value1, value2, value3;
vector unsigned short result0, result1, result2, result3;
value0 = vec_ld(0, q);
value1 = vec_ld(16, q);
value2 = vec_ld(32, q);
value3 = vec_ld(48, q);
result0 = vec_subs(value0, vmx_wsize);
result1 = vec_subs(value1, vmx_wsize);
result2 = vec_subs(value2, vmx_wsize);
result3 = vec_subs(value3, vmx_wsize);
vec_st(result0, 0, q);
vec_st(result1, 16, q);
vec_st(result2, 32, q);
vec_st(result3, 48, q);
entries -= 32;
} while (entries);
}
void Z_INTERNAL SLIDE_PPC(deflate_state *s) {
Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t");
uint16_t wsize = (uint16_t)s->w_size;
slide_hash_chain(s->head, HASH_SIZE, wsize);
slide_hash_chain(s->prev, wsize, wsize);
}

View file

@ -1,72 +0,0 @@
# Makefile for zlib-ng
# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler
# Copyright (C) 2024 Hans Kristian Rosbach
# Copyright (C) 2025 Yin Tong <yintong.ustc@bytedance.com>, ByteDance
# For conditions of distribution and use, see copyright notice in zlib.h
CC=
CFLAGS=
SFLAGS=
INCLUDES=
SUFFIX=
SRCDIR=.
SRCTOP=../..
TOPDIR=$(SRCTOP)
RVVFLAG=
RVVZBCFLAG=
ZBCFLAG=
all: \
riscv_features.o riscv_features.lo \
adler32_rvv.o adler32_rvv.lo \
chunkset_rvv.o chunkset_rvv.lo \
compare256_rvv.o compare256_rvv.lo \
slide_hash_rvv.o slide_hash_rvv.lo \
crc32_zbc.o crc32_zbc.lo
riscv_features.o: $(SRCDIR)/riscv_features.c
$(CC) $(CFLAGS) $(RVVZBCFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/riscv_features.c
riscv_features.lo: $(SRCDIR)/riscv_features.c
$(CC) $(SFLAGS) $(RVVZBCFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/riscv_features.c
adler32_rvv.o: $(SRCDIR)/adler32_rvv.c
$(CC) $(CFLAGS) $(RVVFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_rvv.c
adler32_rvv.lo: $(SRCDIR)/adler32_rvv.c
$(CC) $(SFLAGS) $(RVVFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/adler32_rvv.c
chunkset_rvv.o: $(SRCDIR)/chunkset_rvv.c
$(CC) $(CFLAGS) $(RVVFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_rvv.c
chunkset_rvv.lo: $(SRCDIR)/chunkset_rvv.c
$(CC) $(SFLAGS) $(RVVFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/chunkset_rvv.c
compare256_rvv.o: $(SRCDIR)/compare256_rvv.c
$(CC) $(CFLAGS) $(RVVFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_rvv.c
compare256_rvv.lo: $(SRCDIR)/compare256_rvv.c
$(CC) $(SFLAGS) $(RVVFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/compare256_rvv.c
slide_hash_rvv.o: $(SRCDIR)/slide_hash_rvv.c
$(CC) $(CFLAGS) $(RVVFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_rvv.c
slide_hash_rvv.lo: $(SRCDIR)/slide_hash_rvv.c
$(CC) $(SFLAGS) $(RVVFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_rvv.c
crc32_zbc.o: $(SRCDIR)/crc32_zbc.c
$(CC) $(CFLAGS) $(ZBCFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_zbc.c
crc32_zbc.lo: $(SRCDIR)/crc32_zbc.c
$(CC) $(SFLAGS) $(ZBCFLAG) -DPIC $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_zbc.c
mostlyclean: clean
clean:
rm -f *.o *.lo *~
rm -rf objs
rm -f *.gcda *.gcno *.gcov
distclean: clean
rm -f Makefile

View file

@ -1,45 +0,0 @@
# Building RISC-V Target with Cmake #
> **Warning**
> Runtime rvv detection (using `hwcap`) requires linux kernel 6.5 or newer.
>
> When running on older kernels, we fall back to compile-time detection, potentially this can cause crashes if rvv is enabled at compile but not supported by the target cpu.
> Therefore if older kernel support is needed, rvv should be disabled if the target cpu does not support it.
## Prerequisite: Build RISC-V Clang Toolchain and QEMU ##
If you don't have prebuilt clang and riscv64 qemu, you can refer to the [script](https://github.com/sifive/prepare-riscv-toolchain-qemu/blob/main/prepare_riscv_toolchain_qemu.sh) to get the source. Copy the script to the zlib-ng root directory, and run it to download the source and build them. Modify the content according to your conditions (e.g., toolchain version).
```bash
./prepare_riscv_toolchain_qemu.sh
```
After running script, clang & qemu are built in `build-toolchain-qemu/riscv-clang/` & `build-toolchain-qemu/riscv-qemu/`.
`build-toolchain-qemu/riscv-clang/` is your `TOOLCHAIN_PATH`.
`build-toolchain-qemu/riscv-qemu/bin/qemu-riscv64` is your `QEMU_PATH`.
You can also download the prebuilt toolchain & qemu from [the release page](https://github.com/sifive/prepare-riscv-toolchain-qemu/releases), and enjoy using them.
## Cross-Compile for RISC-V Target ##
```bash
cmake -G Ninja -B ./build-riscv \
-D CMAKE_TOOLCHAIN_FILE=./cmake/toolchain-riscv.cmake \
-D CMAKE_INSTALL_PREFIX=./build-riscv/install \
-D TOOLCHAIN_PATH={TOOLCHAIN_PATH} \
-D QEMU_PATH={QEMU_PATH} \
.
cmake --build ./build-riscv
```
Disable the option if there is no RVV support:
```
-D WITH_RVV=OFF
```
## Run Unittests on User Mode QEMU ##
```bash
cd ./build-riscv && ctest --verbose
```

View file

@ -1,119 +0,0 @@
/* adler32_rvv.c - RVV version of adler32
* Copyright (C) 2023 SiFive, Inc. All rights reserved.
* Contributed by Alex Chiang <alex.chiang@sifive.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef RISCV_RVV
#include "zbuild.h"
#include "adler32_p.h"
#include <riscv_vector.h>
Z_FORCEINLINE static uint32_t adler32_copy_impl(uint32_t adler, uint8_t* restrict dst, const uint8_t *src, size_t len, int COPY) {
/* split Adler-32 into component sums */
uint32_t sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (UNLIKELY(len == 1))
return adler32_copy_tail(adler, dst, src, 1, sum2, 1, 1, COPY);
/* in case short lengths are provided, keep it somewhat fast */
if (UNLIKELY(len < 16))
return adler32_copy_tail(adler, dst, src, len, sum2, 1, 15, COPY);
size_t left = len;
size_t vl = __riscv_vsetvlmax_e8m1();
vl = MIN(vl, 256);
vuint32m4_t v_buf32_accu = __riscv_vmv_v_x_u32m4(0, vl);
vuint32m4_t v_adler32_prev_accu = __riscv_vmv_v_x_u32m4(0, vl);
vuint16m2_t v_buf16_accu;
/*
* We accumulate 8-bit data, and to prevent overflow, we have to use a 32-bit accumulator.
* However, adding 8-bit data into a 32-bit accumulator isn't efficient. We use 16-bit & 32-bit
* accumulators to boost performance.
*
* The block_size is the largest multiple of vl that <= 256, because overflow would occur when
* vl > 256 (255 * 256 <= UINT16_MAX).
*
* We accumulate 8-bit data into a 16-bit accumulator and then
* move the data into the 32-bit accumulator at the last iteration.
*/
size_t block_size = (256 / vl) * vl;
size_t nmax_limit = (NMAX / block_size);
size_t cnt = 0;
while (left >= block_size) {
v_buf16_accu = __riscv_vmv_v_x_u16m2(0, vl);
size_t subprob = block_size;
while (subprob > 0) {
vuint8m1_t v_buf8 = __riscv_vle8_v_u8m1(src, vl);
if (COPY) __riscv_vse8_v_u8m1(dst, v_buf8, vl);
v_adler32_prev_accu = __riscv_vwaddu_wv_u32m4(v_adler32_prev_accu, v_buf16_accu, vl);
v_buf16_accu = __riscv_vwaddu_wv_u16m2(v_buf16_accu, v_buf8, vl);
src += vl;
if (COPY) dst += vl;
subprob -= vl;
}
v_adler32_prev_accu = __riscv_vmacc_vx_u32m4(v_adler32_prev_accu, block_size / vl, v_buf32_accu, vl);
v_buf32_accu = __riscv_vwaddu_wv_u32m4(v_buf32_accu, v_buf16_accu, vl);
left -= block_size;
/* do modulo once each block of NMAX size */
if (++cnt >= nmax_limit) {
v_adler32_prev_accu = __riscv_vremu_vx_u32m4(v_adler32_prev_accu, BASE, vl);
v_buf32_accu = __riscv_vremu_vx_u32m4(v_buf32_accu, BASE, vl);
cnt = 0;
}
}
/* the left len <= 256 now, we can use 16-bit accum safely */
v_buf16_accu = __riscv_vmv_v_x_u16m2(0, vl);
size_t res = left;
while (left >= vl) {
vuint8m1_t v_buf8 = __riscv_vle8_v_u8m1(src, vl);
if (COPY) __riscv_vse8_v_u8m1(dst, v_buf8, vl);
v_adler32_prev_accu = __riscv_vwaddu_wv_u32m4(v_adler32_prev_accu, v_buf16_accu, vl);
v_buf16_accu = __riscv_vwaddu_wv_u16m2(v_buf16_accu, v_buf8, vl);
src += vl;
if (COPY) dst += vl;
left -= vl;
}
v_adler32_prev_accu = __riscv_vmacc_vx_u32m4(v_adler32_prev_accu, res / vl, v_buf32_accu, vl);
v_adler32_prev_accu = __riscv_vremu_vx_u32m4(v_adler32_prev_accu, BASE, vl);
v_buf32_accu = __riscv_vwaddu_wv_u32m4(v_buf32_accu, v_buf16_accu, vl);
vuint32m4_t v_seq = __riscv_vid_v_u32m4(vl);
vuint32m4_t v_rev_seq = __riscv_vrsub_vx_u32m4(v_seq, vl, vl);
vuint32m4_t v_sum32_accu = __riscv_vmul_vv_u32m4(v_buf32_accu, v_rev_seq, vl);
v_sum32_accu = __riscv_vadd_vv_u32m4(v_sum32_accu, __riscv_vmul_vx_u32m4(v_adler32_prev_accu, vl, vl), vl);
vuint32m1_t v_sum2_sum = __riscv_vmv_s_x_u32m1(0, vl);
v_sum2_sum = __riscv_vredsum_vs_u32m4_u32m1(v_sum32_accu, v_sum2_sum, vl);
uint32_t sum2_sum = __riscv_vmv_x_s_u32m1_u32(v_sum2_sum) % BASE;
sum2 += (sum2_sum + adler * ((len - left) % BASE));
vuint32m1_t v_adler_sum = __riscv_vmv_s_x_u32m1(0, vl);
v_adler_sum = __riscv_vredsum_vs_u32m4_u32m1(v_buf32_accu, v_adler_sum, vl);
uint32_t adler_sum = __riscv_vmv_x_s_u32m1_u32(v_adler_sum) % BASE;
adler += adler_sum;
sum2 %= BASE;
adler %= BASE;
/* Process tail (left < 256). */
return adler32_copy_tail(adler, dst, src, left, sum2, left != 0, 255, COPY);
}
Z_INTERNAL uint32_t adler32_rvv(uint32_t adler, const uint8_t *buf, size_t len) {
return adler32_copy_impl(adler, NULL, buf, len, 0);
}
Z_INTERNAL uint32_t adler32_copy_rvv(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len) {
return adler32_copy_impl(adler, dst, src, len, 1);
}
#endif // RISCV_RVV

View file

@ -1,126 +0,0 @@
/* chunkset_rvv.c - RVV version of chunkset
* Copyright (C) 2023 SiFive, Inc. All rights reserved.
* Contributed by Alex Chiang <alex.chiang@sifive.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef RISCV_RVV
#include "zbuild.h"
#include <riscv_vector.h>
/*
* RISC-V glibc would enable RVV optimized memcpy at runtime by IFUNC,
* so we prefer using large size chunk and copy memory as much as possible.
*/
#define HAVE_CHUNKMEMSET_2
#define HAVE_CHUNKMEMSET_4
#define HAVE_CHUNKMEMSET_8
#define CHUNK_MEMSET_RVV_IMPL(from, chunk, elen) \
do { \
size_t vl, len = sizeof(*chunk) / sizeof(uint##elen##_t); \
uint##elen##_t val = *(uint##elen##_t*)from; \
uint##elen##_t* chunk_p = (uint##elen##_t*)chunk; \
do { \
vl = __riscv_vsetvl_e##elen##m4(len); \
vuint##elen##m4_t v_val = __riscv_vmv_v_x_u##elen##m4(val, vl); \
__riscv_vse##elen##_v_u##elen##m4(chunk_p, v_val, vl); \
len -= vl; chunk_p += vl; \
} while (len > 0); \
} while (0)
/* We don't have a 32-byte datatype for RISC-V arch. */
typedef struct chunk_s {
uint64_t data[4];
} chunk_t;
static inline void chunkmemset_2(uint8_t *from, chunk_t *chunk) {
CHUNK_MEMSET_RVV_IMPL(from, chunk, 16);
}
static inline void chunkmemset_4(uint8_t *from, chunk_t *chunk) {
CHUNK_MEMSET_RVV_IMPL(from, chunk, 32);
}
static inline void chunkmemset_8(uint8_t *from, chunk_t *chunk) {
CHUNK_MEMSET_RVV_IMPL(from, chunk, 64);
}
static inline void loadchunk(uint8_t const *s, chunk_t *chunk) {
memcpy(chunk->data, (uint8_t *)s, sizeof(*chunk));
}
static inline void storechunk(uint8_t *out, chunk_t *chunk) {
memcpy(out, chunk->data, sizeof(*chunk));
}
#define CHUNKSIZE chunksize_rvv
#define CHUNKCOPY chunkcopy_rvv
#define CHUNKUNROLL chunkunroll_rvv
#define CHUNKMEMSET chunkmemset_rvv
#define CHUNKMEMSET_SAFE chunkmemset_safe_rvv
#define HAVE_CHUNKCOPY
/*
* Assuming that the length is non-zero, and that `from` lags `out` by at least
* sizeof chunk_t bytes, please see the comments in chunkset_tpl.h.
*
* We load/store a single chunk once in the `CHUNKCOPY`.
* However, RISC-V glibc would enable RVV optimized memcpy at runtime by IFUNC,
* such that, we prefer copy large memory size once to make good use of the the RVV advance.
*
* To be aligned to the other platforms, we didn't modify `CHUNKCOPY` method a lot,
* but we still copy as much memory as possible for some conditions.
*
* case 1: out - from >= len (no overlap)
* We can use memcpy to copy `len` size once
* because the memory layout would be the same.
*
* case 2: overlap
* We copy N chunks using memcpy at once, aiming to achieve our goal:
* to copy as much memory as possible.
*
* After using a single memcpy to copy N chunks, we have to use series of
* loadchunk and storechunk to ensure the result is correct.
*/
static inline uint8_t* CHUNKCOPY(uint8_t *out, uint8_t const *from, size_t len) {
Assert(len > 0, "chunkcopy should never have a length 0");
size_t dist = out - from;
if (out < from || dist >= len) {
memcpy(out, from, len);
out += len;
from += len;
return out;
}
size_t align = ((len - 1) % sizeof(chunk_t)) + 1;
memcpy(out, from, sizeof(chunk_t));
out += align;
from += align;
len -= align;
size_t vl = (dist / sizeof(chunk_t)) * sizeof(chunk_t);
while (len > dist) {
memcpy(out, from, vl);
out += vl;
from += vl;
len -= vl;
}
if (len > 0) {
memcpy(out, from, len);
out += len;
}
return out;
}
#include "chunkset_tpl.h"
#define INFLATE_FAST inflate_fast_rvv
#include "inffast_tpl.h"
#endif

View file

@ -1,48 +0,0 @@
/* compare256_rvv.c - RVV version of compare256
* Copyright (C) 2023 SiFive, Inc. All rights reserved.
* Contributed by Alex Chiang <alex.chiang@sifive.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef RISCV_RVV
#include "zbuild.h"
#include "zmemory.h"
#include "deflate.h"
#include <riscv_vector.h>
static inline uint32_t compare256_rvv_static(const uint8_t *src0, const uint8_t *src1) {
uint32_t len = 0;
size_t vl;
long found_diff;
do {
vl = __riscv_vsetvl_e8m4(256 - len);
vuint8m4_t v_src0 = __riscv_vle8_v_u8m4(src0, vl);
vuint8m4_t v_src1 = __riscv_vle8_v_u8m4(src1, vl);
vbool2_t v_mask = __riscv_vmsne_vv_u8m4_b2(v_src0, v_src1, vl);
found_diff = __riscv_vfirst_m_b2(v_mask, vl);
if (found_diff >= 0)
return len + (uint32_t)found_diff;
src0 += vl, src1 += vl, len += vl;
} while (len < 256);
return 256;
}
Z_INTERNAL uint32_t compare256_rvv(const uint8_t *src0, const uint8_t *src1) {
return compare256_rvv_static(src0, src1);
}
#define LONGEST_MATCH longest_match_rvv
#define COMPARE256 compare256_rvv_static
#include "match_tpl.h"
#define LONGEST_MATCH_ROLL
#define LONGEST_MATCH longest_match_roll_rvv
#define COMPARE256 compare256_rvv_static
#include "match_tpl.h"
#endif // RISCV_RVV

View file

@ -1,103 +0,0 @@
/* crc32_zbc.c - RISCV Zbc version of crc32
* Copyright (C) 2025 ByteDance. All rights reserved.
* Contributed by Yin Tong <yintong.ustc@bytedance.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef RISCV_CRC32_ZBC
#include "zbuild.h"
#include "arch_functions.h"
#define CLMUL_MIN_LEN 16 // Minimum size of buffer for _crc32_clmul
#define CLMUL_CHUNK_LEN 16 // Length of chunk for clmul
#define CONSTANT_R3 0x1751997d0ULL
#define CONSTANT_R4 0x0ccaa009eULL
#define CONSTANT_R5 0x163cd6124ULL
#define MASK32 0xFFFFFFFF
#define CRCPOLY_TRUE_LE_FULL 0x1DB710641ULL
#define CONSTANT_RU 0x1F7011641ULL
static inline uint64_t clmul(uint64_t a, uint64_t b) {
uint64_t res;
__asm__ volatile("clmul %0, %1, %2" : "=r"(res) : "r"(a), "r"(b));
return res;
}
static inline uint64_t clmulh(uint64_t a, uint64_t b) {
uint64_t res;
__asm__ volatile("clmulh %0, %1, %2" : "=r"(res) : "r"(a), "r"(b));
return res;
}
Z_FORCEINLINE static uint32_t crc32_clmul_impl(uint64_t crc, const unsigned char *buf, uint64_t len) {
const uint64_t *buf64 = (const uint64_t *)buf;
uint64_t low = buf64[0] ^ crc;
uint64_t high = buf64[1];
if (len < 16)
goto finish_fold;
len -= 16;
buf64 += 2;
// process each 16-byte block
while (len >= 16) {
uint64_t t2 = clmul(CONSTANT_R4, high);
uint64_t t3 = clmulh(CONSTANT_R4, high);
uint64_t t0_new = clmul(CONSTANT_R3, low);
uint64_t t1_new = clmulh(CONSTANT_R3, low);
// Combine the results and XOR with new data
low = t0_new ^ t2;
high = t1_new ^ t3;
low ^= buf64[0];
high ^= buf64[1];
buf64 += 2;
len -= 16;
}
finish_fold:
// Fold the 128-bit result into 64 bits
uint64_t fold_t3 = clmulh(low, CONSTANT_R4);
uint64_t fold_t2 = clmul(low, CONSTANT_R4);
low = high ^ fold_t2;
high = fold_t3;
// Combine the low and high parts and perform polynomial reduction
uint64_t combined = (low >> 32) | ((high & MASK32) << 32);
uint64_t reduced_low = clmul(low & MASK32, CONSTANT_R5) ^ combined;
// Barrett reduction step
uint64_t barrett = clmul(reduced_low & MASK32, CONSTANT_RU) & MASK32;
barrett = clmul(barrett, CRCPOLY_TRUE_LE_FULL);
uint64_t final = barrett ^ reduced_low;
// Return the high 32 bits as the final CRC
return (uint32_t)(final >> 32);
}
Z_INTERNAL uint32_t crc32_riscv64_zbc(uint32_t crc, const uint8_t *buf, size_t len) {
if (len < CLMUL_MIN_LEN) {
return crc32_braid(crc, buf, len);
}
uint64_t unaligned_length = len % CLMUL_CHUNK_LEN;
if (unaligned_length) {
crc = crc32_braid(crc, buf, unaligned_length);
buf += unaligned_length;
len -= unaligned_length;
}
crc = crc32_clmul_impl(~crc, buf, len);
return ~crc;
}
Z_INTERNAL uint32_t crc32_copy_riscv64_zbc(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) {
crc = crc32_riscv64_zbc(crc, src, len);
memcpy(dst, src, len);
return crc;
}
#endif

View file

@ -1,99 +0,0 @@
#ifdef RISCV_FEATURES
#define _DEFAULT_SOURCE 1 /* For syscall() */
#include "zbuild.h"
#include "riscv_features.h"
#include <sys/utsname.h>
#if defined(__linux__) && defined(HAVE_SYS_AUXV_H)
# include <sys/auxv.h>
#endif
#if defined(__linux__) && defined(HAVE_ASM_HWPROBE_H)
# include <asm/hwprobe.h>
# include <sys/syscall.h> /* For __NR_riscv_hwprobe */
# include <unistd.h> /* For syscall() */
#endif
#define ISA_V_HWCAP (1 << ('v' - 'a'))
#define ISA_ZBC_HWCAP (1 << 29)
static int riscv_check_features_runtime_hwprobe(struct riscv_cpu_features *features) {
#if defined(__NR_riscv_hwprobe) && defined(RISCV_HWPROBE_KEY_IMA_EXT_0)
struct riscv_hwprobe probes[] = {
{RISCV_HWPROBE_KEY_IMA_EXT_0, 0},
};
int ret;
unsigned i;
ret = syscall(__NR_riscv_hwprobe, probes, sizeof(probes) / sizeof(probes[0]), 0, NULL, 0);
if (ret != 0) {
/* Kernel does not support hwprobe */
return 0;
}
for (i = 0; i < sizeof(probes) / sizeof(probes[0]); i++) {
switch (probes[i].key) {
case RISCV_HWPROBE_KEY_IMA_EXT_0:
# ifdef RISCV_HWPROBE_IMA_V
features->has_rvv = !!(probes[i].value & RISCV_HWPROBE_IMA_V);
# endif
# ifdef RISCV_HWPROBE_EXT_ZBC
features->has_zbc = !!(probes[i].value & RISCV_HWPROBE_EXT_ZBC);
# endif
break;
}
}
return 1;
#else
return 0;
#endif
}
static int riscv_check_features_runtime_hwcap(struct riscv_cpu_features *features) {
#if defined(__linux__) && defined(HAVE_SYS_AUXV_H)
unsigned long hw_cap = getauxval(AT_HWCAP);
features->has_rvv = hw_cap & ISA_V_HWCAP;
features->has_zbc = hw_cap & ISA_ZBC_HWCAP;
return 1;
#else
return 0;
#endif
}
static void riscv_check_features_runtime(struct riscv_cpu_features *features) {
if (riscv_check_features_runtime_hwprobe(features))
return;
riscv_check_features_runtime_hwcap(features);
}
void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features) {
riscv_check_features_runtime(features);
#ifdef RISCV_RVV
if (features->has_rvv) {
size_t e8m1_vec_len;
intptr_t vtype_reg_val;
// Check that a vuint8m1_t vector is at least 16 bytes and that tail
// agnostic and mask agnostic mode are supported
//
__asm__ volatile(
"vsetvli %0, zero, e8, m1, ta, ma\n\t"
"csrr %1, vtype"
: "=r"(e8m1_vec_len), "=r"(vtype_reg_val));
// The RVV target is supported if the VILL bit of VTYPE (the MSB bit of
// VTYPE) is not set and the length of a vuint8m1_t vector is at least 16
// bytes
features->has_rvv = (vtype_reg_val >= 0 && e8m1_vec_len >= 16);
}
#endif
}
#endif

View file

@ -1,19 +0,0 @@
/* riscv_features.h -- check for riscv features.
*
* Copyright (C) 2023 SiFive, Inc. All rights reserved.
* Contributed by Alex Chiang <alex.chiang@sifive.com>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef RISCV_FEATURES_H_
#define RISCV_FEATURES_H_
struct riscv_cpu_features {
int has_rvv;
int has_zbc;
};
void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features);
#endif /* RISCV_FEATURES_H_ */

View file

@ -1,69 +0,0 @@
/* riscv_functions.h -- RISCV implementations for arch-specific functions.
*
* Copyright (C) 2023 SiFive, Inc. All rights reserved.
* Contributed by Alex Chiang <alex.chiang@sifive.com>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef RISCV_FUNCTIONS_H_
#define RISCV_FUNCTIONS_H_
#include "riscv_natives.h"
#define CRC32_BRAID_FALLBACK /* used by crc32_zbc */
#ifdef RISCV_RVV
uint32_t adler32_rvv(uint32_t adler, const uint8_t *buf, size_t len);
uint32_t adler32_copy_rvv(uint32_t adler, uint8_t *dst, const uint8_t *src, size_t len);
uint8_t* chunkmemset_safe_rvv(uint8_t *out, uint8_t *from, size_t len, size_t left);
uint32_t compare256_rvv(const uint8_t *src0, const uint8_t *src1);
uint32_t longest_match_rvv(deflate_state *const s, uint32_t cur_match);
uint32_t longest_match_roll_rvv(deflate_state *const s, uint32_t cur_match);
void slide_hash_rvv(deflate_state *s);
void inflate_fast_rvv(PREFIX3(stream) *strm, uint32_t start);
#endif
#ifndef RISCV_RVV_NATIVE
# define ADLER32_FALLBACK
# define CHUNKSET_FALLBACK
# define COMPARE256_FALLBACK
# define SLIDE_HASH_FALLBACK
#endif
#ifdef RISCV_CRC32_ZBC
uint32_t crc32_riscv64_zbc(uint32_t crc, const uint8_t *buf, size_t len);
uint32_t crc32_copy_riscv64_zbc(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len);
#endif
#ifdef DISABLE_RUNTIME_CPU_DETECTION
// RISCV - RVV
# ifdef RISCV_RVV_NATIVE
# undef native_adler32
# define native_adler32 adler32_rvv
# undef native_adler32_copy
# define native_adler32_copy adler32_copy_rvv
# undef native_chunkmemset_safe
# define native_chunkmemset_safe chunkmemset_safe_rvv
# undef native_compare256
# define native_compare256 compare256_rvv
# undef native_inflate_fast
# define native_inflate_fast inflate_fast_rvv
# undef native_longest_match
# define native_longest_match longest_match_rvv
# undef native_longest_match_roll
# define native_longest_match_roll longest_match_roll_rvv
# undef native_slide_hash
# define native_slide_hash slide_hash_rvv
# endif
// RISCV - CRC32
# ifdef RISCV_ZBC_NATIVE
# undef native_crc32
# define native_crc32 crc32_riscv64_zbc
# undef native_crc32_copy
# define native_crc32_copy crc32_copy_riscv64_zbc
# endif
#endif
#endif /* RISCV_FUNCTIONS_H_ */

View file

@ -1,19 +0,0 @@
/* riscv_natives.h -- RISCV compile-time feature detection macros.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef RISCV_NATIVES_H_
#define RISCV_NATIVES_H_
#if defined(__riscv_v) && defined(__linux__)
# ifdef RISCV_RVV
# define RISCV_RVV_NATIVE
# endif
#endif
#if defined(__riscv_zbc)
# ifdef RISCV_CRC32_ZBC
# define RISCV_ZBC_NATIVE
# endif
#endif
#endif /* RISCV_NATIVES_H_ */

View file

@ -1,33 +0,0 @@
/* slide_hash_rvv.c - RVV version of slide_hash
* Copyright (C) 2023 SiFive, Inc. All rights reserved.
* Contributed by Alex Chiang <alex.chiang@sifive.com>
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef RISCV_RVV
#include "zbuild.h"
#include "deflate.h"
#include <riscv_vector.h>
static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) {
size_t vl;
while (entries > 0) {
vl = __riscv_vsetvl_e16m4(entries);
vuint16m4_t v_tab = __riscv_vle16_v_u16m4(table, vl);
vuint16m4_t v_diff = __riscv_vssubu_vx_u16m4(v_tab, wsize, vl);
__riscv_vse16_v_u16m4(table, v_diff, vl);
table += vl, entries -= vl;
}
}
Z_INTERNAL void slide_hash_rvv(deflate_state *s) {
Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t");
uint16_t wsize = (uint16_t)s->w_size;
slide_hash_chain(s->head, HASH_SIZE, wsize);
slide_hash_chain(s->prev, wsize, wsize);
}
#endif // RISCV_RVV

View file

@ -1,54 +0,0 @@
# Makefile for zlib-ng
# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler
# For conditions of distribution and use, see copyright notice in zlib.h
CC=
CFLAGS=
SFLAGS=
INCLUDES=
SUFFIX=
S390VXFLAG=
NOLTOFLAG=
SRCDIR=.
SRCTOP=../..
TOPDIR=$(SRCTOP)
s390_features.o:
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/s390_features.c
s390_features.lo:
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/s390_features.c
dfltcc_deflate.o:
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_deflate.c
dfltcc_deflate.lo:
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_deflate.c
dfltcc_inflate.o:
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_inflate.c
dfltcc_inflate.lo:
$(CC) $(SFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/dfltcc_inflate.c
crc32_vx.o:
$(CC) $(CFLAGS) $(S390VXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_vx.c
crc32_vx.lo:
$(CC) $(SFLAGS) $(S390VXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/crc32_vx.c
slide_hash_vx.o:
$(CC) $(CFLAGS) $(S390VXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_vx.c
slide_hash_vx.lo:
$(CC) $(SFLAGS) $(S390VXFLAG) $(NOLTOFLAG) $(INCLUDES) -c -o $@ $(SRCDIR)/slide_hash_vx.c
mostlyclean: clean
clean:
rm -f *.o *.lo *~
rm -rf objs
rm -f *.gcda *.gcno *.gcov
distclean: clean
rm -f Makefile

View file

@ -1,265 +0,0 @@
# Introduction
This directory contains SystemZ deflate hardware acceleration support.
It can be enabled using the following build commands:
$ ./configure --with-dfltcc-deflate --with-dfltcc-inflate
$ make
or
$ cmake -DWITH_DFLTCC_DEFLATE=1 -DWITH_DFLTCC_INFLATE=1 .
$ make
When built like this, zlib-ng would compress using hardware on level 1,
and using software on all other levels. Decompression will always happen
in hardware. In order to enable hardware compression for levels 1-6
(i.e. to make it used by default) one could add
`-DDFLTCC_LEVEL_MASK=0x7e` to CFLAGS when building zlib-ng.
SystemZ deflate hardware acceleration is available on [IBM z15](
https://www.ibm.com/products/z15) and newer machines under the name [
"Integrated Accelerator for zEnterprise Data Compression"](
https://www.ibm.com/support/z-content-solutions/compression/). The
programming interface to it is a machine instruction called DEFLATE
CONVERSION CALL (DFLTCC). It is documented in Chapter 26 of [Principles
of Operation](https://publibfp.dhe.ibm.com/epubs/pdf/a227832c.pdf). Both
the code and the rest of this document refer to this feature simply as
"DFLTCC".
# Performance
Performance figures are published [here](
https://github.com/iii-i/zlib-ng/wiki/Performance-with-dfltcc-patch-applied-and-dfltcc-support-built-on-dfltcc-enabled-machine
). The compression speed-up can be as high as 110x and the decompression
speed-up can be as high as 15x.
# Limitations
Two DFLTCC compression calls with identical inputs are not guaranteed to
produce identical outputs. Therefore care should be taken when using
hardware compression when reproducible results are desired. In
particular, zlib-ng-specific `zng_deflateSetParams` call allows setting
`Z_DEFLATE_REPRODUCIBLE` parameter, which disables DFLTCC support for a
particular stream.
DFLTCC does not support every single zlib-ng feature, in particular:
* `inflate(Z_BLOCK)` and `inflate(Z_TREES)`
* `inflateMark()`
* `inflatePrime()`
* `inflateSyncPoint()`
When used, these functions will either switch to software, or, in case
this is not possible, gracefully fail.
# Code structure
All SystemZ-specific code lives in `arch/s390` directory and is
integrated with the rest of zlib-ng using hook macros.
## Hook macros
DFLTCC takes as arguments a parameter block, an input buffer, an output
buffer, and a window. Parameter blocks are stored alongside zlib states;
buffers are forwarded from the caller; and window - which must be
4k-aligned and is always 64k large, is managed using the `PAD_WINDOW()`,
`WINDOW_PAD_SIZE`, `HINT_ALIGNED_WINDOW` and `DEFLATE_ADJUST_WINDOW_SIZE()`
and `INFLATE_ADJUST_WINDOW_SIZE()` hooks.
Software and hardware window formats do not match, therefore,
`deflateSetDictionary()`, `deflateGetDictionary()`, `inflateSetDictionary()`
and `inflateGetDictionary()` need special handling, which is triggered using
`DEFLATE_SET_DICTIONARY_HOOK()`, `DEFLATE_GET_DICTIONARY_HOOK()`,
`INFLATE_SET_DICTIONARY_HOOK()` and `INFLATE_GET_DICTIONARY_HOOK()` macros.
`deflateResetKeep()` and `inflateResetKeep()` update the DFLTCC
parameter block using `DEFLATE_RESET_KEEP_HOOK()` and
`INFLATE_RESET_KEEP_HOOK()` macros.
`INFLATE_PRIME_HOOK()`, `INFLATE_MARK_HOOK()` and
`INFLATE_SYNC_POINT_HOOK()` macros make the respective unsupported
calls gracefully fail.
`DEFLATE_PARAMS_HOOK()` implements switching between hardware and
software compression mid-stream using `deflateParams()`. Switching
normally entails flushing the current block, which might not be possible
in low memory situations. `deflateParams()` uses `DEFLATE_DONE()` hook
in order to detect and gracefully handle such situations.
The algorithm implemented in hardware has different compression ratio
than the one implemented in software. `DEFLATE_BOUND_ADJUST_COMPLEN()`
and `DEFLATE_NEED_CONSERVATIVE_BOUND()` macros make `deflateBound()`
return the correct results for the hardware implementation.
Actual compression and decompression are handled by `DEFLATE_HOOK()` and
`INFLATE_TYPEDO_HOOK()` macros. Since inflation with DFLTCC manages the
window on its own, calling `updatewindow()` is suppressed using
`INFLATE_NEED_UPDATEWINDOW()` macro.
In addition to compression, DFLTCC computes CRC-32 and Adler-32
checksums, therefore, whenever it's used, software checksumming is
suppressed using `DEFLATE_NEED_CHECKSUM()` and `INFLATE_NEED_CHECKSUM()`
macros.
While software always produces reproducible compression results, this
is not the case for DFLTCC. Therefore, zlib-ng users are given the
ability to specify whether or not reproducible compression results
are required. While it is always possible to specify this setting
before the compression begins, it is not always possible to do so in
the middle of a deflate stream - the exact conditions for that are
determined by `DEFLATE_CAN_SET_REPRODUCIBLE()` macro.
## SystemZ-specific code
When zlib-ng is built with DFLTCC, the hooks described above are
converted to calls to functions, which are implemented in
`arch/s390/dfltcc_*` files. The functions can be grouped in three broad
categories:
* Base DFLTCC support, e.g. wrapping the machine instruction - `dfltcc()`.
* Translating between software and hardware data formats, e.g.
`dfltcc_deflate_set_dictionary()`.
* Translating between software and hardware state machines, e.g.
`dfltcc_deflate()` and `dfltcc_inflate()`.
The functions from the first two categories are fairly simple, however,
various quirks in both software and hardware state machines make the
functions from the third category quite complicated.
### `dfltcc_deflate()` function
This function is called by `deflate()` and has the following
responsibilities:
* Checking whether DFLTCC can be used with the current stream. If this
is not the case, then it returns `0`, making `deflate()` use some
other function in order to compress in software. Otherwise it returns
`1`.
* Block management and Huffman table generation. DFLTCC ends blocks only
when explicitly instructed to do so by the software. Furthermore,
whether to use fixed or dynamic Huffman tables must also be determined
by the software. Since looking at data in order to gather statistics
would negate performance benefits, the following approach is used: the
first `DFLTCC_FIRST_FHT_BLOCK_SIZE` bytes are placed into a fixed
block, and every next `DFLTCC_BLOCK_SIZE` bytes are placed into
dynamic blocks.
* Writing EOBS. Block Closing Control bit in the parameter block
instructs DFLTCC to write EOBS, however, certain conditions need to be
met: input data length must be non-zero or Continuation Flag must be
set. To put this in simpler terms, DFLTCC will silently refuse to
write EOBS if this is the only thing that it is asked to do. Since the
code has to be able to emit EOBS in software anyway, in order to avoid
tricky corner cases Block Closing Control is never used. Whether to
write EOBS is instead controlled by `soft_bcc` variable.
* Triggering block post-processing. Depending on flush mode, `deflate()`
must perform various additional actions when a block or a stream ends.
`dfltcc_deflate()` informs `deflate()` about this using
`block_state *result` parameter.
* Converting software state fields into hardware parameter block fields,
and vice versa. For example, `wrap` and Check Value Type or `bi_valid`
and Sub-Byte Boundary. Certain fields cannot be translated and must
persist untouched in the parameter block between calls, for example,
Continuation Flag or Continuation State Buffer.
* Handling flush modes and low-memory situations. These aspects are
quite intertwined and pervasive. The general idea here is that the
code must not do anything in software - whether explicitly by e.g.
calling `send_eobs()`, or implicitly - by returning to `deflate()`
with certain return and `*result` values, when Continuation Flag is
set.
* Ending streams. When a new block is started and flush mode is
`Z_FINISH`, Block Header Final parameter block bit is used to mark
this block as final. However, sometimes an empty final block is
needed, and, unfortunately, just like with EOBS, DFLTCC will silently
refuse to do this. The general idea of DFLTCC implementation is to
rely as much as possible on the existing code. Here in order to do
this, the code pretends that it does not support DFLTCC, which makes
`deflate()` call a software compression function, which writes an
empty final block. Whether this is required is controlled by
`need_empty_block` variable.
* Error handling. This is simply converting
Operation-Ending-Supplemental Code to string. Errors can only happen
due to things like memory corruption, and therefore they don't affect
the `deflate()` return code.
### `dfltcc_inflate()` function
This function is called by `inflate()` from the `TYPEDO` state (that is,
when all the metadata is parsed and the stream is positioned at the type
bits of deflate block header) and it's responsible for the following:
* Falling back to software when flush mode is `Z_BLOCK` or `Z_TREES`.
Unfortunately, there is no way to ask DFLTCC to stop decompressing on
block or tree boundary.
* `inflate()` decompression loop management. This is controlled using
the return value, which can be either `DFLTCC_INFLATE_BREAK` or
`DFLTCC_INFLATE_CONTINUE`.
* Converting software state fields into hardware parameter block fields,
and vice versa. For example, `whave` and History Length or `wnext` and
History Offset.
* Ending streams. This instructs `inflate()` to return `Z_STREAM_END`
and is controlled by `last` state field.
* Error handling. Like deflate, error handling comprises
Operation-Ending-Supplemental Code to string conversion. Unlike
deflate, errors may happen due to bad inputs, therefore they are
propagated to `inflate()` by setting `mode` field to `MEM` or `BAD`.
# Testing
Given complexity of DFLTCC machine instruction, it is not clear whether
QEMU TCG will ever support it. At the time of writing, one has to have
access to an IBM z15+ VM or LPAR in order to test DFLTCC support. Since
DFLTCC is a non-privileged instruction, neither special VM/LPAR
configuration nor root are required.
zlib-ng CI uses an IBM-provided z15 self-hosted builder for the DFLTCC
testing. There is no official IBM Z GitHub Actions runner, so we build
one inspired by `anup-kodlekere/gaplib`.
Future updates to actions-runner might need an updated patch. The .net
version number patch has been separated into a separate file to avoid a
need for constantly changing the patch.
## Configuring the builder.
### Install prerequisites.
```
sudo dnf install podman
```
### Create a config file, needs github personal access token.
Access token needs permissions; Repo Admin RW, Org Self-hosted runners RW.
For details, consult
https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-a-repository
#### Create file /etc/actions-runner:
```
REPO=<owner>/<name>
PAT_TOKEN=<github_pat_***>
```
#### Set permissions on /etc/actions-runner:
```
chmod 600 /etc/actions-runner
```
### Add actions-runner service.
```
sudo cp self-hosted-builder/actions-runner.service /etc/systemd/system/
sudo systemctl daemon-reload
```
### Autostart actions-runner.
```
$ sudo systemctl enable --now actions-runner
```
### Add auto-rebuild cronjob
```
sudo cp self-hosted-builder/actions-runner-rebuild.sh /etc/cron.weekly/
chmod +x /etc/cron.weekly/actions-runner-rebuild.sh
```
## Building / Rebuilding the container
```
sudo /etc/cron.weekly/actions-runner-rebuild.sh
```

View file

@ -1,228 +0,0 @@
/*
* Hardware-accelerated CRC-32 variants for Linux on z Systems
*
* Use the z/Architecture Vector Extension Facility to accelerate the
* computing of bitreflected CRC-32 checksums.
*
* This CRC-32 implementation algorithm is bitreflected and processes
* the least-significant bit first (Little-Endian).
*
* This code was originally written by Hendrik Brueckner
* <brueckner@linux.vnet.ibm.com> for use in the Linux kernel and has been
* relicensed under the zlib license.
*/
#ifdef S390_VX
#include "zbuild.h"
#include "arch_functions.h"
#include "vx_intrins.h"
static uint32_t crc32_le_vgfm_16(uint32_t crc, const uint8_t *buf, size_t len) {
/*
* The CRC-32 constant block contains reduction constants to fold and
* process particular chunks of the input data stream in parallel.
*
* For the CRC-32 variants, the constants are precomputed according to
* these definitions:
*
* R1 = [(x4*128+32 mod P'(x) << 32)]' << 1
* R2 = [(x4*128-32 mod P'(x) << 32)]' << 1
* R3 = [(x128+32 mod P'(x) << 32)]' << 1
* R4 = [(x128-32 mod P'(x) << 32)]' << 1
* R5 = [(x64 mod P'(x) << 32)]' << 1
* R6 = [(x32 mod P'(x) << 32)]' << 1
*
* The bitreflected Barret reduction constant, u', is defined as
* the bit reversal of floor(x**64 / P(x)).
*
* where P(x) is the polynomial in the normal domain and the P'(x) is the
* polynomial in the reversed (bitreflected) domain.
*
* CRC-32 (IEEE 802.3 Ethernet, ...) polynomials:
*
* P(x) = 0x04C11DB7
* P'(x) = 0xEDB88320
*/
const uv16qi perm_le2be = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; /* BE->LE mask */
const uv2di r2r1 = {0x1C6E41596, 0x154442BD4}; /* R2, R1 */
const uv2di r4r3 = {0x0CCAA009E, 0x1751997D0}; /* R4, R3 */
const uv2di r5 = {0, 0x163CD6124}; /* R5 */
const uv2di ru_poly = {0, 0x1F7011641}; /* u' */
const uv2di crc_poly = {0, 0x1DB710641}; /* P'(x) << 1 */
/*
* Load the initial CRC value.
*
* The CRC value is loaded into the rightmost word of the
* vector register and is later XORed with the LSB portion
* of the loaded input data.
*/
uv2di v0 = {0, 0};
v0 = (uv2di)vec_insert(crc, (uv4si)v0, 3);
/* Load a 64-byte data chunk and XOR with CRC */
uv2di v1 = vec_perm(((uv2di *)buf)[0], ((uv2di *)buf)[0], perm_le2be);
uv2di v2 = vec_perm(((uv2di *)buf)[1], ((uv2di *)buf)[1], perm_le2be);
uv2di v3 = vec_perm(((uv2di *)buf)[2], ((uv2di *)buf)[2], perm_le2be);
uv2di v4 = vec_perm(((uv2di *)buf)[3], ((uv2di *)buf)[3], perm_le2be);
v1 ^= v0;
buf += 64;
len -= 64;
while (len >= 64) {
/* Load the next 64-byte data chunk */
uv16qi part1 = vec_perm(((uv16qi *)buf)[0], ((uv16qi *)buf)[0], perm_le2be);
uv16qi part2 = vec_perm(((uv16qi *)buf)[1], ((uv16qi *)buf)[1], perm_le2be);
uv16qi part3 = vec_perm(((uv16qi *)buf)[2], ((uv16qi *)buf)[2], perm_le2be);
uv16qi part4 = vec_perm(((uv16qi *)buf)[3], ((uv16qi *)buf)[3], perm_le2be);
/*
* Perform a GF(2) multiplication of the doublewords in V1 with
* the R1 and R2 reduction constants in V0. The intermediate result
* is then folded (accumulated) with the next data chunk in PART1 and
* stored in V1. Repeat this step for the register contents
* in V2, V3, and V4 respectively.
*/
v1 = (uv2di)vec_gfmsum_accum_128(r2r1, v1, part1);
v2 = (uv2di)vec_gfmsum_accum_128(r2r1, v2, part2);
v3 = (uv2di)vec_gfmsum_accum_128(r2r1, v3, part3);
v4 = (uv2di)vec_gfmsum_accum_128(r2r1, v4, part4);
buf += 64;
len -= 64;
}
/*
* Fold V1 to V4 into a single 128-bit value in V1. Multiply V1 with R3
* and R4 and accumulating the next 128-bit chunk until a single 128-bit
* value remains.
*/
v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v2);
v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v3);
v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v4);
while (len >= 16) {
/* Load next data chunk */
v2 = vec_perm(*(uv2di *)buf, *(uv2di *)buf, perm_le2be);
/* Fold next data chunk */
v1 = (uv2di)vec_gfmsum_accum_128(r4r3, v1, (uv16qi)v2);
buf += 16;
len -= 16;
}
/*
* Set up a vector register for byte shifts. The shift value must
* be loaded in bits 1-4 in byte element 7 of a vector register.
* Shift by 8 bytes: 0x40
* Shift by 4 bytes: 0x20
*/
uv16qi v9 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
v9 = vec_insert((unsigned char)0x40, v9, 7);
/*
* Prepare V0 for the next GF(2) multiplication: shift V0 by 8 bytes
* to move R4 into the rightmost doubleword and set the leftmost
* doubleword to 0x1.
*/
v0 = vec_srb(r4r3, (uv2di)v9);
v0[0] = 1;
/*
* Compute GF(2) product of V1 and V0. The rightmost doubleword
* of V1 is multiplied with R4. The leftmost doubleword of V1 is
* multiplied by 0x1 and is then XORed with rightmost product.
* Implicitly, the intermediate leftmost product becomes padded
*/
v1 = (uv2di)vec_gfmsum_128(v0, v1);
/*
* Now do the final 32-bit fold by multiplying the rightmost word
* in V1 with R5 and XOR the result with the remaining bits in V1.
*
* To achieve this by a single VGFMAG, right shift V1 by a word
* and store the result in V2 which is then accumulated. Use the
* vector unpack instruction to load the rightmost half of the
* doubleword into the rightmost doubleword element of V1; the other
* half is loaded in the leftmost doubleword.
* The vector register with CONST_R5 contains the R5 constant in the
* rightmost doubleword and the leftmost doubleword is zero to ignore
* the leftmost product of V1.
*/
v9 = vec_insert((unsigned char)0x20, v9, 7);
v2 = vec_srb(v1, (uv2di)v9);
v1 = vec_unpackl((uv4si)v1); /* Split rightmost doubleword */
v1 = (uv2di)vec_gfmsum_accum_128(r5, v1, (uv16qi)v2);
/*
* Apply a Barret reduction to compute the final 32-bit CRC value.
*
* The input values to the Barret reduction are the degree-63 polynomial
* in V1 (R(x)), degree-32 generator polynomial, and the reduction
* constant u. The Barret reduction result is the CRC value of R(x) mod
* P(x).
*
* The Barret reduction algorithm is defined as:
*
* 1. T1(x) = floor( R(x) / x^32 ) GF2MUL u
* 2. T2(x) = floor( T1(x) / x^32 ) GF2MUL P(x)
* 3. C(x) = R(x) XOR T2(x) mod x^32
*
* Note: The leftmost doubleword of vector register containing
* CONST_RU_POLY is zero and, thus, the intermediate GF(2) product
* is zero and does not contribute to the final result.
*/
/* T1(x) = floor( R(x) / x^32 ) GF2MUL u */
v2 = vec_unpackl((uv4si)v1);
v2 = (uv2di)vec_gfmsum_128(ru_poly, v2);
/*
* Compute the GF(2) product of the CRC polynomial with T1(x) in
* V2 and XOR the intermediate result, T2(x), with the value in V1.
* The final result is stored in word element 2 of V2.
*/
v2 = vec_unpackl((uv4si)v2);
v2 = (uv2di)vec_gfmsum_accum_128(crc_poly, v2, (uv16qi)v1);
return ((uv4si)v2)[2];
}
#define VX_MIN_LEN 64
#define VX_ALIGNMENT 16UL
#define VX_ALIGN_MASK (VX_ALIGNMENT - 1)
uint32_t Z_INTERNAL crc32_s390_vx(uint32_t crc, const unsigned char *buf, size_t len) {
size_t prealign, aligned, remaining;
if (len < VX_MIN_LEN + VX_ALIGN_MASK)
return crc32_braid(crc, buf, len);
if ((uintptr_t)buf & VX_ALIGN_MASK) {
prealign = (size_t)ALIGN_DIFF(buf, VX_ALIGNMENT);
len -= prealign;
crc = crc32_braid(crc, buf, prealign);
buf += prealign;
}
aligned = ALIGN_DOWN(len, VX_ALIGNMENT);
remaining = len & VX_ALIGN_MASK;
crc = ~crc32_le_vgfm_16(~crc, buf, aligned);
if (remaining)
crc = crc32_braid(crc, buf + aligned, remaining);
return crc;
}
Z_INTERNAL uint32_t crc32_copy_s390_vx(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) {
crc = crc32_s390_vx(crc, src, len);
memcpy(dst, src, len);
return crc;
}
#endif

View file

@ -1,119 +0,0 @@
#ifndef DFLTCC_COMMON_H
#define DFLTCC_COMMON_H
#include "zutil.h"
/*
Parameter Block for Query Available Functions.
*/
struct dfltcc_qaf_param {
char fns[16];
char reserved1[8];
char fmts[2];
char reserved2[6];
} ALIGNED_(8);
/*
Parameter Block for Generate Dynamic-Huffman Table, Compress and Expand.
*/
struct dfltcc_param_v0 {
uint16_t pbvn; /* Parameter-Block-Version Number */
uint8_t mvn; /* Model-Version Number */
uint8_t ribm; /* Reserved for IBM use */
uint32_t reserved32 : 31;
uint32_t cf : 1; /* Continuation Flag */
uint8_t reserved64[8];
uint32_t nt : 1; /* New Task */
uint32_t reserved129 : 1;
uint32_t cvt : 1; /* Check Value Type */
uint32_t reserved131 : 1;
uint32_t htt : 1; /* Huffman-Table Type */
uint32_t bcf : 1; /* Block-Continuation Flag */
uint32_t bcc : 1; /* Block Closing Control */
uint32_t bhf : 1; /* Block Header Final */
uint32_t reserved136 : 1;
uint32_t reserved137 : 1;
uint32_t dhtgc : 1; /* DHT Generation Control */
uint32_t reserved139 : 5;
uint32_t reserved144 : 5;
uint32_t sbb : 3; /* Sub-Byte Boundary */
uint8_t oesc; /* Operation-Ending-Supplemental Code */
uint32_t reserved160 : 12;
uint32_t ifs : 4; /* Incomplete-Function Status */
uint16_t ifl; /* Incomplete-Function Length */
uint8_t reserved192[8];
uint8_t reserved256[8];
uint8_t reserved320[4];
uint16_t hl; /* History Length */
uint32_t reserved368 : 1;
uint16_t ho : 15; /* History Offset */
uint32_t cv; /* Check Value */
uint32_t eobs : 15; /* End-of-block Symbol */
uint32_t reserved431: 1;
uint8_t eobl : 4; /* End-of-block Length */
uint32_t reserved436 : 12;
uint32_t reserved448 : 4;
uint16_t cdhtl : 12; /* Compressed-Dynamic-Huffman Table
Length */
uint8_t reserved464[6];
uint8_t cdht[288]; /* Compressed-Dynamic-Huffman Table */
uint8_t reserved[24];
uint8_t ribm2[8]; /* Reserved for IBM use */
uint8_t csb[1152]; /* Continuation-State Buffer */
} ALIGNED_(8);
/*
Extension of inflate_state and deflate_state.
*/
struct dfltcc_state {
struct dfltcc_param_v0 param; /* Parameter block. */
struct dfltcc_qaf_param af; /* Available functions. */
char msg[64]; /* Buffer for strm->msg */
};
typedef struct {
struct dfltcc_state common;
uint16_t level_mask; /* Levels on which to use DFLTCC */
uint32_t block_size; /* New block each X bytes */
size_t block_threshold; /* New block after total_in > X */
uint32_t dht_threshold; /* New block only if avail_in >= X */
} arch_deflate_state;
typedef struct {
struct dfltcc_state common;
} arch_inflate_state;
/*
History buffer size.
*/
#define HB_BITS 15
#define HB_SIZE (1 << HB_BITS)
/*
Sizes of deflate block parts.
*/
#define DFLTCC_BLOCK_HEADER_BITS 3
#define DFLTCC_HLITS_COUNT_BITS 5
#define DFLTCC_HDISTS_COUNT_BITS 5
#define DFLTCC_HCLENS_COUNT_BITS 4
#define DFLTCC_MAX_HCLENS 19
#define DFLTCC_HCLEN_BITS 3
#define DFLTCC_MAX_HLITS 286
#define DFLTCC_MAX_HDISTS 30
#define DFLTCC_MAX_HLIT_HDIST_BITS 7
#define DFLTCC_MAX_SYMBOL_BITS 16
#define DFLTCC_MAX_EOBS_BITS 15
#define DFLTCC_MAX_PADDING_BITS 7
#define DEFLATE_BOUND_COMPLEN(source_len) \
((DFLTCC_BLOCK_HEADER_BITS + \
DFLTCC_HLITS_COUNT_BITS + \
DFLTCC_HDISTS_COUNT_BITS + \
DFLTCC_HCLENS_COUNT_BITS + \
DFLTCC_MAX_HCLENS * DFLTCC_HCLEN_BITS + \
(DFLTCC_MAX_HLITS + DFLTCC_MAX_HDISTS) * DFLTCC_MAX_HLIT_HDIST_BITS + \
(source_len) * DFLTCC_MAX_SYMBOL_BITS + \
DFLTCC_MAX_EOBS_BITS + \
DFLTCC_MAX_PADDING_BITS) >> 3)
#endif

View file

@ -1,390 +0,0 @@
/* dfltcc_deflate.c - IBM Z DEFLATE CONVERSION CALL compression support. */
/*
Use the following commands to build zlib-ng with DFLTCC compression support:
$ ./configure --with-dfltcc-deflate
or
$ cmake -DWITH_DFLTCC_DEFLATE=1 .
and then
$ make
*/
#ifdef S390_DFLTCC_DEFLATE
#include "zbuild.h"
#include "deflate.h"
#include "deflate_p.h"
#include "trees_emit.h"
#include "dfltcc_deflate.h"
#include "dfltcc_detail.h"
void Z_INTERNAL PREFIX(dfltcc_reset_deflate_state)(PREFIX3(streamp) strm) {
deflate_state *state = (deflate_state *)strm->state;
arch_deflate_state *dfltcc_state = &state->arch;
dfltcc_reset_state(&dfltcc_state->common);
/* Initialize tuning parameters */
dfltcc_state->level_mask = DFLTCC_LEVEL_MASK;
dfltcc_state->block_size = DFLTCC_BLOCK_SIZE;
dfltcc_state->block_threshold = DFLTCC_FIRST_FHT_BLOCK_SIZE;
dfltcc_state->dht_threshold = DFLTCC_DHT_MIN_SAMPLE_SIZE;
}
static inline int dfltcc_can_deflate_with_params(PREFIX3(streamp) strm, int level, uInt window_bits, int strategy,
int reproducible) {
deflate_state *state = (deflate_state *)strm->state;
arch_deflate_state *dfltcc_state = &state->arch;
/* Unsupported compression settings */
if ((dfltcc_state->level_mask & (1 << level)) == 0)
return 0;
if (window_bits != HB_BITS)
return 0;
if (strategy != Z_FIXED && strategy != Z_DEFAULT_STRATEGY)
return 0;
if (reproducible)
return 0;
/* Unsupported hardware */
if (!is_bit_set(dfltcc_state->common.af.fns, DFLTCC_GDHT) ||
!is_bit_set(dfltcc_state->common.af.fns, DFLTCC_CMPR) ||
!is_bit_set(dfltcc_state->common.af.fmts, DFLTCC_FMT0))
return 0;
return 1;
}
int Z_INTERNAL PREFIX(dfltcc_can_deflate)(PREFIX3(streamp) strm) {
deflate_state *state = (deflate_state *)strm->state;
return dfltcc_can_deflate_with_params(strm, state->level, W_BITS(state), state->strategy, state->reproducible);
}
static inline void dfltcc_gdht(PREFIX3(streamp) strm) {
deflate_state *state = (deflate_state *)strm->state;
struct dfltcc_param_v0 *param = &state->arch.common.param;
size_t avail_in = strm->avail_in;
dfltcc(DFLTCC_GDHT, param, NULL, NULL, &strm->next_in, &avail_in, NULL);
}
static inline dfltcc_cc dfltcc_cmpr(PREFIX3(streamp) strm) {
deflate_state *state = (deflate_state *)strm->state;
struct dfltcc_param_v0 *param = &state->arch.common.param;
size_t avail_in = strm->avail_in;
size_t avail_out = strm->avail_out;
dfltcc_cc cc;
cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR,
param, &strm->next_out, &avail_out,
&strm->next_in, &avail_in, state->window);
strm->total_in += (strm->avail_in - avail_in);
strm->total_out += (strm->avail_out - avail_out);
strm->avail_in = avail_in;
strm->avail_out = avail_out;
return cc;
}
static inline void send_eobs(PREFIX3(streamp) strm, const struct dfltcc_param_v0 *param) {
deflate_state *state = (deflate_state *)strm->state;
send_bits(state, bi_reverse((uint16_t)(param->eobs >> (15 - param->eobl)), param->eobl),
param->eobl, state->bi_buf, state->bi_valid);
flush_pending_inline(strm);
if (state->pending != 0) {
/* The remaining data is located in pending_out[0:pending]. If someone
* calls put_byte() - this might happen in deflate() - the byte will be
* placed into pending_buf[pending], which is incorrect. Move the
* remaining data to the beginning of pending_buf so that put_byte() is
* usable again.
*/
memmove(state->pending_buf, state->pending_out, state->pending);
state->pending_out = state->pending_buf;
}
#ifdef ZLIB_DEBUG
state->compressed_len += param->eobl;
#endif
}
int Z_INTERNAL PREFIX(dfltcc_deflate)(PREFIX3(streamp) strm, int flush, block_state *result) {
deflate_state *state = (deflate_state *)strm->state;
arch_deflate_state *dfltcc_state = &state->arch;
struct dfltcc_param_v0 *param = &dfltcc_state->common.param;
uInt masked_avail_in;
dfltcc_cc cc;
int need_empty_block;
int soft_bcc;
int no_flush;
if (!PREFIX(dfltcc_can_deflate)(strm)) {
/* Clear history. */
if (flush == Z_FULL_FLUSH)
param->hl = 0;
return 0;
}
again:
masked_avail_in = 0;
soft_bcc = 0;
no_flush = flush == Z_NO_FLUSH;
/* No input data. Return, except when Continuation Flag is set, which means
* that DFLTCC has buffered some output in the parameter block and needs to
* be called again in order to flush it.
*/
if (strm->avail_in == 0 && !param->cf) {
/* A block is still open, and the hardware does not support closing
* blocks without adding data. Thus, close it manually.
*/
if (!no_flush && param->bcf) {
send_eobs(strm, param);
param->bcf = 0;
}
/* Let one of deflate_* functions write a trailing empty block. */
if (flush == Z_FINISH)
return 0;
/* Clear history. */
if (flush == Z_FULL_FLUSH)
param->hl = 0;
/* Trigger block post-processing if necessary. */
*result = no_flush ? need_more : block_done;
return 1;
}
/* There is an open non-BFINAL block, we are not going to close it just
* yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see
* more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new
* DHT in order to adapt to a possibly changed input data distribution.
*/
if (param->bcf && no_flush &&
strm->total_in > dfltcc_state->block_threshold &&
strm->avail_in >= dfltcc_state->dht_threshold) {
if (param->cf) {
/* We need to flush the DFLTCC buffer before writing the
* End-of-block Symbol. Mask the input data and proceed as usual.
*/
masked_avail_in += strm->avail_in;
strm->avail_in = 0;
no_flush = 0;
} else {
/* DFLTCC buffer is empty, so we can manually write the
* End-of-block Symbol right away.
*/
send_eobs(strm, param);
param->bcf = 0;
dfltcc_state->block_threshold = strm->total_in + dfltcc_state->block_size;
}
}
/* No space for compressed data. If we proceed, dfltcc_cmpr() will return
* DFLTCC_CC_OP1_TOO_SHORT without buffering header bits, but we will still
* set BCF=1, which is wrong. Avoid complications and return early.
*/
if (strm->avail_out == 0) {
*result = need_more;
return 1;
}
/* The caller gave us too much data. Pass only one block worth of
* uncompressed data to DFLTCC and mask the rest, so that on the next
* iteration we start a new block.
*/
if (no_flush && strm->avail_in > dfltcc_state->block_size) {
masked_avail_in += (strm->avail_in - dfltcc_state->block_size);
strm->avail_in = dfltcc_state->block_size;
}
/* When we have an open non-BFINAL deflate block and caller indicates that
* the stream is ending, we need to close an open deflate block and open a
* BFINAL one.
*/
need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf;
/* Translate stream to parameter block */
param->cvt = state->wrap == 2 ? CVT_CRC32 : CVT_ADLER32;
if (!no_flush)
/* We need to close a block. Always do this in software - when there is
* no input data, the hardware will not honor BCC. */
soft_bcc = 1;
if (flush == Z_FINISH && !param->bcf)
/* We are about to open a BFINAL block, set Block Header Final bit
* until the stream ends.
*/
param->bhf = 1;
/* DFLTCC-CMPR will write to next_out, so make sure that buffers with
* higher precedence are empty.
*/
Assert(state->pending == 0, "There must be no pending bytes");
Assert(state->bi_valid < 8, "There must be less than 8 pending bits");
param->sbb = (unsigned int)state->bi_valid;
if (param->sbb > 0)
*strm->next_out = (unsigned char)state->bi_buf;
/* Honor history and check value */
param->nt = 0;
if (state->wrap == 1)
param->cv = strm->adler;
else if (state->wrap == 2)
param->cv = ZSWAP32(strm->adler);
/* When opening a block, choose a Huffman-Table Type */
if (!param->bcf) {
if (state->strategy == Z_FIXED || (strm->total_in == 0 && dfltcc_state->block_threshold > 0))
param->htt = HTT_FIXED;
else {
param->htt = HTT_DYNAMIC;
dfltcc_gdht(strm);
}
}
/* Deflate */
do {
cc = dfltcc_cmpr(strm);
if (strm->avail_in < 4096 && masked_avail_in > 0)
/* We are about to call DFLTCC with a small input buffer, which is
* inefficient. Since there is masked data, there will be at least
* one more DFLTCC call, so skip the current one and make the next
* one handle more data.
*/
break;
} while (cc == DFLTCC_CC_AGAIN);
/* Translate parameter block to stream */
strm->msg = oesc_msg(dfltcc_state->common.msg, param->oesc);
state->bi_valid = param->sbb;
if (state->bi_valid == 0)
state->bi_buf = 0; /* Avoid accessing next_out */
else
state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1);
if (state->wrap == 1)
strm->adler = param->cv;
else if (state->wrap == 2)
strm->adler = ZSWAP32(param->cv);
/* Unmask the input data */
strm->avail_in += masked_avail_in;
masked_avail_in = 0;
/* If we encounter an error, it means there is a bug in DFLTCC call */
Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG");
/* Update Block-Continuation Flag. It will be used to check whether to call
* GDHT the next time.
*/
if (cc == DFLTCC_CC_OK) {
if (soft_bcc) {
send_eobs(strm, param);
param->bcf = 0;
dfltcc_state->block_threshold = strm->total_in + dfltcc_state->block_size;
} else
param->bcf = 1;
if (flush == Z_FINISH) {
if (need_empty_block)
/* Make the current deflate() call also close the stream */
return 0;
else {
bi_windup(state);
*result = finish_done;
}
} else {
if (flush == Z_FULL_FLUSH)
param->hl = 0; /* Clear history */
*result = flush == Z_NO_FLUSH ? need_more : block_done;
}
} else {
param->bcf = 1;
*result = need_more;
}
if (strm->avail_in != 0 && strm->avail_out != 0)
goto again; /* deflate() must use all input or all output */
return 1;
}
/*
Switching between hardware and software compression.
DFLTCC does not support all zlib settings, e.g. generation of non-compressed
blocks or alternative window sizes. When such settings are applied on the
fly with deflateParams, we need to convert between hardware and software
window formats.
*/
static int dfltcc_was_deflate_used(PREFIX3(streamp) strm) {
deflate_state *state = (deflate_state *)strm->state;
struct dfltcc_param_v0 *param = &state->arch.common.param;
return strm->total_in > 0 || param->nt == 0 || param->hl > 0;
}
int Z_INTERNAL PREFIX(dfltcc_deflate_params)(PREFIX3(streamp) strm, int level, int strategy, int *flush) {
deflate_state *state = (deflate_state *)strm->state;
int could_deflate = PREFIX(dfltcc_can_deflate)(strm);
int can_deflate = dfltcc_can_deflate_with_params(strm, level, W_BITS(state), strategy, state->reproducible);
if (can_deflate == could_deflate)
/* We continue to work in the same mode - no changes needed */
return Z_OK;
if (!dfltcc_was_deflate_used(strm))
/* DFLTCC was not used yet - no changes needed */
return Z_OK;
/* For now, do not convert between window formats - simply get rid of the old data instead */
*flush = Z_FULL_FLUSH;
return Z_OK;
}
int Z_INTERNAL PREFIX(dfltcc_deflate_done)(PREFIX3(streamp) strm, int flush) {
deflate_state *state = (deflate_state *)strm->state;
struct dfltcc_param_v0 *param = &state->arch.common.param;
/* When deflate(Z_FULL_FLUSH) is called with small avail_out, it might
* close the block without resetting the compression state. Detect this
* situation and return that deflation is not done.
*/
if (flush == Z_FULL_FLUSH && strm->avail_out == 0)
return 0;
/* Return that deflation is not done if DFLTCC is used and either it
* buffered some data (Continuation Flag is set), or has not written EOBS
* yet (Block-Continuation Flag is set).
*/
return !PREFIX(dfltcc_can_deflate)(strm) || (!param->cf && !param->bcf);
}
int Z_INTERNAL PREFIX(dfltcc_can_set_reproducible)(PREFIX3(streamp) strm, int reproducible) {
deflate_state *state = (deflate_state *)strm->state;
return reproducible != state->reproducible && !dfltcc_was_deflate_used(strm);
}
/*
Preloading history.
*/
int Z_INTERNAL PREFIX(dfltcc_deflate_set_dictionary)(PREFIX3(streamp) strm,
const unsigned char *dictionary, uInt dict_length) {
deflate_state *state = (deflate_state *)strm->state;
struct dfltcc_param_v0 *param = &state->arch.common.param;
append_history(param, state->window, dictionary, dict_length);
state->strstart = 1; /* Add FDICT to zlib header */
state->block_start = state->strstart; /* Make deflate_stored happy */
return Z_OK;
}
int Z_INTERNAL PREFIX(dfltcc_deflate_get_dictionary)(PREFIX3(streamp) strm, unsigned char *dictionary, uInt *dict_length) {
deflate_state *state = (deflate_state *)strm->state;
struct dfltcc_param_v0 *param = &state->arch.common.param;
if (dictionary)
get_history(param, state->window, dictionary);
if (dict_length)
*dict_length = param->hl;
return Z_OK;
}
#endif

View file

@ -1,58 +0,0 @@
#ifndef DFLTCC_DEFLATE_H
#define DFLTCC_DEFLATE_H
#include "deflate.h"
#include "dfltcc_common.h"
void Z_INTERNAL PREFIX(dfltcc_reset_deflate_state)(PREFIX3(streamp));
int Z_INTERNAL PREFIX(dfltcc_can_deflate)(PREFIX3(streamp) strm);
int Z_INTERNAL PREFIX(dfltcc_deflate)(PREFIX3(streamp) strm, int flush, block_state *result);
int Z_INTERNAL PREFIX(dfltcc_deflate_params)(PREFIX3(streamp) strm, int level, int strategy, int *flush);
int Z_INTERNAL PREFIX(dfltcc_deflate_done)(PREFIX3(streamp) strm, int flush);
int Z_INTERNAL PREFIX(dfltcc_can_set_reproducible)(PREFIX3(streamp) strm, int reproducible);
int Z_INTERNAL PREFIX(dfltcc_deflate_set_dictionary)(PREFIX3(streamp) strm,
const unsigned char *dictionary, uInt dict_length);
int Z_INTERNAL PREFIX(dfltcc_deflate_get_dictionary)(PREFIX3(streamp) strm, unsigned char *dictionary, uInt* dict_length);
#define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) \
do { \
if (PREFIX(dfltcc_can_deflate)((strm))) \
return PREFIX(dfltcc_deflate_set_dictionary)((strm), (dict), (dict_len)); \
} while (0)
#define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) \
do { \
if (PREFIX(dfltcc_can_deflate)((strm))) \
return PREFIX(dfltcc_deflate_get_dictionary)((strm), (dict), (dict_len)); \
} while (0)
#define DEFLATE_RESET_KEEP_HOOK PREFIX(dfltcc_reset_deflate_state)
#define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) \
do { \
int err; \
\
err = PREFIX(dfltcc_deflate_params)((strm), (level), (strategy), (hook_flush)); \
if (err == Z_STREAM_ERROR) \
return err; \
} while (0)
#define DEFLATE_DONE PREFIX(dfltcc_deflate_done)
#define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, source_len) \
do { \
if (deflateStateCheck((strm)) || PREFIX(dfltcc_can_deflate)((strm))) \
(complen) = DEFLATE_BOUND_COMPLEN(source_len); \
} while (0)
#define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) (PREFIX(dfltcc_can_deflate)((strm)))
#define DEFLATE_HOOK PREFIX(dfltcc_deflate)
#define DEFLATE_NEED_CHECKSUM(strm) (!PREFIX(dfltcc_can_deflate)((strm)))
#define DEFLATE_CAN_SET_REPRODUCIBLE PREFIX(dfltcc_can_set_reproducible)
#define DEFLATE_ADJUST_WINDOW_SIZE(n) MAX(n, HB_SIZE)
#endif

View file

@ -1,274 +0,0 @@
#include "zbuild.h"
#include "zsanitizer.h"
#include <stdio.h>
#ifdef HAVE_SYS_SDT_H
#include <sys/sdt.h>
#endif
/*
Tuning parameters.
*/
#ifndef DFLTCC_LEVEL_MASK
#define DFLTCC_LEVEL_MASK 0x2
#endif
#ifndef DFLTCC_BLOCK_SIZE
#define DFLTCC_BLOCK_SIZE 1048576
#endif
#ifndef DFLTCC_FIRST_FHT_BLOCK_SIZE
#define DFLTCC_FIRST_FHT_BLOCK_SIZE 4096
#endif
#ifndef DFLTCC_DHT_MIN_SAMPLE_SIZE
#define DFLTCC_DHT_MIN_SAMPLE_SIZE 4096
#endif
#ifndef DFLTCC_RIBM
#define DFLTCC_RIBM 0
#endif
#define static_assert(c, msg) __attribute__((unused)) static char static_assert_failed_ ## msg[c ? 1 : -1]
#define DFLTCC_SIZEOF_QAF 32
static_assert(sizeof(struct dfltcc_qaf_param) == DFLTCC_SIZEOF_QAF, qaf);
static inline int is_bit_set(const char *bits, int n) {
return bits[n / 8] & (1 << (7 - (n % 8)));
}
static inline void clear_bit(char *bits, int n) {
bits[n / 8] &= ~(1 << (7 - (n % 8)));
}
#define DFLTCC_FACILITY 151
static inline int is_dfltcc_enabled(void) {
uint64_t facilities[(DFLTCC_FACILITY / 64) + 1];
Z_REGISTER uint8_t r0 __asm__("r0");
memset(facilities, 0, sizeof(facilities));
r0 = sizeof(facilities) / sizeof(facilities[0]) - 1;
/* STFLE is supported since z9-109 and only in z/Architecture mode. When
* compiling with -m31, gcc defaults to ESA mode, however, since the kernel
* is 64-bit, it's always z/Architecture mode at runtime.
*/
__asm__ volatile(
#ifndef __clang__
".machinemode push\n"
".machinemode zarch\n"
#endif
"stfle %[facilities]\n"
#ifndef __clang__
".machinemode pop\n"
#endif
: [facilities] "=Q" (facilities), [r0] "+r" (r0) :: "cc");
return is_bit_set((const char *)facilities, DFLTCC_FACILITY);
}
#define DFLTCC_FMT0 0
#define CVT_CRC32 0
#define CVT_ADLER32 1
#define HTT_FIXED 0
#define HTT_DYNAMIC 1
#define DFLTCC_SIZEOF_GDHT_V0 384
#define DFLTCC_SIZEOF_CMPR_XPND_V0 1536
static_assert(offsetof(struct dfltcc_param_v0, csb) == DFLTCC_SIZEOF_GDHT_V0, gdht_v0);
static_assert(sizeof(struct dfltcc_param_v0) == DFLTCC_SIZEOF_CMPR_XPND_V0, cmpr_xpnd_v0);
static inline z_const char *oesc_msg(char *buf, int oesc) {
if (oesc == 0x00)
return NULL; /* Successful completion */
else {
sprintf(buf, "Operation-Ending-Supplemental Code is 0x%.2X", oesc);
return buf;
}
}
/*
C wrapper for the DEFLATE CONVERSION CALL instruction.
*/
typedef enum {
DFLTCC_CC_OK = 0,
DFLTCC_CC_OP1_TOO_SHORT = 1,
DFLTCC_CC_OP2_TOO_SHORT = 2,
DFLTCC_CC_OP2_CORRUPT = 2,
DFLTCC_CC_AGAIN = 3,
} dfltcc_cc;
#define DFLTCC_QAF 0
#define DFLTCC_GDHT 1
#define DFLTCC_CMPR 2
#define DFLTCC_XPND 4
#define HBT_CIRCULAR (1 << 7)
#define DFLTCC_FN_MASK ((1 << 7) - 1)
/* Return lengths of high (starting at param->ho) and low (starting at 0) fragments of the circular history buffer. */
static inline void get_history_lengths(struct dfltcc_param_v0 *param, size_t *hl_high, size_t *hl_low) {
*hl_high = MIN(param->hl, HB_SIZE - param->ho);
*hl_low = param->hl - *hl_high;
}
/* Notify instrumentation about an upcoming read/write access to the circular history buffer. */
static inline void instrument_read_write_hist(struct dfltcc_param_v0 *param, void *hist) {
size_t hl_high, hl_low;
get_history_lengths(param, &hl_high, &hl_low);
instrument_read_write(hist + param->ho, hl_high);
instrument_read_write(hist, hl_low);
}
/* Notify MSan about a completed write to the circular history buffer. */
static inline void msan_unpoison_hist(struct dfltcc_param_v0 *param, void *hist) {
size_t hl_high, hl_low;
get_history_lengths(param, &hl_high, &hl_low);
__msan_unpoison(hist + param->ho, hl_high);
__msan_unpoison(hist, hl_low);
}
static inline dfltcc_cc dfltcc(int fn, void *param,
unsigned char **op1, size_t *len1,
z_const unsigned char **op2, size_t *len2, void *hist) {
unsigned char *t2 = op1 ? *op1 : NULL;
unsigned char *orig_t2 = t2;
size_t t3 = len1 ? *len1 : 0;
z_const unsigned char *t4 = op2 ? *op2 : NULL;
size_t t5 = len2 ? *len2 : 0;
Z_REGISTER int r0 __asm__("r0");
Z_REGISTER void *r1 __asm__("r1");
Z_REGISTER unsigned char *r2 __asm__("r2");
Z_REGISTER size_t r3 __asm__("r3");
Z_REGISTER z_const unsigned char *r4 __asm__("r4");
Z_REGISTER size_t r5 __asm__("r5");
int cc;
/* Insert pre-instrumentation for DFLTCC. */
switch (fn & DFLTCC_FN_MASK) {
case DFLTCC_QAF:
instrument_write(param, DFLTCC_SIZEOF_QAF);
break;
case DFLTCC_GDHT:
instrument_read_write(param, DFLTCC_SIZEOF_GDHT_V0);
instrument_read(t4, t5);
break;
case DFLTCC_CMPR:
case DFLTCC_XPND:
instrument_read_write(param, DFLTCC_SIZEOF_CMPR_XPND_V0);
instrument_read(t4, t5);
instrument_write(t2, t3);
instrument_read_write_hist(param, hist);
break;
}
r0 = fn; r1 = param; r2 = t2; r3 = t3; r4 = t4; r5 = t5;
__asm__ volatile(
#ifdef HAVE_SYS_SDT_H
STAP_PROBE_ASM(zlib, dfltcc_entry, STAP_PROBE_ASM_TEMPLATE(5))
#endif
".insn rrf,0xb9390000,%[r2],%[r4],%[hist],0\n"
#ifdef HAVE_SYS_SDT_H
STAP_PROBE_ASM(zlib, dfltcc_exit, STAP_PROBE_ASM_TEMPLATE(5))
#endif
"ipm %[cc]\n"
: [r2] "+r" (r2)
, [r3] "+r" (r3)
, [r4] "+r" (r4)
, [r5] "+r" (r5)
, [cc] "=r" (cc)
: [r0] "r" (r0)
, [r1] "r" (r1)
, [hist] "r" (hist)
#ifdef HAVE_SYS_SDT_H
, STAP_PROBE_ASM_OPERANDS(5, r2, r3, r4, r5, hist)
#endif
: "cc", "memory");
t2 = r2; t3 = r3; t4 = r4; t5 = r5;
/* Insert post-instrumentation for DFLTCC. */
switch (fn & DFLTCC_FN_MASK) {
case DFLTCC_QAF:
__msan_unpoison(param, DFLTCC_SIZEOF_QAF);
break;
case DFLTCC_GDHT:
__msan_unpoison(param, DFLTCC_SIZEOF_GDHT_V0);
break;
case DFLTCC_CMPR:
__msan_unpoison(param, DFLTCC_SIZEOF_CMPR_XPND_V0);
__msan_unpoison(orig_t2, t2 - orig_t2 + (((struct dfltcc_param_v0 *)param)->sbb == 0 ? 0 : 1));
msan_unpoison_hist(param, hist);
break;
case DFLTCC_XPND:
__msan_unpoison(param, DFLTCC_SIZEOF_CMPR_XPND_V0);
__msan_unpoison(orig_t2, t2 - orig_t2);
msan_unpoison_hist(param, hist);
break;
}
if (op1)
*op1 = t2;
if (len1)
*len1 = t3;
if (op2)
*op2 = t4;
if (len2)
*len2 = t5;
return (cc >> 28) & 3;
}
static inline void dfltcc_reset_state(struct dfltcc_state *dfltcc_state) {
/* Initialize available functions */
if (is_dfltcc_enabled()) {
dfltcc(DFLTCC_QAF, &dfltcc_state->param, NULL, NULL, NULL, NULL, NULL);
memmove(&dfltcc_state->af, &dfltcc_state->param, sizeof(dfltcc_state->af));
} else
memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
/* Initialize parameter block */
memset(&dfltcc_state->param, 0, sizeof(dfltcc_state->param));
dfltcc_state->param.nt = 1;
dfltcc_state->param.ribm = DFLTCC_RIBM;
}
static inline void dfltcc_copy_state(void *dst, const void *src, uInt size, uInt extension_size) {
memcpy(dst, src, ALIGN_UP(size, 8) + extension_size);
}
static inline void append_history(struct dfltcc_param_v0 *param, unsigned char *history,
const unsigned char *buf, uInt count) {
size_t offset;
size_t n;
/* Do not use more than 32K */
if (count > HB_SIZE) {
buf += count - HB_SIZE;
count = HB_SIZE;
}
offset = (param->ho + param->hl) % HB_SIZE;
if (offset + count <= HB_SIZE)
/* Circular history buffer does not wrap - copy one chunk */
memcpy(history + offset, buf, count);
else {
/* Circular history buffer wraps - copy two chunks */
n = HB_SIZE - offset;
memcpy(history + offset, buf, n);
memcpy(history, buf + n, count - n);
}
n = param->hl + count;
if (n <= HB_SIZE)
/* All history fits into buffer - no need to discard anything */
param->hl = n;
else {
/* History does not fit into buffer - discard extra bytes */
param->ho = (param->ho + (n - HB_SIZE)) % HB_SIZE;
param->hl = HB_SIZE;
}
}
static inline void get_history(struct dfltcc_param_v0 *param, const unsigned char *history,
unsigned char *buf) {
size_t hl_high, hl_low;
get_history_lengths(param, &hl_high, &hl_low);
memcpy(buf, history + param->ho, hl_high);
memcpy(buf + hl_high, history, hl_low);
}

View file

@ -1,195 +0,0 @@
/* dfltcc_inflate.c - IBM Z DEFLATE CONVERSION CALL decompression support. */
/*
Use the following commands to build zlib-ng with DFLTCC decompression support:
$ ./configure --with-dfltcc-inflate
or
$ cmake -DWITH_DFLTCC_INFLATE=1 .
and then
$ make
*/
#ifdef S390_DFLTCC_INFLATE
#include "zbuild.h"
#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
#include "dfltcc_inflate.h"
#include "dfltcc_detail.h"
void Z_INTERNAL PREFIX(dfltcc_reset_inflate_state)(PREFIX3(streamp) strm) {
struct inflate_state *state = (struct inflate_state *)strm->state;
dfltcc_reset_state(&state->arch.common);
}
int Z_INTERNAL PREFIX(dfltcc_can_inflate)(PREFIX3(streamp) strm) {
struct inflate_state *state = (struct inflate_state *)strm->state;
struct dfltcc_state *dfltcc_state = &state->arch.common;
/* Unsupported hardware */
return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) && is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0);
}
static inline dfltcc_cc dfltcc_xpnd(PREFIX3(streamp) strm) {
struct inflate_state *state = (struct inflate_state *)strm->state;
struct dfltcc_param_v0 *param = &state->arch.common.param;
size_t avail_in = strm->avail_in;
size_t avail_out = strm->avail_out;
dfltcc_cc cc;
cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR,
param, &strm->next_out, &avail_out,
&strm->next_in, &avail_in, state->window);
strm->avail_in = avail_in;
strm->avail_out = avail_out;
return cc;
}
dfltcc_inflate_action Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, int flush, int *ret) {
struct inflate_state *state = (struct inflate_state *)strm->state;
struct dfltcc_state *dfltcc_state = &state->arch.common;
struct dfltcc_param_v0 *param = &dfltcc_state->param;
dfltcc_cc cc;
if (flush == Z_BLOCK || flush == Z_TREES) {
/* DFLTCC does not support stopping on block boundaries */
if (PREFIX(dfltcc_inflate_disable)(strm)) {
*ret = Z_STREAM_ERROR;
return DFLTCC_INFLATE_BREAK;
} else
return DFLTCC_INFLATE_SOFTWARE;
}
if (state->last) {
if (state->bits != 0) {
strm->next_in++;
strm->avail_in--;
state->bits = 0;
}
state->mode = CHECK;
return DFLTCC_INFLATE_CONTINUE;
}
if (strm->avail_in == 0 && !param->cf)
return DFLTCC_INFLATE_BREAK;
/* if window not in use yet, initialize */
if (state->wsize == 0)
state->wsize = 1U << state->wbits;
/* Translate stream to parameter block */
param->cvt = ((state->wrap & 4) && state->flags) ? CVT_CRC32 : CVT_ADLER32;
param->sbb = state->bits;
if (param->hl)
param->nt = 0; /* Honor history for the first block */
if (state->wrap & 4)
param->cv = state->flags ? ZSWAP32(state->check) : state->check;
/* Inflate */
do {
cc = dfltcc_xpnd(strm);
} while (cc == DFLTCC_CC_AGAIN);
/* Translate parameter block to stream */
strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
state->last = cc == DFLTCC_CC_OK;
state->bits = param->sbb;
if (state->wrap & 4)
strm->adler = state->check = state->flags ? ZSWAP32(param->cv) : param->cv;
if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) {
/* Report an error if stream is corrupted */
state->mode = BAD;
return DFLTCC_INFLATE_CONTINUE;
}
state->mode = TYPEDO;
/* Break if operands are exhausted, otherwise continue looping */
return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ?
DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE;
}
int Z_INTERNAL PREFIX(dfltcc_was_inflate_used)(PREFIX3(streamp) strm) {
struct inflate_state *state = (struct inflate_state *)strm->state;
return !state->arch.common.param.nt;
}
/*
Rotates a circular buffer.
The implementation is based on https://cplusplus.com/reference/algorithm/rotate/
*/
static void rotate(unsigned char *start, unsigned char *pivot, unsigned char *end) {
unsigned char *p = pivot;
unsigned char tmp;
while (p != start) {
tmp = *start;
*start = *p;
*p = tmp;
start++;
p++;
if (p == end)
p = pivot;
else if (start == pivot)
pivot = p;
}
}
int Z_INTERNAL PREFIX(dfltcc_inflate_disable)(PREFIX3(streamp) strm) {
struct inflate_state *state = (struct inflate_state *)strm->state;
struct dfltcc_state *dfltcc_state = &state->arch.common;
struct dfltcc_param_v0 *param = &dfltcc_state->param;
if (!PREFIX(dfltcc_can_inflate)(strm))
return 0;
if (PREFIX(dfltcc_was_inflate_used)(strm))
/* DFLTCC has already decompressed some data. Since there is not
* enough information to resume decompression in software, the call
* must fail.
*/
return 1;
/* DFLTCC was not used yet - decompress in software */
memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
/* Convert the window from the hardware to the software format */
rotate(state->window, state->window + param->ho, state->window + HB_SIZE);
state->whave = state->wnext = MIN(param->hl, state->wsize);
return 0;
}
/*
Preloading history.
*/
int Z_INTERNAL PREFIX(dfltcc_inflate_set_dictionary)(PREFIX3(streamp) strm,
const unsigned char *dictionary, uInt dict_length) {
struct inflate_state *state = (struct inflate_state *)strm->state;
struct dfltcc_param_v0 *param = &state->arch.common.param;
/* if window not in use yet, initialize */
if (state->wsize == 0)
state->wsize = 1U << state->wbits;
append_history(param, state->window, dictionary, dict_length);
state->havedict = 1;
return Z_OK;
}
int Z_INTERNAL PREFIX(dfltcc_inflate_get_dictionary)(PREFIX3(streamp) strm,
unsigned char *dictionary, uInt *dict_length) {
struct inflate_state *state = (struct inflate_state *)strm->state;
struct dfltcc_param_v0 *param = &state->arch.common.param;
if (dictionary && state->window)
get_history(param, state->window, dictionary);
if (dict_length)
*dict_length = param->hl;
return Z_OK;
}
#endif

View file

@ -1,67 +0,0 @@
#ifndef DFLTCC_INFLATE_H
#define DFLTCC_INFLATE_H
#include "dfltcc_common.h"
void Z_INTERNAL PREFIX(dfltcc_reset_inflate_state)(PREFIX3(streamp) strm);
int Z_INTERNAL PREFIX(dfltcc_can_inflate)(PREFIX3(streamp) strm);
typedef enum {
DFLTCC_INFLATE_CONTINUE,
DFLTCC_INFLATE_BREAK,
DFLTCC_INFLATE_SOFTWARE,
} dfltcc_inflate_action;
dfltcc_inflate_action Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, int flush, int *ret);
int Z_INTERNAL PREFIX(dfltcc_was_inflate_used)(PREFIX3(streamp) strm);
int Z_INTERNAL PREFIX(dfltcc_inflate_disable)(PREFIX3(streamp) strm);
int Z_INTERNAL PREFIX(dfltcc_inflate_set_dictionary)(PREFIX3(streamp) strm,
const unsigned char *dictionary, uInt dict_length);
int Z_INTERNAL PREFIX(dfltcc_inflate_get_dictionary)(PREFIX3(streamp) strm,
unsigned char *dictionary, uInt* dict_length);
#define INFLATE_RESET_KEEP_HOOK PREFIX(dfltcc_reset_inflate_state)
#define INFLATE_PRIME_HOOK(strm, bits, value) \
do { if (PREFIX(dfltcc_inflate_disable)((strm))) return Z_STREAM_ERROR; } while (0)
#define INFLATE_TYPEDO_HOOK(strm, flush) \
if (PREFIX(dfltcc_can_inflate)((strm))) { \
dfltcc_inflate_action action; \
\
RESTORE(); \
action = PREFIX(dfltcc_inflate)((strm), (flush), &ret); \
LOAD(); \
if (action == DFLTCC_INFLATE_CONTINUE) \
break; \
else if (action == DFLTCC_INFLATE_BREAK) \
goto inf_leave; \
}
#define INFLATE_NEED_CHECKSUM(strm) (!PREFIX(dfltcc_can_inflate)((strm)))
#define INFLATE_NEED_UPDATEWINDOW(strm) (!PREFIX(dfltcc_can_inflate)((strm)))
#define INFLATE_MARK_HOOK(strm) \
do { \
if (PREFIX(dfltcc_was_inflate_used)((strm))) return -(1L << 16); \
} while (0)
#define INFLATE_SYNC_POINT_HOOK(strm) \
do { \
if (PREFIX(dfltcc_was_inflate_used)((strm))) return Z_STREAM_ERROR; \
} while (0)
#define INFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) \
do { \
if (PREFIX(dfltcc_can_inflate)((strm))) \
return PREFIX(dfltcc_inflate_set_dictionary)((strm), (dict), (dict_len)); \
} while (0)
#define INFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) \
do { \
if (PREFIX(dfltcc_can_inflate)((strm))) \
return PREFIX(dfltcc_inflate_get_dictionary)((strm), (dict), (dict_len)); \
} while (0)
#define INFLATE_ADJUST_WINDOW_SIZE(n) MAX(n, HB_SIZE)
#endif

View file

@ -1,18 +0,0 @@
#ifdef S390_FEATURES
#include "zbuild.h"
#include "s390_features.h"
#ifdef HAVE_SYS_AUXV_H
# include <sys/auxv.h>
#endif
#ifndef HWCAP_S390_VXRS
#define HWCAP_S390_VXRS (1 << 11)
#endif
void Z_INTERNAL s390_check_features(struct s390_cpu_features *features) {
features->has_vx = getauxval(AT_HWCAP) & HWCAP_S390_VXRS;
}
#endif

View file

@ -1,14 +0,0 @@
/* s390_features.h -- check for s390 features.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef S390_FEATURES_H_
#define S390_FEATURES_H_
struct s390_cpu_features {
int has_vx;
};
void Z_INTERNAL s390_check_features(struct s390_cpu_features *features);
#endif

View file

@ -1,44 +0,0 @@
/* s390_functions.h -- s390 implementations for arch-specific functions.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef S390_FUNCTIONS_H_
#define S390_FUNCTIONS_H_
#include "s390_natives.h"
#define ADLER32_FALLBACK
#define CHUNKSET_FALLBACK
#define COMPARE256_FALLBACK
#define CRC32_BRAID_FALLBACK /* used by crc32_s390_vx */
#ifndef S390_VX_NATIVE
# define SLIDE_HASH_FALLBACK
#endif
#ifdef S390_VX
uint32_t crc32_s390_vx(uint32_t crc, const uint8_t *buf, size_t len);
uint32_t crc32_copy_s390_vx(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len);
void slide_hash_vx(deflate_state *s);
#ifdef __clang__
# if ((__clang_major__ == 18) || (__clang_major__ == 19 && (__clang_minor__ < 1 || (__clang_minor__ == 1 && __clang_patchlevel__ < 2))))
# error CRC32-VX optimizations are broken due to compiler bug in Clang versions: 18.0.0 <= clang_version < 19.1.2. \
Either disable the zlib-ng S390 VX optimizations, or switch to another compiler/compiler version.
# endif
#endif
#endif
#ifdef DISABLE_RUNTIME_CPU_DETECTION
# ifdef S390_VX_NATIVE
# undef native_crc32
# define native_crc32 crc32_s390_vx
# undef native_crc32_copy
# define native_crc32_copy crc32_copy_s390_vx
# undef native_slide_hash
# define native_slide_hash slide_hash_vx
# endif
#endif
#endif

View file

@ -1,14 +0,0 @@
/* s390_natives.h -- s390 compile-time feature detection macros.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef S390_NATIVES_H_
#define S390_NATIVES_H_
#if defined(__zarch__) && __ARCH__ >= 11 && defined(__VX__)
# ifdef S390_VX
# define S390_VX_NATIVE
# endif
#endif
#endif /* S390_NATIVES_H_ */

View file

@ -1,62 +0,0 @@
#!/bin/bash
#
# Ephemeral runner startup script.
#
# Expects the following environment variables:
#
# - REPO=<owner>
# - PAT_TOKEN=<github_pat_***>
#
set -e -u
# Validate required environment variables
if [ -z "${REPO:-}" ] || [ -z "${PAT_TOKEN:-}" ]; then
echo "Error: REPO and/or PAT_TOKEN environment variables not found"
exit 1
fi
# Check the cached registration token.
TOKEN_FILE=registration-token.json
if [ -f $TOKEN_FILE ]; then
set +e
EXPIRES=$(jq --raw-output .expires_at "$TOKEN_FILE" 2>/dev/null)
STATUS=$?
set -e
else
STATUS=1
EXPIRES=""
fi
if [[ $STATUS -ne 0 || -z "$EXPIRES" || "$EXPIRES" == "null" || $(date +%s) -ge $(date -d "$EXPIRES" +%s) ]]; then
# Refresh the cached registration token.
curl \
-sS \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $PAT_TOKEN" \
"https://api.github.com/repos/$REPO/actions/runners/registration-token" \
-o "$TOKEN_FILE"
fi
REG_TOKEN=$(jq --raw-output .token "$TOKEN_FILE")
if [ $REG_TOKEN = "null" ]; then
echo "Failed to get registration token"
exit 1
fi
# (Re-)register the runner.
./config.sh remove --token "$REG_TOKEN" || true
set -x
./config.sh \
--url "https://github.com/$REPO" \
--token "$REG_TOKEN" \
--unattended \
--disableupdate \
--replace \
--labels z15 \
--ephemeral
# Run one job.
./run.sh

View file

@ -1,52 +0,0 @@
#!/usr/bin/bash
set -ex
TMPDIR="$(mktemp -d)"
if [ -f actions-runner.Dockerfile ]; then
MODE=1
cp actions-runner.Dockerfile actions-runner entrypoint $TMPDIR
cd $TMPDIR
else
MODE=2
cd $TMPDIR
wget https://raw.githubusercontent.com/zlib-ng/zlib-ng/refs/heads/develop/arch/s390/self-hosted-builder/actions-runner.Dockerfile
wget https://raw.githubusercontent.com/zlib-ng/zlib-ng/refs/heads/develop/arch/s390/self-hosted-builder/actions-runner
wget https://raw.githubusercontent.com/zlib-ng/zlib-ng/refs/heads/develop/arch/s390/self-hosted-builder/entrypoint
fi
# Stop service
systemctl stop actions-runner || true
# Delete old container
podman container rm gaplib-actions-runner || true
# Delete old image
podman image rm localhost/zlib-ng/actions-runner || true
# Prune all unused podman data
podman system prune -f || true
# Build new image
podman build --squash -f actions-runner.Dockerfile --tag zlib-ng/actions-runner . 2>&1 | tee /var/log/actions-runner-build.log
# Create new container
podman create --replace --name=gaplib-actions-runner --env-file=/etc/actions-runner --init \
zlib-ng/actions-runner 2>&1 | tee -a /var/log/actions-runner-build.log
# Start service
systemctl start actions-runner || true
# Cleanup
podman image prune -af || true
# Clean up tempfile
if [ "$MODE" == "2" ] ; then
cd $TMPDIR
rm actions-runner.Dockerfile
rm actions-runner
rm entrypoint
cd ..
rmdir $TMPDIR
echo "Deleted tempfiles."
fi

View file

@ -1,47 +0,0 @@
# Self-Hosted IBM Z Github Actions Runner.
FROM almalinux:10
RUN dnf update -y -q && \
dnf install -y -q --enablerepo=crb wget git which sudo jq sed \
cmake make automake autoconf m4 libtool ninja-build \
python3-pip python3-devel python3-lxml \
gcc gcc-c++ clang llvm-toolset glibc-all-langpacks langpacks-en \
glibc-static libstdc++-static libstdc++-devel libxslt-devel libxml2-devel
RUN dnf install -y -q dotnet-sdk-8.0 && \
echo "Using SDK - `dotnet --version`"
RUN cd /tmp && \
git clone -q https://github.com/actions/runner && \
cd runner && \
git checkout $(git tag --sort=-v:refname | grep '^v[0-9]' | head -n1) && \
git log -n 1 && \
wget https://raw.githubusercontent.com/IBM/action-runner-image-pz/refs/heads/main/patches/runner-sdk8-s390x.patch -O runner-sdk8-s390x.patch && \
git apply --whitespace=nowarn runner-sdk8-s390x.patch && \
sed -i'' -e /version/s/8......\"$/$8.0.100\"/ src/global.json
RUN cd /tmp/runner/src && \
./dev.sh layout && \
./dev.sh package && \
rm -rf /root/.dotnet /root/.nuget
RUN useradd -c "Action Runner" -m actions-runner && \
usermod -L actions-runner
RUN tar -xf /tmp/runner/_package/*.tar.gz -C /home/actions-runner && \
chown -R actions-runner:actions-runner /home/actions-runner
# Cleanup
RUN rm -rf /tmp/runner /var/cache/dnf/* /tmp/runner.patch /tmp/global.json && \
dnf clean all
USER actions-runner
# Scripts.
COPY --chmod=555 entrypoint /usr/bin/
COPY --chmod=555 actions-runner /usr/bin/
WORKDIR /home/actions-runner
ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["/usr/bin/actions-runner"]

View file

@ -1,18 +0,0 @@
[Unit]
Description=Podman container: Gaplib Github Actions Runner
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=1
RequiresMountsFor=/run/user/1001/containers
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
TimeoutStopSec=61
ExecStart=/usr/bin/podman start gaplib-actions-runner
ExecStop=/usr/bin/podman stop -t 30 gaplib-actions-runner
ExecStopPost=/usr/bin/podman stop -t 10 gaplib-actions-runner
Type=forking
[Install]
WantedBy=default.target

View file

@ -1,30 +0,0 @@
#!/bin/bash
#
# Container entrypoint that waits for all spawned processes.
#
set -e -u
# Create a FIFO and start reading from its read end.
tempdir=$(mktemp -d "/tmp/done.XXXXXXXXXX")
trap 'rm -r "$tempdir"' EXIT
done="$tempdir/pipe"
mkfifo "$done"
cat "$done" & waiter=$!
# Start the workload. Its descendants will inherit the FIFO's write end.
status=0
if [ "$#" -eq 0 ]; then
bash 9>"$done" || status=$?
else
"$@" 9>"$done" || status=$?
fi
# When the workload and all of its descendants exit, the FIFO's write end will
# be closed and `cat "$done"` will exit. Wait until it happens. This is needed
# in order to handle SelfUpdater, which the workload may start in background
# before exiting.
wait "$waiter"
exit "$status"

View file

@ -1,35 +0,0 @@
/* slide_hash_vx.c - VX version of slide_hash for S390 processors
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef S390_VX
#include "zbuild.h"
#include "deflate.h"
#include "vx_intrins.h"
static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize) {
const uv8hi vmx_wsize = vec_splats(wsize);
Pos *p = table;
do {
uv8hi value, result;
value = vec_xl(0, p);
result = vec_sub(value, vec_min(value, vmx_wsize));
vec_xst(result, 0, p);
p += 8;
entries -= 8;
} while (entries > 0);
}
Z_INTERNAL void slide_hash_vx(deflate_state *s) {
Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t");
uint16_t wsize = (uint16_t)s->w_size;
slide_hash_chain(s->head, HASH_SIZE, wsize);
slide_hash_chain(s->prev, wsize, wsize);
}
#endif

View file

@ -1,21 +0,0 @@
#ifndef S390_VX_INTRINS_H
#define S390_VX_INTRINS_H
#include <vecintrin.h>
typedef unsigned char uv16qi __attribute__((vector_size(16)));
typedef unsigned short uv8hi __attribute__((vector_size(16)));
typedef unsigned int uv4si __attribute__((vector_size(16)));
typedef unsigned long long uv2di __attribute__((vector_size(16)));
#ifndef vec_sub
#define vec_sub(a, b) ((a) - (b))
#endif
#ifndef vec_subs
static inline uv8hi vec_subs_u16(uv8hi a, uv8hi b) {
return a - vec_min(a, b);
}
#define vec_subs(a, b) vec_subs_u16((a), (b))
#endif
#endif

View file

@ -1,26 +0,0 @@
/* chunk_128bit_perm_idx_lut.h - shared SSSE3/NEON/LSX permutation idx lut for use with chunkmemset family of functions.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef CHUNK_128BIT_PERM_IDX_LUT_H_
#define CHUNK_128BIT_PERM_IDX_LUT_H_
#include "chunk_permute_table.h"
static const lut_rem_pair perm_idx_lut[13] = {
{0, 1}, /* 3 */
{0, 0}, /* don't care */
{1 * 32, 1}, /* 5 */
{2 * 32, 4}, /* 6 */
{3 * 32, 2}, /* 7 */
{0 * 32, 0}, /* don't care */
{4 * 32, 7}, /* 9 */
{5 * 32, 6}, /* 10 */
{6 * 32, 5}, /* 11 */
{7 * 32, 4}, /* 12 */
{8 * 32, 3}, /* 13 */
{9 * 32, 2}, /* 14 */
{10 * 32, 1},/* 15 */
};
#endif

View file

@ -1,47 +0,0 @@
/* chunk_256bit_perm_idx_lut.h - shared AVX512/AVX2/LASX permutation idx lut for use with chunkmemset family of functions.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef CHUNK_256BIT_PERM_IDX_LUT_H_
#define CHUNK_256BIT_PERM_IDX_LUT_H_
#include "chunk_permute_table.h"
/* Populate don't cares so that this is a direct lookup (with some indirection into the permute table), because dist can
* never be 0 - 2, we'll start with an offset, subtracting 3 from the input */
static const lut_rem_pair perm_idx_lut[29] = {
{ 0, 2}, /* 3 */
{ 0, 0}, /* don't care */
{ 1 * 32, 2}, /* 5 */
{ 2 * 32, 2}, /* 6 */
{ 3 * 32, 4}, /* 7 */
{ 0 * 32, 0}, /* don't care */
{ 4 * 32, 5}, /* 9 */
{ 5 * 32, 22}, /* 10 */
{ 6 * 32, 21}, /* 11 */
{ 7 * 32, 20}, /* 12 */
{ 8 * 32, 6}, /* 13 */
{ 9 * 32, 4}, /* 14 */
{10 * 32, 2}, /* 15 */
{ 0 * 32, 0}, /* don't care */
{11 * 32, 15}, /* 17 */
{11 * 32 + 16, 14}, /* 18 */
{11 * 32 + 16 * 2, 13}, /* 19 */
{11 * 32 + 16 * 3, 12}, /* 20 */
{11 * 32 + 16 * 4, 11}, /* 21 */
{11 * 32 + 16 * 5, 10}, /* 22 */
{11 * 32 + 16 * 6, 9}, /* 23 */
{11 * 32 + 16 * 7, 8}, /* 24 */
{11 * 32 + 16 * 8, 7}, /* 25 */
{11 * 32 + 16 * 9, 6}, /* 26 */
{11 * 32 + 16 * 10, 5}, /* 27 */
{11 * 32 + 16 * 11, 4}, /* 28 */
{11 * 32 + 16 * 12, 3}, /* 29 */
{11 * 32 + 16 * 13, 2}, /* 30 */
{11 * 32 + 16 * 14, 1} /* 31 */
};
static const uint16_t half_rem_vals[13] = {
1, 0, 1, 4, 2, 0, 7, 6, 5, 4, 3, 2, 1
};
#endif

View file

@ -1,53 +0,0 @@
/* chunk_permute_table.h - shared AVX/SSSE3/NEON/LSX/LASX permutation table for use with chunkmemset family of functions.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifndef CHUNK_PERMUTE_TABLE_H_
#define CHUNK_PERMUTE_TABLE_H_
#include "zbuild.h"
/* Need entries for all numbers not an even modulus for 1, 2, 4, 8, 16 & 32 */
static const ALIGNED_(32) uint8_t permute_table[26*32] = {
0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, /* dist 3 */
0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, /* dist 5 */
0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, /* dist 6 */
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, /* dist 7 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, /* dist 9 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, /* dist 10 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* dist 11 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, /* dist 12 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, /* dist 13 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1, 2, 3, /* dist 14 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 1, /* dist 15 */
/* Beyond dists of 15 means we have to permute from a vector > len(m128i). Because AVX couldn't permute
* beyond 128 bit lanes until AVX512 for sub 4-byte sequences, we have to do some math here for an eventual
* blend with a comparison. That means we need to wrap the indices with yet another derived table. For simplicity,
* we'll use absolute indexing here to derive a blend vector. This is actually a lot simpler with ARM's TBL, but,
* this is what we're dealt.
*/
16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* dist 17 */
16, 17, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, /* dist 18 */
16, 17, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, /* dist 19 */
16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* dist 20 */
16, 17, 18, 19, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, /* dist 21 */
16, 17, 18, 19, 20, 21, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* dist 22 */
16, 17, 18, 19, 20, 21, 22, 0, 1, 2, 3, 4, 5, 6, 7, 8, /* dist 23 */
16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5, 6, 7, /* dist 24 */
16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 1, 2, 3, 4, 5, 6, /* dist 25 */
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 1, 2, 3, 4, 5, /* dist 26 */
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 1, 2, 3, 4, /* dist 27 */
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0, 1, 2, 3, /* dist 28 */
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 1, 2, /* dist 29 */
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 1, /* dist 30 */
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 0, /* dist 31 */
};
typedef struct lut_rem_pair_s {
uint16_t idx;
uint16_t remval;
} lut_rem_pair;
#endif

View file

@ -1,98 +0,0 @@
/* crc32_hw_common_tpl.h -- Private shared inline CRC32 functions for CPU with native crc instructions
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zbuild.h"
Z_FORCEINLINE static Z_TARGET_CRC uint32_t crc32_hw_align(uint32_t crc, uint8_t **dst, const uint8_t **buf,
size_t *len, uintptr_t align_diff, const int COPY) {
if (*len && (align_diff & 1)) {
uint8_t val = **buf;
if (COPY) {
**dst = val;
*dst += 1;
}
crc = CRC32B(crc, val);
*buf += 1;
*len -= 1;
}
if (*len >= 2 && (align_diff & 2)) {
uint16_t val = *((uint16_t*)*buf);
if (COPY) {
memcpy(*dst, &val, 2);
*dst += 2;
}
crc = CRC32H(crc, val);
*buf += 2;
*len -= 2;
}
if (*len >= 4 && (align_diff & 4)) {
uint32_t val = *((uint32_t*)*buf);
if (COPY) {
memcpy(*dst, &val, 4);
*dst += 4;
}
crc = CRC32W(crc, val);
*buf += 4;
*len -= 4;
}
if (*len >= 8 && (align_diff & 8)) {
uint64_t val = *((uint64_t*)*buf);
if (COPY) {
memcpy(*dst, &val, 8);
*dst += 8;
}
crc = CRC32D(crc, val);
*buf += 8;
*len -= 8;
}
return crc;
}
Z_FORCEINLINE static Z_TARGET_CRC uint32_t crc32_hw_tail(uint32_t crc, uint8_t *dst, const uint8_t *buf,
size_t len, const int COPY) {
while (len >= 8) {
uint64_t val = *((uint64_t*)buf);
if (COPY) {
memcpy(dst, &val, 8);
dst += 8;
}
crc = CRC32D(crc, val);
buf += 8;
len -= 8;
}
if (len & 4) {
uint32_t val = *((uint32_t*)buf);
if (COPY) {
memcpy(dst, &val, 4);
dst += 4;
}
crc = CRC32W(crc, val);
buf += 4;
}
if (len & 2) {
uint16_t val = *((uint16_t*)buf);
if (COPY) {
memcpy(dst, &val, 2);
dst += 2;
}
crc = CRC32H(crc, val);
buf += 2;
}
if (len & 1) {
uint8_t val = *buf;
if (COPY)
*dst = val;
crc = CRC32B(crc, val);
}
return ~crc;
}

Some files were not shown because too many files have changed in this diff Show more