Coverage Report

Created: 2026-09-13 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zlib-ng/match_tpl.h
Line
Count
Source
1
/* match_tpl.h -- find longest match template for compare256 variants
2
 *
3
 * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
4
 * For conditions of distribution and use, see copyright notice in zlib.h
5
 *
6
 * Portions copyright (C) 2014-2021 Konstantin Nosov
7
 *  Fast-zlib optimized longest_match
8
 *  https://github.com/gildor2/fast_zlib
9
 */
10
11
#include "insert_string_p.h"
12
13
359k
#define EARLY_EXIT_TRIGGER_LEVEL 5
14
15
#define GOTO_NEXT_CHAIN \
16
19.8M
    if (--chain_length && (cur_match = prev[cur_match & wmask]) > limit) \
17
19.4M
        continue; \
18
327k
    return best_len;
19
20
/* Set match_start to the longest match starting at the given string and
21
 * return its length. Matches shorter or equal to prev_length are discarded,
22
 * in which case the result is equal to prev_length and match_start is garbage.
23
 *
24
 * IN assertions: cur_match is the head of the hash chain for the current
25
 * string (strstart) and its distance is <= MAX_DIST, and prev_length >=1
26
 * OUT assertion: the match length is not greater than s->lookahead
27
 */
28
917k
Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, uint32_t cur_match) {
29
917k
    const unsigned wmask = W_MASK(s);
30
917k
    unsigned int strstart = s->strstart;
31
917k
    const unsigned char *window = s->window;
32
917k
    const Pos *prev = s->prev;
33
#ifdef LONGEST_MATCH_SLOW
34
    const Pos *head = s->head;
35
#endif
36
917k
    const unsigned char *scan;
37
917k
    const unsigned char *mbase_start = window;
38
917k
    const unsigned char *mbase_end;
39
917k
    uint32_t limit;
40
#ifdef LONGEST_MATCH_SLOW
41
    uint32_t limit_base;
42
#endif
43
#ifndef LONGEST_MATCH_SLOW
44
    int32_t early_exit;
45
#endif
46
917k
    uint32_t chain_length = s->max_chain_length;
47
917k
    uint32_t nice_match = (uint32_t)s->nice_match;
48
917k
    uint32_t best_len, offset;
49
917k
    uint32_t lookahead = s->lookahead;
50
917k
    uint32_t match_offset = 0;
51
917k
    uint64_t scan_start;
52
917k
    uint64_t scan_end;
53
54
    /* The code is optimized for STD_MAX_MATCH-2 multiple of 16. */
55
917k
    Assert(STD_MAX_MATCH == 258, "Code too clever");
56
57
917k
    best_len = s->prev_length ? s->prev_length : STD_MIN_MATCH-1;
58
917k
    if (UNLIKELY(best_len >= lookahead))
59
1.93k
        return lookahead;
60
#ifdef LONGEST_MATCH_SLOW
61
#  ifdef LONGEST_MATCH_SLOW_ROLL
62
    /* Rolling-hash variant always runs the post-match offset search; the
63
     * compiler folds the constant away below.
64
     */
65
406k
    const int offset_search = 1;
66
#  else
67
    /* The post-match offset search only pays off when we entered with a
68
     * prior best_len from lazy evaluation, so gate on it at function entry.
69
     */
70
149k
    const int offset_search = (best_len >= STD_MIN_MATCH);
71
#  endif
72
149k
#endif
73
74
    /* Calculate read offset which should only extend an extra byte to find the
75
     * next best match length. When best_len is shorter than the read width, we
76
     * diff the mismatched bytes instead.
77
     */
78
915k
    offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
79
80
359k
    scan = window + strstart;
81
359k
    scan_start = zng_memread_8(scan);
82
359k
    scan_end = zng_memread_8(scan+offset);
83
359k
    mbase_end = (mbase_start+offset);
84
85
    /* Do not waste too much time if we already have a good match */
86
915k
    if (UNLIKELY(best_len >= s->good_match))
87
44.7k
        chain_length >>= 2;
88
89
    /* Stop when cur_match becomes <= limit. To simplify the code,
90
     * we prevent matches with the string of window index 0
91
     */
92
915k
    limit = strstart > MAX_DIST(s) ? (strstart - MAX_DIST(s)) : 0;
93
#ifndef LONGEST_MATCH_SLOW
94
359k
    early_exit = s->level < EARLY_EXIT_TRIGGER_LEVEL;
95
#endif
96
#ifdef LONGEST_MATCH_SLOW
97
    limit_base = limit;
98
555k
    if (best_len >= STD_MIN_MATCH) {
99
        /* We're continuing search (lazy evaluation). Find a most distant
100
         * chain by hashing substrings within the match area. We cannot use
101
         * s->prev[strstart+1,...] immediately because those strings are not
102
         * yet inserted into the hash table.
103
         */
104
#  ifdef LONGEST_MATCH_SLOW_ROLL
105
        uint32_t hash;
106
        uint32_t pos;
107
108
        hash = update_hash_roll(0, scan[1]);
109
        hash = update_hash_roll(hash, scan[2]);
110
111
2.43M
        for (uint32_t i = 3; i <= best_len; i++) {
112
2.29M
            hash = update_hash_roll(hash, scan[i]);
113
2.29M
            pos = head[hash];
114
2.29M
            if (UNLIKELY(pos < cur_match)) {
115
148k
                match_offset = i - 2;
116
148k
                cur_match = pos;
117
148k
            }
118
2.29M
        }
119
#  else /* 4-byte Knuth hash, fresh lookup per offset */
120
717k
        for (uint32_t i = 1; i + (WANT_MIN_MATCH - 1) <= best_len; i++) {
121
657k
            uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan + i));
122
657k
            uint32_t hash;
123
657k
            UPDATE_HASH_KNUTH(hash, val);
124
657k
            uint32_t pos = head[hash];
125
657k
            if (pos < cur_match) {
126
64.2k
                match_offset = i;
127
64.2k
                cur_match = pos;
128
64.2k
            }
129
657k
        }
130
#  endif
131
132
        /* Update offset-dependent variables */
133
200k
        limit = limit_base+match_offset;
134
200k
        if (UNLIKELY(cur_match <= limit))
135
108k
            return best_len;
136
91.6k
        mbase_start -= match_offset;
137
91.6k
        mbase_end -= match_offset;
138
91.6k
    }
