Coverage Report

Created: 2026-11-12 06:21

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
#define GOTO_NEXT_CHAIN \
14
15.9M
    if (--chain_length && (cur_match = prev[cur_match & wmask]) > limit) \
15
14.4M
        continue; \
16
1.52M
    return best_len;
17
18
/* Set match_start to the longest match starting at the given string and
19
 * return its length. Matches shorter or equal to prev_length are discarded,
20
 * in which case the result is equal to prev_length and match_start is garbage.
21
 *
22
 * IN assertions: cur_match is the head of the hash chain for the current
23
 * string (strstart) and its distance is <= MAX_DIST, and prev_length >=1
24
 * OUT assertion: the match length is not greater than s->lookahead
25
 */
26
69.8M
Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, uint32_t cur_match) {
27
69.8M
    const unsigned wmask = W_MASK(s);
28
69.8M
    unsigned int strstart = s->strstart;
29
69.8M
    const unsigned char *window = s->window;
30
69.8M
    const Pos *prev = s->prev;
31
#ifdef LONGEST_MATCH_SLOW
32
    const Pos *head = s->head;
33
#endif
34
69.8M
    const unsigned char *scan;
35
69.8M
    const unsigned char *mbase_start = window;
36
69.8M
    const unsigned char *mbase_end;
37
69.8M
    uint32_t limit;
38
#ifdef LONGEST_MATCH_SLOW
39
    uint32_t limit_base;
40
#endif
41
69.8M
    uint32_t chain_length = s->max_chain_length;
42
69.8M
    uint32_t nice_match = (uint32_t)s->nice_match;
43
69.8M
    uint32_t best_len, offset;
44
69.8M
    uint32_t lookahead = s->lookahead;
45
69.8M
    uint32_t match_offset = 0;
46
69.8M
    uint64_t scan_start;
47
69.8M
    uint64_t scan_end;
48
49
    /* The code is optimized for STD_MAX_MATCH-2 multiple of 16. */
50
69.8M
    Assert(STD_MAX_MATCH == 258, "Code too clever");
51
52
#ifdef LONGEST_MATCH_SLOW
53
0
    best_len = s->prev_length ? s->prev_length : STD_MIN_MATCH-1;
54
0
    if (UNLIKELY(best_len >= lookahead))
55
0
        return lookahead;
56
#else
57
69.8M
    best_len = STD_MIN_MATCH-1;
58
#endif
59
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
0
    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
0
    const int offset_search = (best_len >= STD_MIN_MATCH);
71
#  endif
72
0
#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
69.8M
    offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
79
80
0
    scan = window + strstart;
81
0
    scan_start = zng_memread_8(scan);
82
0
    scan_end = zng_memread_8(scan+offset);
83
0
    mbase_end = (mbase_start+offset);
84
85
    /* Do not waste too much time if we already have a good match */
86
69.8M
    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
69.8M
    limit = strstart > MAX_DIST(s) ? (strstart - MAX_DIST(s)) : 0;
93
#ifdef LONGEST_MATCH_SLOW
94
    limit_base = limit;
95
0
    if (best_len >= STD_MIN_MATCH) {
96
        /* We're continuing search (lazy evaluation). Find a most distant
97
         * chain by hashing substrings within the match area. We cannot use
98
         * s->prev[strstart+1,...] immediately because those strings are not
99
         * yet inserted into the hash table.
100
         */
101
#  ifdef LONGEST_MATCH_SLOW_ROLL
102
        uint32_t hash;
103
        uint32_t pos;
104
105
        hash = update_hash_roll(0, scan[1]);
106
        hash = update_hash_roll(hash, scan[2]);
107
108
0
        for (uint32_t i = 3; i <= best_len; i++) {
109
0
            hash = update_hash_roll(hash, scan[i]);
110
0
            pos = head[hash];
111
0
            if (UNLIKELY(pos < cur_match)) {
112
0
                match_offset = i - 2;
113
0
                cur_match = pos;
114
0
            }
115
0
        }
116
#  else /* 4-byte Knuth hash, fresh lookup per offset */
117
0
        for (uint32_t i = 1; i + (WANT_MIN_MATCH - 1) <= best_len; i++) {
118
0
            uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan + i));
119
0
            uint32_t hash;
120
0
            UPDATE_HASH_KNUTH(hash, val);
121
0
            uint32_t pos = head[hash];
122
0
            if (pos < cur_match) {
123
0
                match_offset = i;
124
0
                cur_match = pos;
125
0
            }
126
0
        }
