]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
fix bug #263: hoist invariant loads
authorSebastian Pop <s.pop@samsung.com>
Thu, 20 Dec 2018 20:08:16 +0000 (14:08 -0600)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Tue, 15 Jan 2019 11:14:31 +0000 (12:14 +0100)
This patch speeds up longest_match when compiled with clang for x86_64 to match
the performance of zlib.org. The performance of zlib-ng does not change much
when compiled with gcc for x86_64, or when zlib-ng is cross compiled by gcc or
llvm for aarch64.

Performance analysis for this patch:
https://gist.github.com/sebpop/7cdc5b2abd3297c5fcd2a8315bd9a209

match.c

diff --git a/match.c b/match.c
index fd55c3e1300123370333a8595b17d79335b6b5fe..207aedf7be8ab5dc099d6d962b90b56d2e264053 100644 (file)
--- a/match.c
+++ b/match.c
@@ -347,21 +347,23 @@ ZLIB_INTERNAL unsigned longest_match(deflate_state *const s, IPos cur_match) {
  */
 
 ZLIB_INTERNAL unsigned longest_match(deflate_state *const s, IPos cur_match) {
+    unsigned int strstart = s->strstart;
     unsigned chain_length = s->max_chain_length;/* max hash chain length */
-    register unsigned char *scan = s->window + s->strstart; /* current string */
+    unsigned char *window = s->window;
+    register unsigned char *scan = window + strstart; /* current string */
     register unsigned char *match;                       /* matched string */
     register unsigned int len;                  /* length of current match */
     unsigned int best_len = s->prev_length;     /* best match length so far */
     unsigned int nice_match = s->nice_match;    /* stop if match long enough */
-    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
-        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    IPos limit = strstart > (IPos)MAX_DIST(s) ?
+        strstart - (IPos)MAX_DIST(s) : NIL;
     /* Stop when cur_match becomes <= limit. To simplify the code,
      * we prevent matches with the string of window index 0.
      */
     Pos *prev = s->prev;
     unsigned int wmask = s->w_mask;
 
-    register unsigned char *strend = s->window + s->strstart + MAX_MATCH;
+    register unsigned char *strend = window + strstart + MAX_MATCH;
 
     uint16_t scan_start, scan_end;
 
@@ -382,10 +384,10 @@ ZLIB_INTERNAL unsigned longest_match(deflate_state *const s, IPos cur_match) {
      */
     if ((unsigned int)nice_match > s->lookahead) nice_match = s->lookahead;
 
-    Assert((unsigned long)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+    Assert((unsigned long)strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
 
     do {
-        if (cur_match >= s->strstart) {
+        if (cur_match >= strstart) {
           break;
         }
 
@@ -397,10 +399,9 @@ ZLIB_INTERNAL unsigned longest_match(deflate_state *const s, IPos cur_match) {
          * However the length of the match is limited to the lookahead, so
          * the output of deflate is not affected by the uninitialized values.
          */
-        unsigned char *win = s->window;
         int cont = 1;
         do {
-            match = win + cur_match;
+            match = window + cur_match;
             if (likely(memcmp(match+best_len-1, &scan_end, sizeof(scan_end)) != 0)) {
                 if ((cur_match = prev[cur_match & wmask]) > limit
                     && --chain_length != 0) {
@@ -450,7 +451,7 @@ ZLIB_INTERNAL unsigned longest_match(deflate_state *const s, IPos cur_match) {
         if (scan > strend)
             scan = strend;
 
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        Assert(scan <= window + (unsigned)(s->window_size-1), "wild scan");
 
         len = MAX_MATCH - (int)(strend - scan);
         scan = strend - MAX_MATCH;