139
447k
#endif
140
447k
    Assert((unsigned long)strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead");
141
3.43M
    for (;;) {
142
3.43M
        if (UNLIKELY(cur_match >= strstart))
143
0
            break;
144
145
        /* Skip to next match if the match length cannot increase or if the match length is
146
         * less than 2. Note that the checks below for insufficient lookahead only occur
147
         * occasionally for performance reasons.
148
         * Therefore uninitialized memory will be accessed and conditional jumps will be made
149
         * that depend on those values. However the length of the match is limited to the
150
         * lookahead, so the output of deflate is not affected by the uninitialized values.
151
         */
152
3.43M
        uint32_t len;
153
3.43M
        if (best_len < sizeof(uint64_t)) {
154
1.32M
            uint64_t cand_start = zng_memread_8(mbase_start + cur_match);
155
1.32M
            if (scan_start != cand_start) {
156
                /* Peel the first candidate out of the loop. A full 8-byte match falls straight
157
                 * through to compare256, and single-candidate chains (barely-compressible data)
158
                 * run with no loop overhead. */
159
1.07M
                uint64_t first_mask = zng_first_bytes_mask64(best_len + 1);
160
1.07M
                uint64_t diff = scan_start ^ cand_start;
161
                /* A candidate beats best_len only when its first best_len+1 bytes match, i.e.
162
                 * those bytes of the XOR are zero. The masked test rejects without running ctz. */
163
1.07M
                if (UNLIKELY((diff & first_mask) == 0)) {
164
672k
                    len = zng_first_diff_byte64(diff);
165
672k
                    goto short_match_accept;
166
672k
                }
167
406k
                if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
168
131k
                    return best_len;
169
275k
                cand_start = zng_memread_8(mbase_start + cur_match);
170
275k
                if (scan_start != cand_start) {
171
                    /* Walk the remaining candidates with the chain advance kept inline. */
172
10.6M
                    for (;;) {
173
10.6M
                        diff = scan_start ^ cand_start;
174
10.6M
                        if (UNLIKELY((diff & first_mask) == 0)) {
175
77.0k
                            len = zng_first_diff_byte64(diff);
176
77.0k
                            goto short_match_accept;
177
77.0k
                        }
178
10.5M
                        if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
179
165k
                            return best_len;
180
10.4M
                        cand_start = zng_memread_8(mbase_start + cur_match);
181
10.4M
                        if (scan_start == cand_start)
182
24.4k
                            break;
183
10.4M
                    }
184
266k
                }
185
275k
            }
186
            /* All 8 bytes match, fallthrough to compare256 for the tail. */
187
2.11M
        } else {
188
            /* Pre-filter the candidate on the start and end sentinels before compare256 using
189
             * simple 8-byte comparison since best_len >= 8. */
190
19.5M
            for (;;) {
191
                /* First check the end of the candidate at best_len+1 due to the higher
192
                 * likelihood of a mismatch. */
193
19.5M
                if (zng_memcmp_8(mbase_end+cur_match, &scan_end) == 0 &&
194
2.41M
                    zng_memcmp_8(mbase_start+cur_match, &scan_start) == 0)
195
1.96M
                    break;
196
17.5M
                GOTO_NEXT_CHAIN;
197
17.5M
            }
198
2.11M
        }
199
2.24M
        len = COMPARE256(scan+2, mbase_start+cur_match+2) + 2;
200
2.24M
        Assert(scan+len <= window+(unsigned)(s->window_size-1), "wild scan");
201
202
2.24M
        if (len > best_len)
203
3.58M
short_match_accept:
204
3.58M
        {
205
3.58M
            uint32_t match_start = cur_match - match_offset;
206
3.58M
            s->match_start = match_start;
207
208
            /* Do not look for better matches if the current match reaches
209
             * or exceeds the end of the input.
210
             */
211
3.58M
            if (UNLIKELY(len >= lookahead))
212
3.82k
                return lookahead;
213
2.16M
            if (UNLIKELY(len >= nice_match))
214
100k
                return len;
215
216
2.06M
            best_len = len;
217
218
2.06M
            offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
219
220
2.06M
            scan_end = zng_memread_8(scan+offset);
221
222
#ifdef LONGEST_MATCH_SLOW
223
            /* Look for a better string offset */
224
1.22M
            if (UNLIKELY(offset_search && len > STD_MIN_MATCH && match_start + len < strstart)) {
225
661k
                const unsigned char *scan_endstr;
226
661k
                uint32_t hash;
227
661k
                uint32_t pos, next_pos;
228
229
                /* Go back to offset 0 */
230
                cur_match -= match_offset;
231
                match_offset = 0;
232
                next_pos = cur_match;
233
234
                /* Walk prev[] for positions inside the match. The bound keeps
235
                 * the hash window within the match, so we follow chains that
236
                 * share bytes with the current match, not data past its end.
237
                 */
238
#  ifdef LONGEST_MATCH_SLOW_ROLL
239
26.8M
                for (uint32_t i = 0; i <= len - STD_MIN_MATCH; i++) {
240
#  else /* 4-byte Knuth hash needs len - 4 bound */
241
768k
                for (uint32_t i = 0; i <= len - WANT_MIN_MATCH; i++) {
242
748k
#  endif
243
748k
                    pos = prev[(cur_match + i) & wmask];
244
26.9M
                    if (UNLIKELY(pos < next_pos)) {
245
                        /* Hash chain is more distant, use it */
246
732k
                        if (UNLIKELY(pos <= limit_base + i))
247
44.5k
                            return best_len;
248
688k
                        next_pos = pos;
249
688k
                        match_offset = i;
250
688k
                    }
251
748k
                }
252
                /* Switch cur_match to next_pos chain */
253
617k
                cur_match = next_pos;
254
255
                /* Try hash head at a window covering the tail of the current
256
                 * match to find chains that extend farther back. The window
257
                 * width differs per variant: 3 bytes for rolling, 4 for Knuth.
258
                 */
259
#  ifdef LONGEST_MATCH_SLOW_ROLL
260
597k
                scan_endstr = scan + len - (STD_MIN_MATCH-1);
261
262
                hash = update_hash_roll(0, scan_endstr[0]);
263
                hash = update_hash_roll(hash, scan_endstr[1]);
264
                hash = update_hash_roll(hash, scan_endstr[2]);
265
266
                pos = head[hash];
267
597k
                if (UNLIKELY(pos < cur_match)) {
268
48.9k
                    match_offset = len - (STD_MIN_MATCH-1);
269
48.9k
                    if (pos <= limit_base + match_offset)
270
32.8k
                        return best_len;
271
16.1k
                    cur_match = pos;
272
16.1k
                }
273
#  else
274
20.0k
                scan_endstr = scan + len - WANT_MIN_MATCH;
275
20.0k
                uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan_endstr));
276
20.0k
                UPDATE_HASH_KNUTH(hash, val);
277
278
                pos = head[hash];
279
20.0k
                if (pos < cur_match) {
280
0
                    match_offset = len - WANT_MIN_MATCH;
281
0
                    if (pos <= limit_base + match_offset)
282
0
                        return best_len;
283
0
                    cur_match = pos;
284
0
                }
285
20.0k
#  endif
286
287
                /* Update offset-dependent variables */
288
584k
                limit = limit_base+match_offset;
289
584k
                mbase_start = window-match_offset;
290
584k
                mbase_end = (mbase_start+offset);
291
584k
                continue;
292
617k
            }
293
568k
#endif
294
568k
            mbase_end = (mbase_start+offset);
295
568k
        }
296
#ifndef LONGEST_MATCH_SLOW
297
82.4k
        else if (UNLIKELY(early_exit)) {
298
            /* The probability of finding a match later if we here is pretty low, so for
299
             * performance it's best to outright stop here for the lower compression levels
300
             */
301
342
            break;
302
342
        }
303
912k
#endif
304
2.22M
        GOTO_NEXT_CHAIN;
305
2.22M
    }