127
#  endif
128
129
        /* Update offset-dependent variables */
130
0
        limit = limit_base+match_offset;
131
0
        if (UNLIKELY(cur_match <= limit))
132
0
            return best_len;
133
0
        mbase_start -= match_offset;
134
0
        mbase_end -= match_offset;
135
0
    }
136
0
#endif
137
0
    Assert(strstart <= s->fill_end, "need lookahead");
138
73.7M
    for (;;) {
139
73.7M
        if (UNLIKELY(cur_match >= strstart))
140
0
            break;
141
142
        /* Skip to next match if the match length cannot increase or if the match length is
143
         * less than 2. Note that the checks below for insufficient lookahead only occur
144
         * occasionally for performance reasons.
145
         * Therefore uninitialized memory will be accessed and conditional jumps will be made
146
         * that depend on those values. However the length of the match is limited to the
147
         * lookahead, so the output of deflate is not affected by the uninitialized values.
148
         */
149
73.7M
        uint32_t len;
150
73.7M
        if (best_len < sizeof(uint64_t)) {
151
72.7M
            uint64_t cand_start = zng_memread_8(mbase_start + cur_match);
152
72.7M
            if (scan_start != cand_start) {
153
                /* Peel the first candidate out of the loop. A full 8-byte match falls straight
154
                 * through to compare256, and single-candidate chains (barely-compressible data)
155
                 * run with no loop overhead. */
156
72.3M
                uint64_t first_mask = zng_first_bytes_mask64(best_len + 1);
157
72.3M
                uint64_t diff = scan_start ^ cand_start;
158
                /* A candidate beats best_len only when its first best_len+1 bytes match, i.e.
159
                 * those bytes of the XOR are zero. The masked test rejects without running ctz. */
160
72.3M
                if (UNLIKELY((diff & first_mask) == 0)) {
161
3.57M
                    len = zng_first_diff_byte64(diff);
162
3.57M
                    goto short_match_accept;
163
3.57M
                }
164
68.8M
                if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
165
51.6M
                    return best_len;
166
17.1M
                cand_start = zng_memread_8(mbase_start + cur_match);
167
17.1M
                if (scan_start != cand_start) {
168
                    /* Walk the remaining candidates with the chain advance kept inline. */
169
45.7M
                    for (;;) {
170
45.7M
                        diff = scan_start ^ cand_start;
171
45.7M
                        if (UNLIKELY((diff & first_mask) == 0)) {
172
482k
                            len = zng_first_diff_byte64(diff);
173
482k
                            goto short_match_accept;
174
482k
                        }
175
45.3M
                        if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
176
16.6M
                            return best_len;
177
28.7M
                        cand_start = zng_memread_8(mbase_start + cur_match);
178
28.7M
                        if (scan_start == cand_start)
179
42.9k
                            break;
180
28.7M
                    }
181
17.1M
                }
182
17.1M
            }
183
            /* All 8 bytes match, fallthrough to compare256 for the tail. */
184
72.7M
        } else {
185
            /* Pre-filter the candidate on the start and end sentinels before compare256 using
186
             * simple 8-byte comparison since best_len >= 8. */
187
11.5M
            for (;;) {
188
                /* First check the end of the candidate at best_len+1 due to the higher
189
                 * likelihood of a mismatch. */
190
11.5M
                if (zng_memcmp_8(mbase_end+cur_match, &scan_end) == 0 &&
191
877k
                    zng_memcmp_8(mbase_start+cur_match, &scan_start) == 0)
192
771k
                    break;
193
10.8M
                GOTO_NEXT_CHAIN;
194
10.8M
            }
195
1.02M
        }
196
197
1.17M
        len = COMPARE256(scan+2, mbase_start+cur_match+2) + 2;
198
1.17M
        Assert(scan+len <= window+(unsigned)(s->window_size-1), "wild scan");
199
200
1.17M
        if (len > best_len)
201
6.07M
short_match_accept:
202
6.07M
        {
203
6.07M
            uint32_t match_start = cur_match - match_offset;
204
6.07M
            s->match_start = match_start;
205
206
            /* Do not look for better matches if the current match reaches
207
             * or exceeds the end of the input.
208
             */
209
6.07M
            if (UNLIKELY(len >= lookahead))
210
1.56k
                return lookahead;
211
5.06M
            if (UNLIKELY(len >= nice_match))
212
59.2k
                return len;
213
214
5.00M
            best_len = len;
215
216
5.00M
            offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
217
218
5.00M
            scan_end = zng_memread_8(scan+offset);
219
220
#ifdef LONGEST_MATCH_SLOW
221
            /* Look for a better string offset */
222
0
            if (UNLIKELY(offset_search && len > STD_MIN_MATCH && match_start + len < strstart)) {
223
0
                const unsigned char *scan_endstr;
224
0
                uint32_t hash;
225
0
                uint32_t pos, next_pos;
226
227
                /* Go back to offset 0 */
228
                cur_match -= match_offset;
229
                match_offset = 0;
230
                next_pos = cur_match;
231
232
                /* Walk prev[] for positions inside the match. The bound keeps
233
                 * the hash window within the match, so we follow chains that
234
                 * share bytes with the current match, not data past its end.
235
                 */
236
#  ifdef LONGEST_MATCH_SLOW_ROLL
237
0
                for (uint32_t i = 0; i <= len - STD_MIN_MATCH; i++) {
238
#  else /* 4-byte Knuth hash needs len - 4 bound */
239
0
                for (uint32_t i = 0; i <= len - WANT_MIN_MATCH; i++) {
240
0
#  endif
241
0
                    pos = prev[(cur_match + i) & wmask];
242
0
                    if (UNLIKELY(pos < next_pos)) {
243
                        /* Hash chain is more distant, use it */
244
0
                        if (UNLIKELY(pos <= limit_base + i))
245
0
                            return best_len;
246
0
                        next_pos = pos;
247
0
                        match_offset = i;
248
0
                    }
249
0
                }
250
                /* Switch cur_match to next_pos chain */
251
0
                cur_match = next_pos;
252
253
                /* Try hash head at a window covering the tail of the current
254
                 * match to find chains that extend farther back. The window
255
                 * width differs per variant: 3 bytes for rolling, 4 for Knuth.
256
                 */
257
#  ifdef LONGEST_MATCH_SLOW_ROLL
258
0
                scan_endstr = scan + len - (STD_MIN_MATCH-1);
259
260
                hash = update_hash_roll(0, scan_endstr[0]);
261
                hash = update_hash_roll(hash, scan_endstr[1]);
262
                hash = update_hash_roll(hash, scan_endstr[2]);
263
264
                pos = head[hash];
265
0
                if (UNLIKELY(pos < cur_match)) {
266
0
                    match_offset = len - (STD_MIN_MATCH-1);
267
0
                    if (pos <= limit_base + match_offset)
268
0
                        return best_len;
269
0
                    cur_match = pos;
270
0
                }
271
#  else
272
0
                scan_endstr = scan + len - WANT_MIN_MATCH;
273
0
                uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan_endstr));
274
0
                UPDATE_HASH_KNUTH(hash, val);
275
276
                pos = head[hash];
277
0
                if (pos < cur_match) {
278
0
                    match_offset = len - WANT_MIN_MATCH;
279
0
                    if (pos <= limit_base + match_offset)
280
0
                        return best_len;
281
0
                    cur_match = pos;
282
0
                }
283
0
#  endif
284
285
                /* Update offset-dependent variables */
286
0
                limit = limit_base+match_offset;
287
0
                mbase_start = window-match_offset;
288
0
                mbase_end = (mbase_start+offset);
289
0
                continue;
290
0
            }
291
0
#endif
292
0
            mbase_end = (mbase_start+offset);
293
0
        }