306
342
    return best_len;
307
447k
}
Unexecuted instantiation: longest_match_sse2
Unexecuted instantiation: longest_match_slow_knuth_sse2
Unexecuted instantiation: longest_match_slow_roll_sse2
longest_match_avx2
Line
Count
Source
28
359k
Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, uint32_t cur_match) {
29
359k
    const unsigned wmask = W_MASK(s);
30
359k
    unsigned int strstart = s->strstart;
31
359k
    const unsigned char *window = s->window;
32
359k
    const Pos *prev = s->prev;
33
#ifdef LONGEST_MATCH_SLOW
34
    const Pos *head = s->head;
35
#endif
36
359k
    const unsigned char *scan;
37
359k
    const unsigned char *mbase_start = window;
38
359k
    const unsigned char *mbase_end;
39
359k
    uint32_t limit;
40
#ifdef LONGEST_MATCH_SLOW
41
    uint32_t limit_base;
42
#endif
43
359k
#ifndef LONGEST_MATCH_SLOW
44
359k
    int32_t early_exit;
45
359k
#endif
46
359k
    uint32_t chain_length = s->max_chain_length;
47
359k
    uint32_t nice_match = (uint32_t)s->nice_match;
48
359k
    uint32_t best_len, offset;
49
359k
    uint32_t lookahead = s->lookahead;
50
359k
    uint32_t match_offset = 0;
51
359k
    uint64_t scan_start;
52
359k
    uint64_t scan_end;
53
54
    /* The code is optimized for STD_MAX_MATCH-2 multiple of 16. */
55
359k
    Assert(STD_MAX_MATCH == 258, "Code too clever");
56
57
359k
    best_len = s->prev_length ? s->prev_length : STD_MIN_MATCH-1;
58
359k
    if (UNLIKELY(best_len >= lookahead))
59
0
        return lookahead;
60
#ifdef LONGEST_MATCH_SLOW
61
#  ifdef LONGEST_MATCH_SLOW_ROLL
62
    /* Rolling-hash variant always runs the post-match offset search; the
63
     * compiler folds the constant away below.
64
     */
65
    const int offset_search = 1;
66
#  else
67
    /* The post-match offset search only pays off when we entered with a
68
     * prior best_len from lazy evaluation, so gate on it at function entry.
69
     */
70
    const int offset_search = (best_len >= STD_MIN_MATCH);
71
#  endif
72
#endif
73
74
    /* Calculate read offset which should only extend an extra byte to find the
75
     * next best match length. When best_len is shorter than the read width, we
76
     * diff the mismatched bytes instead.
77
     */
78
359k
    offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
79
80
359k
    scan = window + strstart;
81
359k
    scan_start = zng_memread_8(scan);
82
359k
    scan_end = zng_memread_8(scan+offset);
83
359k
    mbase_end = (mbase_start+offset);
84
85
    /* Do not waste too much time if we already have a good match */
86
359k
    if (UNLIKELY(best_len >= s->good_match))
87
0
        chain_length >>= 2;
88
89
    /* Stop when cur_match becomes <= limit. To simplify the code,
90
     * we prevent matches with the string of window index 0
91
     */
92
359k
    limit = strstart > MAX_DIST(s) ? (strstart - MAX_DIST(s)) : 0;
93
359k
#ifndef LONGEST_MATCH_SLOW
94
359k
    early_exit = s->level < EARLY_EXIT_TRIGGER_LEVEL;
95
359k
#endif
96
#ifdef LONGEST_MATCH_SLOW
97
    limit_base = limit;
98
    if (best_len >= STD_MIN_MATCH) {
99
        /* We're continuing search (lazy evaluation). Find a most distant
100
         * chain by hashing substrings within the match area. We cannot use
101
         * s->prev[strstart+1,...] immediately because those strings are not
102
         * yet inserted into the hash table.
103
         */
104
#  ifdef LONGEST_MATCH_SLOW_ROLL
105
        uint32_t hash;
106
        uint32_t pos;
107
108
        hash = update_hash_roll(0, scan[1]);
109
        hash = update_hash_roll(hash, scan[2]);
110
111
        for (uint32_t i = 3; i <= best_len; i++) {
112
            hash = update_hash_roll(hash, scan[i]);
113
            pos = head[hash];
114
            if (UNLIKELY(pos < cur_match)) {
115
                match_offset = i - 2;
116
                cur_match = pos;
117
            }
118
        }
119
#  else /* 4-byte Knuth hash, fresh lookup per offset */
120
        for (uint32_t i = 1; i + (WANT_MIN_MATCH - 1) <= best_len; i++) {
121
            uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan + i));
122
            uint32_t hash;
123
            UPDATE_HASH_KNUTH(hash, val);
124
            uint32_t pos = head[hash];
125
            if (pos < cur_match) {
126
                match_offset = i;
127
                cur_match = pos;
128
            }
129
        }
130
#  endif
131
132
        /* Update offset-dependent variables */
133
        limit = limit_base+match_offset;
134
        if (UNLIKELY(cur_match <= limit))
135
            return best_len;
136
        mbase_start -= match_offset;
137
        mbase_end -= match_offset;
138
    }
139
#endif
140
359k
    Assert((unsigned long)strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead");
141
1.17M
    for (;;) {
142
1.17M
        if (UNLIKELY(cur_match >= strstart))
143
0
            break;
144
145
        /* Skip to next match if the match length cannot increase or if the match length is
146
         * less than 2. Note that the checks below for insufficient lookahead only occur
147
         * occasionally for performance reasons.
148
         * Therefore uninitialized memory will be accessed and conditional jumps will be made
149
         * that depend on those values. However the length of the match is limited to the
150
         * lookahead, so the output of deflate is not affected by the uninitialized values.
151
         */
152
1.17M
        uint32_t len;
153
1.17M
        if (best_len < sizeof(uint64_t)) {
154
614k
            uint64_t cand_start = zng_memread_8(mbase_start + cur_match);
155
614k
            if (scan_start != cand_start) {
156
                /* Peel the first candidate out of the loop. A full 8-byte match falls straight
157
                 * through to compare256, and single-candidate chains (barely-compressible data)
158
                 * run with no loop overhead. */
159
451k
                uint64_t first_mask = zng_first_bytes_mask64(best_len + 1);
160
451k
                uint64_t diff = scan_start ^ cand_start;
161
                /* A candidate beats best_len only when its first best_len+1 bytes match, i.e.
162
                 * those bytes of the XOR are zero. The masked test rejects without running ctz. */
163
451k
                if (UNLIKELY((diff & first_mask) == 0)) {
164
302k
                    len = zng_first_diff_byte64(diff);
165
302k
                    goto short_match_accept;
166
302k
                }
167
149k
                if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
168
49.6k
                    return best_len;
169
99.8k
                cand_start = zng_memread_8(mbase_start + cur_match);
170
99.8k
                if (scan_start != cand_start) {
171
                    /* Walk the remaining candidates with the chain advance kept inline. */
172
1.10M
                    for (;;) {
173
1.10M
                        diff = scan_start ^ cand_start;
174
1.10M
                        if (UNLIKELY((diff & first_mask) == 0)) {
175
17.6k
                            len = zng_first_diff_byte64(diff);
176
17.6k
                            goto short_match_accept;
177
17.6k
                        }
178
1.08M
                        if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
179
69.4k
                            return best_len;
180
1.01M
                        cand_start = zng_memread_8(mbase_start + cur_match);
181
1.01M
                        if (scan_start == cand_start)
182
8.53k
                            break;
183
1.01M
                    }
184
95.6k
                }
185
99.8k
            }
186
            /* All 8 bytes match, fallthrough to compare256 for the tail. */
187
614k
        } else {
188
            /* Pre-filter the candidate on the start and end sentinels before compare256 using
189
             * simple 8-byte comparison since best_len >= 8. */
190
2.56M
            for (;;) {
191
                /* First check the end of the candidate at best_len+1 due to the higher
192
                 * likelihood of a mismatch. */
193
2.56M
                if (zng_memcmp_8(mbase_end+cur_match, &scan_end) == 0 &&
194
546k
                    zng_memcmp_8(mbase_start+cur_match, &scan_start) == 0)
195
509k
                    break;
196
2.05M
                GOTO_NEXT_CHAIN;
197
2.05M
            }
198
562k
        }
199
684k
        len = COMPARE256(scan+2, mbase_start+cur_match+2) + 2;
200
684k
        Assert(scan+len <= window+(unsigned)(s->window_size-1), "wild scan");
201
202
684k
        if (len > best_len)
203
1.52M
short_match_accept:
204
1.52M
        {
205
1.52M
            uint32_t match_start = cur_match - match_offset;
206
1.52M
            s->match_start = match_start;
207
208
            /* Do not look for better matches if the current match reaches
209
             * or exceeds the end of the input.
210
             */
211
1.52M
            if (UNLIKELY(len >= lookahead))
212
1.55k
                return lookahead;
213
920k
            if (UNLIKELY(len >= nice_match))
214
90.1k
                return len;
215
216
830k
            best_len = len;
217
218
830k
            offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
219
220
830k
            scan_end = zng_memread_8(scan+offset);
221
222
#ifdef LONGEST_MATCH_SLOW
223
            /* Look for a better string offset */
224
            if (UNLIKELY(offset_search && len > STD_MIN_MATCH && match_start + len < strstart)) {
225
                const unsigned char *scan_endstr;
226
                uint32_t hash;
227
                uint32_t pos, next_pos;
228
229
                /* Go back to offset 0 */
230
                cur_match -= match_offset;
231
                match_offset = 0;
232
                next_pos = cur_match;
233
234
                /* Walk prev[] for positions inside the match. The bound keeps
235
                 * the hash window within the match, so we follow chains that
236
                 * share bytes with the current match, not data past its end.
237
                 */
238
#  ifdef LONGEST_MATCH_SLOW_ROLL
239
                for (uint32_t i = 0; i <= len - STD_MIN_MATCH; i++) {
240
#  else /* 4-byte Knuth hash needs len - 4 bound */
241
                for (uint32_t i = 0; i <= len - WANT_MIN_MATCH; i++) {
242
#  endif
243
                    pos = prev[(cur_match + i) & wmask];
244
                    if (UNLIKELY(pos < next_pos)) {
245
                        /* Hash chain is more distant, use it */
246
                        if (UNLIKELY(pos <= limit_base + i))
247
                            return best_len;
248
                        next_pos = pos;
249
                        match_offset = i;
250
                    }
251
                }
252
                /* Switch cur_match to next_pos chain */
253
                cur_match = next_pos;
254
255
                /* Try hash head at a window covering the tail of the current
256
                 * match to find chains that extend farther back. The window
257
                 * width differs per variant: 3 bytes for rolling, 4 for Knuth.
258
                 */
259
#  ifdef LONGEST_MATCH_SLOW_ROLL
260
                scan_endstr = scan + len - (STD_MIN_MATCH-1);
261
262
                hash = update_hash_roll(0, scan_endstr[0]);
263
                hash = update_hash_roll(hash, scan_endstr[1]);
264
                hash = update_hash_roll(hash, scan_endstr[2]);
265
266
                pos = head[hash];
267
                if (UNLIKELY(pos < cur_match)) {
268
                    match_offset = len - (STD_MIN_MATCH-1);
269
                    if (pos <= limit_base + match_offset)
270
                        return best_len;
271
                    cur_match = pos;
272
                }
273
#  else
274
                scan_endstr = scan + len - WANT_MIN_MATCH;
275
                uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan_endstr));
276
                UPDATE_HASH_KNUTH(hash, val);
277
278
                pos = head[hash];
279
                if (pos < cur_match) {
280
                    match_offset = len - WANT_MIN_MATCH;
281
                    if (pos <= limit_base + match_offset)
282
                        return best_len;
283
                    cur_match = pos;
284
                }
285
#  endif
286
287
                /* Update offset-dependent variables */
288
                limit = limit_base+match_offset;
289
                mbase_start = window-match_offset;
290
                mbase_end = (mbase_start+offset);
291
                continue;
292
            }
293
#endif
294
830k
            mbase_end = (mbase_start+offset);
295
830k
        }
296
82.4k
#ifndef LONGEST_MATCH_SLOW
297
82.4k
        else if (UNLIKELY(early_exit)) {
298
            /* The probability of finding a match later if we here is pretty low, so for
299
             * performance it's best to outright stop here for the lower compression levels
300
             */
301
342
            break;
302
342
        }
303
912k
#endif
304
912k
        GOTO_NEXT_CHAIN;
305
912k
    }