294
5.17M
        GOTO_NEXT_CHAIN;
295
5.17M
    }
296
0
    return best_len;
297
0
}
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
26
69.8M
Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, uint32_t cur_match) {
27
69.8M
    const unsigned wmask = W_MASK(s);
28
69.8M
    unsigned int strstart = s->strstart;
29
69.8M
    const unsigned char *window = s->window;
30
69.8M
    const Pos *prev = s->prev;
31
#ifdef LONGEST_MATCH_SLOW
32
    const Pos *head = s->head;
33
#endif
34
69.8M
    const unsigned char *scan;
35
69.8M
    const unsigned char *mbase_start = window;
36
69.8M
    const unsigned char *mbase_end;
37
69.8M
    uint32_t limit;
38
#ifdef LONGEST_MATCH_SLOW
39
    uint32_t limit_base;
40
#endif
41
69.8M
    uint32_t chain_length = s->max_chain_length;
42
69.8M
    uint32_t nice_match = (uint32_t)s->nice_match;
43
69.8M
    uint32_t best_len, offset;
44
69.8M
    uint32_t lookahead = s->lookahead;
45
69.8M
    uint32_t match_offset = 0;
46
69.8M
    uint64_t scan_start;
47
69.8M
    uint64_t scan_end;
48
49
    /* The code is optimized for STD_MAX_MATCH-2 multiple of 16. */
50
69.8M
    Assert(STD_MAX_MATCH == 258, "Code too clever");
51
52
#ifdef LONGEST_MATCH_SLOW
53
    best_len = s->prev_length ? s->prev_length : STD_MIN_MATCH-1;
54
    if (UNLIKELY(best_len >= lookahead))
55
        return lookahead;
56
#else
57
69.8M
    best_len = STD_MIN_MATCH-1;
58
69.8M
#endif
59
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
69.8M
    offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
79
80
69.8M
    scan = window + strstart;
81
69.8M
    scan_start = zng_memread_8(scan);
82
69.8M
    scan_end = zng_memread_8(scan+offset);
83
69.8M
    mbase_end = (mbase_start+offset);
84
85
    /* Do not waste too much time if we already have a good match */
86
69.8M
    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
69.8M
    limit = strstart > MAX_DIST(s) ? (strstart - MAX_DIST(s)) : 0;
93
#ifdef LONGEST_MATCH_SLOW
94
    limit_base = limit;
95
    if (best_len >= STD_MIN_MATCH) {
96
        /* We're continuing search (lazy evaluation). Find a most distant
97
         * chain by hashing substrings within the match area. We cannot use
98
         * s->prev[strstart+1,...] immediately because those strings are not
99
         * yet inserted into the hash table.
100
         */
101
#  ifdef LONGEST_MATCH_SLOW_ROLL
102
        uint32_t hash;
103
        uint32_t pos;
104
105
        hash = update_hash_roll(0, scan[1]);
106
        hash = update_hash_roll(hash, scan[2]);
107
108
        for (uint32_t i = 3; i <= best_len; i++) {
109
            hash = update_hash_roll(hash, scan[i]);
110
            pos = head[hash];
111
            if (UNLIKELY(pos < cur_match)) {
112
                match_offset = i - 2;
113
                cur_match = pos;
114
            }
115
        }
116
#  else /* 4-byte Knuth hash, fresh lookup per offset */
117
        for (uint32_t i = 1; i + (WANT_MIN_MATCH - 1) <= best_len; i++) {
118
            uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan + i));
119
            uint32_t hash;
120
            UPDATE_HASH_KNUTH(hash, val);
121
            uint32_t pos = head[hash];
122
            if (pos < cur_match) {
123
                match_offset = i;
124
                cur_match = pos;
125
            }
126
        }