306
342
    return best_len;
307
359k
}
longest_match_slow_knuth_avx2
Line
Count
Source
28
150k
Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, uint32_t cur_match) {
29
150k
    const unsigned wmask = W_MASK(s);
30
150k
    unsigned int strstart = s->strstart;
31
150k
    const unsigned char *window = s->window;
32
150k
    const Pos *prev = s->prev;
33
150k
#ifdef LONGEST_MATCH_SLOW
34
150k
    const Pos *head = s->head;
35
150k
#endif
36
150k
    const unsigned char *scan;
37
150k
    const unsigned char *mbase_start = window;
38
150k
    const unsigned char *mbase_end;
39
150k
    uint32_t limit;
40
150k
#ifdef LONGEST_MATCH_SLOW
41
150k
    uint32_t limit_base;
42
150k
#endif
43
#ifndef LONGEST_MATCH_SLOW
44
    int32_t early_exit;
45
#endif
46
150k
    uint32_t chain_length = s->max_chain_length;
47
150k
    uint32_t nice_match = (uint32_t)s->nice_match;
48
150k
    uint32_t best_len, offset;
49
150k
    uint32_t lookahead = s->lookahead;
50
150k
    uint32_t match_offset = 0;
51
150k
    uint64_t scan_start;
52
150k
    uint64_t scan_end;
53
54
    /* The code is optimized for STD_MAX_MATCH-2 multiple of 16. */
55
150k
    Assert(STD_MAX_MATCH == 258, "Code too clever");
56
57
150k
    best_len = s->prev_length ? s->prev_length : STD_MIN_MATCH-1;
58
150k
    if (UNLIKELY(best_len >= lookahead))
59
766
        return lookahead;
60
149k
#ifdef LONGEST_MATCH_SLOW
61
#  ifdef LONGEST_MATCH_SLOW_ROLL
62
    /* Rolling-hash variant always runs the post-match offset search; the
63
     * compiler folds the constant away below.
64
     */
65
    const int offset_search = 1;
66
#  else
67
    /* The post-match offset search only pays off when we entered with a
68
     * prior best_len from lazy evaluation, so gate on it at function entry.
69
     */
70
149k
    const int offset_search = (best_len >= STD_MIN_MATCH);
71
149k
#  endif
72
149k
#endif
73
74
    /* Calculate read offset which should only extend an extra byte to find the
75
     * next best match length. When best_len is shorter than the read width, we
76
     * diff the mismatched bytes instead.
77
     */
78
149k
    offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
79
80
149k
    scan = window + strstart;
81
149k
    scan_start = zng_memread_8(scan);
82
149k
    scan_end = zng_memread_8(scan+offset);
83
149k
    mbase_end = (mbase_start+offset);
84
85
    /* Do not waste too much time if we already have a good match */
86
149k
    if (UNLIKELY(best_len >= s->good_match))
87
25.4k
        chain_length >>= 2;
88
89
    /* Stop when cur_match becomes <= limit. To simplify the code,
90
     * we prevent matches with the string of window index 0
91
     */
92
149k
    limit = strstart > MAX_DIST(s) ? (strstart - MAX_DIST(s)) : 0;
93
#ifndef LONGEST_MATCH_SLOW
94
    early_exit = s->level < EARLY_EXIT_TRIGGER_LEVEL;
95
#endif
96
149k
#ifdef LONGEST_MATCH_SLOW
97
149k
    limit_base = limit;
98
149k
    if (best_len >= STD_MIN_MATCH) {
99
        /* We're continuing search (lazy evaluation). Find a most distant
100
         * chain by hashing substrings within the match area. We cannot use
101
         * s->prev[strstart+1,...] immediately because those strings are not
102
         * yet inserted into the hash table.
103
         */
104
#  ifdef LONGEST_MATCH_SLOW_ROLL
105
        uint32_t hash;
106
        uint32_t pos;
107
108
        hash = update_hash_roll(0, scan[1]);
109
        hash = update_hash_roll(hash, scan[2]);
110
111
        for (uint32_t i = 3; i <= best_len; i++) {
112
            hash = update_hash_roll(hash, scan[i]);
113
            pos = head[hash];
114
            if (UNLIKELY(pos < cur_match)) {
115
                match_offset = i - 2;
116
                cur_match = pos;
117
            }
118
        }
119
#  else /* 4-byte Knuth hash, fresh lookup per offset */
120
717k
        for (uint32_t i = 1; i + (WANT_MIN_MATCH - 1) <= best_len; i++) {
121
657k
            uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan + i));
122
657k
            uint32_t hash;
123
657k
            UPDATE_HASH_KNUTH(hash, val);
124
657k
            uint32_t pos = head[hash];
125
657k
            if (pos < cur_match) {
126
64.2k
                match_offset = i;
127
64.2k
                cur_match = pos;
128
64.2k
            }
129
657k
        }
130
59.5k
#  endif
131
132
        /* Update offset-dependent variables */
133
59.5k
        limit = limit_base+match_offset;
134
59.5k
        if (UNLIKELY(cur_match <= limit))
135
29.1k
            return best_len;
136
30.3k
        mbase_start -= match_offset;
137
30.3k
        mbase_end -= match_offset;
138
30.3k
    }