127
#  endif
128
129
        /* Update offset-dependent variables */
130
        limit = limit_base+match_offset;
131
        if (UNLIKELY(cur_match <= limit))
132
            return best_len;
133
        mbase_start -= match_offset;
134
        mbase_end -= match_offset;
135
    }
136
#endif
137
69.8M
    Assert(strstart <= s->fill_end, "need lookahead");
138
73.7M
    for (;;) {
139
73.7M
        if (UNLIKELY(cur_match >= strstart))
140
0
            break;
141
142
        /* Skip to next match if the match length cannot increase or if the match length is
143
         * less than 2. Note that the checks below for insufficient lookahead only occur
144
         * occasionally for performance reasons.
145
         * Therefore uninitialized memory will be accessed and conditional jumps will be made
146
         * that depend on those values. However the length of the match is limited to the
147
         * lookahead, so the output of deflate is not affected by the uninitialized values.
148
         */
149
73.7M
        uint32_t len;
150
73.7M
        if (best_len < sizeof(uint64_t)) {
151
72.7M
            uint64_t cand_start = zng_memread_8(mbase_start + cur_match);
152
72.7M
            if (scan_start != cand_start) {
153
                /* Peel the first candidate out of the loop. A full 8-byte match falls straight
154
                 * through to compare256, and single-candidate chains (barely-compressible data)
155
                 * run with no loop overhead. */
156
72.3M
                uint64_t first_mask = zng_first_bytes_mask64(best_len + 1);
157
72.3M
                uint64_t diff = scan_start ^ cand_start;
158
                /* A candidate beats best_len only when its first best_len+1 bytes match, i.e.
159
                 * those bytes of the XOR are zero. The masked test rejects without running ctz. */
160
72.3M
                if (UNLIKELY((diff & first_mask) == 0)) {
161
3.57M
                    len = zng_first_diff_byte64(diff);
162
3.57M
                    goto short_match_accept;
163
3.57M
                }
164
68.8M
                if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
165
51.6M
                    return best_len;
166
17.1M
                cand_start = zng_memread_8(mbase_start + cur_match);
167
17.1M
                if (scan_start != cand_start) {
168
                    /* Walk the remaining candidates with the chain advance kept inline. */
169
45.7M
                    for (;;) {
170
45.7M
                        diff = scan_start ^ cand_start;
171
45.7M
                        if (UNLIKELY((diff & first_mask) == 0)) {
172
482k
                            len = zng_first_diff_byte64(diff);
173
482k
                            goto short_match_accept;
174
482k
                        }
175
45.3M
                        if (--chain_length == 0 || (cur_match = prev[cur_match & wmask]) <= limit)
176
16.6M
                            return best_len;
177
28.7M
                        cand_start = zng_memread_8(mbase_start + cur_match);
178
28.7M
                        if (scan_start == cand_start)
179
42.9k
                            break;
180
28.7M
                    }
181
17.1M
                }
182
17.1M
            }
183
            /* All 8 bytes match, fallthrough to compare256 for the tail. */
184
72.7M
        } else {
185
            /* Pre-filter the candidate on the start and end sentinels before compare256 using
186
             * simple 8-byte comparison since best_len >= 8. */
187
11.5M
            for (;;) {
188
                /* First check the end of the candidate at best_len+1 due to the higher
189
                 * likelihood of a mismatch. */
190
11.5M
                if (zng_memcmp_8(mbase_end+cur_match, &scan_end) == 0 &&
191
877k
                    zng_memcmp_8(mbase_start+cur_match, &scan_start) == 0)
192
771k
                    break;
193
10.8M
                GOTO_NEXT_CHAIN;
194
10.8M
            }
195
1.02M
        }
196
197
1.17M
        len = COMPARE256(scan+2, mbase_start+cur_match+2) + 2;
198
1.17M
        Assert(scan+len <= window+(unsigned)(s->window_size-1), "wild scan");
199
200
1.17M
        if (len > best_len)
201
6.07M
short_match_accept:
202
6.07M
        {
203
6.07M
            uint32_t match_start = cur_match - match_offset;
204
6.07M
            s->match_start = match_start;
205
206
            /* Do not look for better matches if the current match reaches
207
             * or exceeds the end of the input.
208
             */
209
6.07M
            if (UNLIKELY(len >= lookahead))
210
1.56k
                return lookahead;
211
5.06M
            if (UNLIKELY(len >= nice_match))
212
59.2k
                return len;
213
214
5.00M
            best_len = len;
215
216
5.00M
            offset = best_len >= sizeof(uint64_t) ? best_len - 7 : 0;
217
218
5.00M
            scan_end = zng_memread_8(scan+offset);
219
220
#ifdef LONGEST_MATCH_SLOW
221
            /* Look for a better string offset */
222
            if (UNLIKELY(offset_search && len > STD_MIN_MATCH && match_start + len < strstart)) {
223
                const unsigned char *scan_endstr;
224
                uint32_t hash;
225
                uint32_t pos, next_pos;
226
227
                /* Go back to offset 0 */
228
                cur_match -= match_offset;
229
                match_offset = 0;
230
                next_pos = cur_match;
231
232
                /* Walk prev[] for positions inside the match. The bound keeps
233
                 * the hash window within the match, so we follow chains that
234
                 * share bytes with the current match, not data past its end.
235
                 */
236
#  ifdef LONGEST_MATCH_SLOW_ROLL
237
                for (uint32_t i = 0; i <= len - STD_MIN_MATCH; i++) {
238
#  else /* 4-byte Knuth hash needs len - 4 bound */
239
                for (uint32_t i = 0; i <= len - WANT_MIN_MATCH; i++) {
240
#  endif
241
                    pos = prev[(cur_match + i) & wmask];
242
                    if (UNLIKELY(pos < next_pos)) {
243
                        /* Hash chain is more distant, use it */
244
                        if (UNLIKELY(pos <= limit_base + i))
245
                            return best_len;
246
                        next_pos = pos;
247
                        match_offset = i;
248
                    }
249
                }
250
                /* Switch cur_match to next_pos chain */
251
                cur_match = next_pos;
252
253
                /* Try hash head at a window covering the tail of the current
254
                 * match to find chains that extend farther back. The window
255
                 * width differs per variant: 3 bytes for rolling, 4 for Knuth.
256
                 */
257
#  ifdef LONGEST_MATCH_SLOW_ROLL
258
                scan_endstr = scan + len - (STD_MIN_MATCH-1);
259
260
                hash = update_hash_roll(0, scan_endstr[0]);
261
                hash = update_hash_roll(hash, scan_endstr[1]);
262
                hash = update_hash_roll(hash, scan_endstr[2]);
263
264
                pos = head[hash];
265
                if (UNLIKELY(pos < cur_match)) {
266
                    match_offset = len - (STD_MIN_MATCH-1);
267
                    if (pos <= limit_base + match_offset)
268
                        return best_len;
269
                    cur_match = pos;
270
                }
271
#  else
272
                scan_endstr = scan + len - WANT_MIN_MATCH;
273
                uint32_t val = Z_U32_FROM_LE(zng_memread_4(scan_endstr));
274
                UPDATE_HASH_KNUTH(hash, val);
275
276
                pos = head[hash];
277
                if (pos < cur_match) {
278
                    match_offset = len - WANT_MIN_MATCH;
279
                    if (pos <= limit_base + match_offset)
280
                        return best_len;
281
                    cur_match = pos;
282
                }
283
#  endif
284
285
                /* Update offset-dependent variables */
286
                limit = limit_base+match_offset;
287
                mbase_start = window-match_offset;
288
                mbase_end = (mbase_start+offset);
289
                continue;
290
            }
291
#endif
292
5.00M
            mbase_end = (mbase_start+offset);
293
5.00M
        }
294
5.17M
        GOTO_NEXT_CHAIN;
295
5.17M
    }
296
0
    return best_len;
297
69.8M
}
Unexecuted instantiation: longest_match_slow_knuth_avx2
Unexecuted instantiation: longest_match_slow_roll_avx2
Unexecuted instantiation: longest_match_avx512
Unexecuted instantiation: longest_match_slow_knuth_avx512
Unexecuted instantiation: longest_match_slow_roll_avx512
298
299
#undef LONGEST_MATCH_SLOW
300
#undef LONGEST_MATCH_SLOW_ROLL
301
#undef LONGEST_MATCH