139
120k
#endif
140
120k
    Assert((unsigned long)strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead");
141
730k
    for (;;) {
142
730k
        if (UNLIKELY(cur_match >= strstart))
143
0
            break;
144
145
        /* Skip to next match if the match length cannot increase or if the match length is
146
         * less than 2. Note that the checks below for insufficient lookahead only occur
147
         * occasionally for performance reasons.
148
         * Therefore uninitialized memory will be accessed and conditional jumps will be made
149
         * that depend on those values. However the length of the match is limited to the
150
         * lookahead, so the output of deflate is not affected by the uninitialized values.
151
         */
152
730k
        uint32_t len;
153
730k
        if (best_len < sizeof(uint64_t)) {
154
202k
            uint64_t cand_start = zng_memread_8(mbase_start + cur_match);
155
202k
            if (scan_start != cand_start) {
156
                /* Peel the first candidate out of the loop. A full 8-byte match falls straight
157
                 * through to compare256, and single-candidate chains (barely-compressible data)
158
                 * run with no loop overhead. */
159
169k
                uint64_t first_mask = zng_first_bytes_mask64(best_len + 1);
160
169k
                uint64_t diff = scan_start ^ cand_start;
161
                /* A candidate beats best_len only when its first best_len+1 bytes match, i.e.
162
                 * those bytes of the XOR are zero. The masked test rejects without running ctz. */
163
169k
                if (UNLIKELY((diff & first_mask) == 0)) {
164
103k
                    len = zng_first_diff_byte64(diff);
165
103k
                    goto short_match_accept;
166
103k
                }
167
65.9k
                if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
168
13.3k
                    return best_len;
169
52.5k
                cand_start = zng_memread_8(mbase_start + cur_match);
170
52.5k
                if (scan_start != cand_start) {
171
                    /* Walk the remaining candidates with the chain advance kept inline. */
172
1.93M
                    for (;;) {
173
1.93M
                        diff = scan_start ^ cand_start;
174
1.93M
                        if (UNLIKELY((diff & first_mask) == 0)) {
175
14.9k
                            len = zng_first_diff_byte64(diff);
176
14.9k
                            goto short_match_accept;
177
14.9k
                        }
178
1.91M
                        if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
179
28.1k
                            return best_len;
180
1.88M
                        cand_start = zng_memread_8(mbase_start + cur_match);
181
1.88M
                        if (scan_start == cand_start)
182
7.66k
                            break;
183
1.88M
                    }
184
50.8k
                }
185
52.5k
            }
186
            /* All 8 bytes match, fallthrough to compare256 for the tail. */
187
528k
        } else {
188
            /* Pre-filter the candidate on the start and end sentinels before compare256 using
189
             * simple 8-byte comparison since best_len >= 8. */
190
5.47M
            for (;;) {
191
                /* First check the end of the candidate at best_len+1 due to the higher
192
                 * likelihood of a mismatch. */
193
5.47M
                if (zng_memcmp_8(mbase_end+cur_match, &scan_end) == 0 &&
194
552k
                    zng_memcmp_8(mbase_start+cur_match, &scan_start) == 0)
195
483k
                    break;
196
4.99M
                GOTO_NEXT_CHAIN;
197
4.99M
            }
198
528k
        }
199
526k
        len = COMPARE256(scan+2, mbase_start+cur_match+2) + 2;
200
526k
        Assert(scan+len <= window+(unsigned)(s->window_size-1), "wild scan");
201
202
526k
        if (len > best_len)
203
740k
short_match_accept:
204
740k
        {
205
740k
            uint32_t match_start = cur_match - match_offset;
206
740k
            s->match_start = match_start;
207
208
            /* Do not look for better matches if the current match reaches
209
             * or exceeds the end of the input.
210
             */
211
740k
            if (UNLIKELY(len >= lookahead))
212
1.01k
                return lookahead;
213
428k
            if (UNLIKELY(len >= nice_match))
214
4.66k
                return len;
215
216
423k
            best_len = len;
217
218
423k
            offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
219
220
423k
            scan_end = zng_memread_8(scan+offset);
221
222
423k
#ifdef LONGEST_MATCH_SLOW
223
            /* Look for a better string offset */
224
423k
            if (UNLIKELY(offset_search && len > STD_MIN_MATCH && match_start + len < strstart)) {
225
22.2k
                const unsigned char *scan_endstr;
226
22.2k
                uint32_t hash;
227
22.2k
                uint32_t pos, next_pos;
228
229
                /* Go back to offset 0 */
230
22.2k
                cur_match -= match_offset;
231
22.2k
                match_offset = 0;
232
22.2k
                next_pos = cur_match;
233
234
                /* Walk prev[] for positions inside the match. The bound keeps
235
                 * the hash window within the match, so we follow chains that
236
                 * share bytes with the current match, not data past its end.
237
                 */
238
#  ifdef LONGEST_MATCH_SLOW_ROLL
239
                for (uint32_t i = 0; i <= len - STD_MIN_MATCH; i++) {
240
#  else /* 4-byte Knuth hash needs len - 4 bound */
241
768k
                for (uint32_t i = 0; i <= len - WANT_MIN_MATCH; i++) {
242
748k
#  endif
243
748k
                    pos = prev[(cur_match + i) & wmask];
244
748k
                    if (UNLIKELY(pos < next_pos)) {
245
                        /* Hash chain is more distant, use it */
246
30.1k
                        if (UNLIKELY(pos <= limit_base + i))
247
2.24k
                            return best_len;
248
27.8k
                        next_pos = pos;
249
27.8k
                        match_offset = i;
250
27.8k
                    }
251
748k
                }
252
                /* Switch cur_match to next_pos chain */
253
20.0k
                cur_match = next_pos;
254
255
                /* Try hash head at a window covering the tail of the current
256
                 * match to find chains that extend farther back. The window
257
                 * width differs per variant: 3 bytes for rolling, 4 for Knuth.
258
                 */
259
#  ifdef LONGEST_MATCH_SLOW_ROLL
260
                scan_endstr = scan + len - (STD_MIN_MATCH-1);
261
262
                hash = update_hash_roll(0, scan_endstr[0]);
263
                hash = update_hash_roll(hash, scan_endstr[1]);
264
                hash = update_hash_roll(hash, scan_endstr[2]);
265
266
                pos = head[hash];
267
                if (UNLIKELY(pos < cur_match)) {
268
                    match_offset = len - (STD_MIN_MATCH-1);
269
                    if (pos <= limit_base + match_offset)
270
                        return best_len;
271
                    cur_match = pos;
272
                }
273
#  else
274
20.0k
                scan_endstr = scan + len - WANT_MIN_MATCH;
275
20.0k
                uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan_endstr));
276
20.0k
                UPDATE_HASH_KNUTH(hash, val);
277
278
20.0k
                pos = head[hash];
279
20.0k
                if (pos < cur_match) {
280
0
                    match_offset = len - WANT_MIN_MATCH;
281
0
                    if (pos <= limit_base + match_offset)
282
0
                        return best_len;
283
0
                    cur_match = pos;
284
0
                }
285
20.0k
#  endif
286
287
                /* Update offset-dependent variables */
288
20.0k
                limit = limit_base+match_offset;
289
20.0k
                mbase_start = window-match_offset;
290
20.0k
                mbase_end = (mbase_start+offset);
291
20.0k
                continue;
292
20.0k
            }
293
401k
#endif
294
401k
            mbase_end = (mbase_start+offset);
295
401k
        }
296
#ifndef LONGEST_MATCH_SLOW
297
        else if (UNLIKELY(early_exit)) {
298
            /* The probability of finding a match later if we here is pretty low, so for
299
             * performance it's best to outright stop here for the lower compression levels
300
             */
301
            break;
302
        }
303
#endif
304
617k
        GOTO_NEXT_CHAIN;
305
617k
    }
306
0
    return best_len;
307
120k
}
longest_match_slow_roll_avx2
Line
Count
Source
28
407k
Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, uint32_t cur_match) {
29
407k
    const unsigned wmask = W_MASK(s);
30
407k
    unsigned int strstart = s->strstart;
31
407k
    const unsigned char *window = s->window;
32
407k
    const Pos *prev = s->prev;
33
407k
#ifdef LONGEST_MATCH_SLOW
34
407k
    const Pos *head = s->head;
35
407k
#endif
36
407k
    const unsigned char *scan;
37
407k
    const unsigned char *mbase_start = window;
38
407k
    const unsigned char *mbase_end;
39
407k
    uint32_t limit;
40
407k
#ifdef LONGEST_MATCH_SLOW
41
407k
    uint32_t limit_base;
42
407k
#endif
43
#ifndef LONGEST_MATCH_SLOW
44
    int32_t early_exit;
45
#endif
46
407k
    uint32_t chain_length = s->max_chain_length;
47
407k
    uint32_t nice_match = (uint32_t)s->nice_match;
48
407k
    uint32_t best_len, offset;
49
407k
    uint32_t lookahead = s->lookahead;
50
407k
    uint32_t match_offset = 0;
51
407k
    uint64_t scan_start;
52
407k
    uint64_t scan_end;
53
54
    /* The code is optimized for STD_MAX_MATCH-2 multiple of 16. */
55
407k
    Assert(STD_MAX_MATCH == 258, "Code too clever");
56
57
407k
    best_len = s->prev_length ? s->prev_length : STD_MIN_MATCH-1;
58
407k
    if (UNLIKELY(best_len >= lookahead))
59
1.16k
        return lookahead;
60
406k
#ifdef LONGEST_MATCH_SLOW
61
406k
#  ifdef LONGEST_MATCH_SLOW_ROLL
62
    /* Rolling-hash variant always runs the post-match offset search; the
63
     * compiler folds the constant away below.
64
     */
65
406k
    const int offset_search = 1;
66
#  else
67
    /* The post-match offset search only pays off when we entered with a
68
     * prior best_len from lazy evaluation, so gate on it at function entry.
69
     */
70
    const int offset_search = (best_len >= STD_MIN_MATCH);
71
#  endif
72
406k
#endif
73
74
    /* Calculate read offset which should only extend an extra byte to find the
75
     * next best match length. When best_len is shorter than the read width, we
76
     * diff the mismatched bytes instead.
77
     */
78
406k
    offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
79
80
406k
    scan = window + strstart;
81
406k
    scan_start = zng_memread_8(scan);
82
406k
    scan_end = zng_memread_8(scan+offset);
83
406k
    mbase_end = (mbase_start+offset);
84
85
    /* Do not waste too much time if we already have a good match */
86
406k
    if (UNLIKELY(best_len >= s->good_match))
87
19.3k
        chain_length >>= 2;
88
89
    /* Stop when cur_match becomes <= limit. To simplify the code,
90
     * we prevent matches with the string of window index 0
91
     */
92
406k
    limit = strstart > MAX_DIST(s) ? (strstart - MAX_DIST(s)) : 0;
93
#ifndef LONGEST_MATCH_SLOW
94
    early_exit = s->level < EARLY_EXIT_TRIGGER_LEVEL;
95
#endif
96
406k
#ifdef LONGEST_MATCH_SLOW
97
406k
    limit_base = limit;
98
406k
    if (best_len >= STD_MIN_MATCH) {
99
        /* We're continuing search (lazy evaluation). Find a most distant
100
         * chain by hashing substrings within the match area. We cannot use
101
         * s->prev[strstart+1,...] immediately because those strings are not
102
         * yet inserted into the hash table.
103
         */
104
141k
#  ifdef LONGEST_MATCH_SLOW_ROLL
105
141k
        uint32_t hash;
106
141k
        uint32_t pos;
107
108
141k
        hash = update_hash_roll(0, scan[1]);
109
141k
        hash = update_hash_roll(hash, scan[2]);
110
111
2.43M
        for (uint32_t i = 3; i <= best_len; i++) {
112
2.29M
            hash = update_hash_roll(hash, scan[i]);
113
2.29M
            pos = head[hash];
114
2.29M
            if (UNLIKELY(pos < cur_match)) {
115
148k
                match_offset = i - 2;
116
148k
                cur_match = pos;
117
148k
            }
118
2.29M
        }
119
#  else /* 4-byte Knuth hash, fresh lookup per offset */
120
        for (uint32_t i = 1; i + (WANT_MIN_MATCH - 1) <= best_len; i++) {
121
            uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan + i));
122
            uint32_t hash;
123
            UPDATE_HASH_KNUTH(hash, val);
124
            uint32_t pos = head[hash];
125
            if (pos < cur_match) {
126
                match_offset = i;
127
                cur_match = pos;
128
            }
129
        }
130
#  endif
131
132
        /* Update offset-dependent variables */
133
141k
        limit = limit_base+match_offset;
134
141k
        if (UNLIKELY(cur_match <= limit))
135
79.7k
            return best_len;
136
61.3k
        mbase_start -= match_offset;
137
61.3k
        mbase_end -= match_offset;
138
61.3k
    }
139
326k
#endif
140
326k
    Assert((unsigned long)strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead");
141
1.53M
    for (;;) {
142
1.53M
        if (UNLIKELY(cur_match >= strstart))
143
0
            break;
144
145
        /* Skip to next match if the match length cannot increase or if the match length is
146
         * less than 2. Note that the checks below for insufficient lookahead only occur
147
         * occasionally for performance reasons.
148
         * Therefore uninitialized memory will be accessed and conditional jumps will be made
149
         * that depend on those values. However the length of the match is limited to the
150
         * lookahead, so the output of deflate is not affected by the uninitialized values.
151
         */
152
1.53M
        uint32_t len;
153
1.53M
        if (best_len < sizeof(uint64_t)) {
154
506k
            uint64_t cand_start = zng_memread_8(mbase_start + cur_match);
155
506k
            if (scan_start != cand_start) {
156
                /* Peel the first candidate out of the loop. A full 8-byte match falls straight
157
                 * through to compare256, and single-candidate chains (barely-compressible data)
158
                 * run with no loop overhead. */
159
457k
                uint64_t first_mask = zng_first_bytes_mask64(best_len + 1);
160
457k
                uint64_t diff = scan_start ^ cand_start;
161
                /* A candidate beats best_len only when its first best_len+1 bytes match, i.e.
162
                 * those bytes of the XOR are zero. The masked test rejects without running ctz. */
163
457k
                if (UNLIKELY((diff & first_mask) == 0)) {
164
266k
                    len = zng_first_diff_byte64(diff);
165
266k
                    goto short_match_accept;
166
266k
                }
167
191k
                if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
168
68.5k
                    return best_len;
169
122k
                cand_start = zng_memread_8(mbase_start + cur_match);
170
122k
                if (scan_start != cand_start) {
171
                    /* Walk the remaining candidates with the chain advance kept inline. */
172
7.63M
                    for (;;) {
173
7.63M
                        diff = scan_start ^ cand_start;
174
7.63M
                        if (UNLIKELY((diff & first_mask) == 0)) {
175
44.3k
                            len = zng_first_diff_byte64(diff);
176
44.3k
                            goto short_match_accept;
177
44.3k
                        }
178
7.58M
                        if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
179
67.3k
                            return best_len;
180
7.52M
                        cand_start = zng_memread_8(mbase_start + cur_match);
181
7.52M
                        if (scan_start == cand_start)
182
8.27k
                            break;
183
7.52M
                    }
184
120k
                }
185
122k
            }
186
            /* All 8 bytes match, fallthrough to compare256 for the tail. */
187
1.02M
        } else {
188
            /* Pre-filter the candidate on the start and end sentinels before compare256 using
189
             * simple 8-byte comparison since best_len >= 8. */
190
11.5M
            for (;;) {
191
                /* First check the end of the candidate at best_len+1 due to the higher
192
                 * likelihood of a mismatch. */
193
11.5M
                if (zng_memcmp_8(mbase_end+cur_match, &scan_end) == 0 &&
194
1.31M
                    zng_memcmp_8(mbase_start+cur_match, &scan_start) == 0)
195
975k
                    break;
196
10.5M
                GOTO_NEXT_CHAIN;
197
10.5M
            }
198
1.02M
        }
199
1.03M
        len = COMPARE256(scan+2, mbase_start+cur_match+2) + 2;
200
1.03M
        Assert(scan+len <= window+(unsigned)(s->window_size-1), "wild scan");
201
202
1.03M
        if (len > best_len)
203
1.31M
short_match_accept:
204
1.31M
        {
205
1.31M
            uint32_t match_start = cur_match - match_offset;
206
1.31M
            s->match_start = match_start;
207
208
            /* Do not look for better matches if the current match reaches
209
             * or exceeds the end of the input.
210
             */
211
1.31M
            if (UNLIKELY(len >= lookahead))
212
1.25k
                return lookahead;
213
812k
            if (UNLIKELY(len >= nice_match))
214
6.04k
                return len;
215
216
806k
            best_len = len;
217
218
806k
            offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
219
220
806k
            scan_end = zng_memread_8(scan+offset);
221
222
806k
#ifdef LONGEST_MATCH_SLOW
223
            /* Look for a better string offset */
224
806k
            if (UNLIKELY(offset_search && len > STD_MIN_MATCH && match_start + len < strstart)) {
225
639k
                const unsigned char *scan_endstr;
226
639k
                uint32_t hash;
227
639k
                uint32_t pos, next_pos;
228
229
                /* Go back to offset 0 */
230
639k
                cur_match -= match_offset;
231
639k
                match_offset = 0;
232
639k
                next_pos = cur_match;
233
234
                /* Walk prev[] for positions inside the match. The bound keeps
235
                 * the hash window within the match, so we follow chains that
236
                 * share bytes with the current match, not data past its end.
237
                 */
238
639k
#  ifdef LONGEST_MATCH_SLOW_ROLL
239
26.8M
                for (uint32_t i = 0; i <= len - STD_MIN_MATCH; i++) {
240
#  else /* 4-byte Knuth hash needs len - 4 bound */
241
                for (uint32_t i = 0; i <= len - WANT_MIN_MATCH; i++) {
242
#  endif
243
26.2M
                    pos = prev[(cur_match + i) & wmask];
244
26.2M
                    if (UNLIKELY(pos < next_pos)) {
245
                        /* Hash chain is more distant, use it */
246
702k
                        if (UNLIKELY(pos <= limit_base + i))
247
42.2k
                            return best_len;
248
660k
                        next_pos = pos;
249
660k
                        match_offset = i;
250
660k
                    }
251
26.2M
                }
252
                /* Switch cur_match to next_pos chain */
253
597k
                cur_match = next_pos;
254
255
                /* Try hash head at a window covering the tail of the current
256
                 * match to find chains that extend farther back. The window
257
                 * width differs per variant: 3 bytes for rolling, 4 for Knuth.
258
                 */
259
597k
#  ifdef LONGEST_MATCH_SLOW_ROLL
260
597k
                scan_endstr = scan + len - (STD_MIN_MATCH-1);
261
262
597k
                hash = update_hash_roll(0, scan_endstr[0]);
263
597k
                hash = update_hash_roll(hash, scan_endstr[1]);
264
597k
                hash = update_hash_roll(hash, scan_endstr[2]);
265
266
597k
                pos = head[hash];
267
597k
                if (UNLIKELY(pos < cur_match)) {
268
48.9k
                    match_offset = len - (STD_MIN_MATCH-1);
269
48.9k
                    if (pos <= limit_base + match_offset)
270
32.8k
                        return best_len;
271
16.1k
                    cur_match = pos;
272
16.1k
                }
273
#  else
274
                scan_endstr = scan + len - WANT_MIN_MATCH;
275
                uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan_endstr));
276
                UPDATE_HASH_KNUTH(hash, val);
277
278
                pos = head[hash];
279
                if (pos < cur_match) {
280
                    match_offset = len - WANT_MIN_MATCH;
281
                    if (pos <= limit_base + match_offset)
282
                        return best_len;
283
                    cur_match = pos;
284
                }
285
#  endif
286
287
                /* Update offset-dependent variables */
288
564k
                limit = limit_base+match_offset;
289
564k
                mbase_start = window-match_offset;
290
564k
                mbase_end = (mbase_start+offset);
291
564k
                continue;
292
597k
            }
293
166k
#endif
294
166k
            mbase_end = (mbase_start+offset);
295
166k
        }
296
#ifndef LONGEST_MATCH_SLOW
297
        else if (UNLIKELY(early_exit)) {
298
            /* The probability of finding a match later if we here is pretty low, so for
299
             * performance it's best to outright stop here for the lower compression levels
300
             */
301
            break;
302
        }
303
#endif
304
699k
        GOTO_NEXT_CHAIN;
305
699k
    }
306
0
    return best_len;
307
326k
}
Unexecuted instantiation: longest_match_avx512
Unexecuted instantiation: longest_match_slow_knuth_avx512
Unexecuted instantiation: longest_match_slow_roll_avx512
308
309
#undef LONGEST_MATCH_SLOW
310
#undef LONGEST_MATCH_SLOW_ROLL
311
#undef LONGEST_MATCH