Coverage Report

Created: 2026-09-13 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zlib-ng/functable.c
Line
Count
Source
1
/* functable.c -- Choose relevant optimized functions at runtime
2
 * Copyright (C) 2017 Hans Kristian Rosbach
3
 * For conditions of distribution and use, see copyright notice in zlib.h
4
 */
5
#ifndef DISABLE_RUNTIME_CPU_DETECTION
6
7
#include "zbuild.h"
8
9
#if defined(_MSC_VER)
10
#  include <intrin.h>
11
#endif
12
13
#include "functable.h"
14
#include "cpu_features.h"
15
#include "arch_functions.h"
16
17
/* Platform has pointer size atomic store */
18
#if defined(__GNUC__) || defined(__clang__)
19
#  define FUNCTABLE_ASSIGN(VAR, FUNC_NAME) \
20
26
    __atomic_store(&(functable.FUNC_NAME), &(VAR.FUNC_NAME), __ATOMIC_SEQ_CST)
21
2
#  define FUNCTABLE_BARRIER() __atomic_thread_fence(__ATOMIC_SEQ_CST)
22
#elif defined(_MSC_VER)
23
#  define FUNCTABLE_ASSIGN(VAR, FUNC_NAME) \
24
    _InterlockedExchangePointer((void * volatile *)&(functable.FUNC_NAME), (void *)(VAR.FUNC_NAME))
25
#  ifdef ARCH_ARM
26
#    define FUNCTABLE_BARRIER() do { \
27
    _ReadWriteBarrier();  \
28
    __dmb(0xB); /* _ARM_BARRIER_ISH */ \
29
    _ReadWriteBarrier(); \
30
} while (0)
31
#  else
32
#    define FUNCTABLE_BARRIER() _ReadWriteBarrier()
33
#  endif
34
#else
35
#  warning Unable to detect atomic intrinsic support.
36
#  define FUNCTABLE_ASSIGN(VAR, FUNC_NAME) \
37
    *((void * volatile *)&(functable.FUNC_NAME)) = (void *)(VAR.FUNC_NAME)
38
#  define FUNCTABLE_BARRIER() do { /* Empty */ } while (0)
39
#endif
40
41
/* Verify all pointers are valid before assigning, return 1 on failure
42
 * This allows inflateinit/deflateinit functions to gracefully return Z_VERSION_ERROR
43
 * if functable initialization fails.
44
 */
45
#define FUNCTABLE_VERIFY_ASSIGN(VAR, FUNC_NAME) \
46
24
    if (!VAR.FUNC_NAME) { \
47
0
        fprintf(stderr, "Zlib-ng functable failed initialization!\n"); \
48
0
        return 1; \
49
0
    } \
50
24
    FUNCTABLE_ASSIGN(VAR, FUNC_NAME);
51
52
/* Functable init & abort on failure.
53
 * Abort is needed because some stub functions are reachable without first
54
 * calling any inflateinit/deflateinit functions, and have no error propagation.
55
 */
56
#define FUNCTABLE_INIT_ABORT \
57
2
    if (init_functable()) { \
58
0
        fprintf(stderr, "Zlib-ng functable failed initialization!\n"); \
59
0
        abort(); \
60
2
    };
61
62
// Empty stub, used when functable has already been initialized
63
25.6k
static int force_init_empty(void) {
64
25.6k
    return 0;
65
25.6k
}
66
67
/* Functable initialization.
68
 * Selects the best available optimized functions appropriate for the runtime cpu.
69
 */
70
2
static int init_functable(void) {
71
2
    struct functable_s ft;
72
2
    struct cpu_features cf;
73
74
2
    memset(&ft, 0, sizeof(struct functable_s));
75
2
    cpu_check_features(&cf);
76
2
    ft.force_init = &force_init_empty;
77
78
    // Only use necessary generic functions when no suitable simd versions are available.
79
2
#ifdef ADLER32_FALLBACK
80
2
    ft.adler32 = &adler32_c;
81
2
    ft.adler32_copy = &adler32_copy_c;
82
2
#endif
83
#ifdef CHUNKSET_FALLBACK
84
    ft.chunkmemset_safe = &chunkmemset_safe_c;
85
    ft.inflate_fast = &inflate_fast_c;
86
#endif
87
#ifdef COMPARE256_FALLBACK
88
    ft.compare256 = &compare256_c;
89
    ft.longest_match = &longest_match_c;
90
    ft.longest_match_slow_knuth = &longest_match_slow_knuth_c;
91
    ft.longest_match_slow_roll = &longest_match_slow_roll_c;
92
#endif
93
2
#ifdef CRC32_BRAID_FALLBACK
94
2
    ft.crc32 = &crc32_braid;
95
2
    ft.crc32_copy = &crc32_copy_braid;
96
2
#endif
97
#ifdef SLIDE_HASH_FALLBACK
98
    ft.slide_hash = &slide_hash_c;
99
    ft.slide_hash_head = &slide_hash_head_c;
100
#endif
101
102
    // Select arch-optimized functions
103
2
#ifdef WITH_OPTIM
104
105
    // Chorba generic C fallback
106
2
#ifdef CRC32_CHORBA_FALLBACK
107
2
    ft.crc32 = &crc32_chorba;
108
2
    ft.crc32_copy = &crc32_copy_chorba;
109
2
#endif
110
111
    // X86 - SSE2
112
2
#ifdef X86_SSE2
113
#  ifndef X86_SSE2_NATIVE
114
    if (cf.x86.has_sse2)
115
#  endif
116
2
    {
117
2
#  ifndef X86_AVX2_NATIVE
118
2
        ft.chunkmemset_safe = &chunkmemset_safe_sse2;
119
2
        ft.compare256 = &compare256_sse2;
120
2
        ft.inflate_fast = &inflate_fast_sse2;
121
2
        ft.longest_match = &longest_match_sse2;
122
2
        ft.longest_match_slow_knuth = &longest_match_slow_knuth_sse2;
123
2
        ft.longest_match_slow_roll = &longest_match_slow_roll_sse2;
124
2
        ft.slide_hash = &slide_hash_sse2;
125
2
        ft.slide_hash_head = &slide_hash_head_sse2;
126
2
#  endif
127
2
#  if defined(CRC32_CHORBA_SSE_FALLBACK) && !defined(X86_SSE41_NATIVE) && !defined(X86_PCLMULQDQ_NATIVE)
128
2
        ft.crc32 = &crc32_chorba_sse2;
129
2
        ft.crc32_copy = &crc32_copy_chorba_sse2;
130
2
#  endif
131
2
    }
132
2
#endif
133
    // X86 - SSSE3
134
2
#ifdef X86_SSSE3
135
2
#  ifndef X86_SSSE3_NATIVE
136
2
    if (cf.x86.has_ssse3)
137
2
#  endif
138
2
    {
139
2
        ft.adler32 = &adler32_ssse3;
140
2
        ft.adler32_copy = &adler32_copy_ssse3;
141
2
#  ifndef X86_AVX2_NATIVE
142
2
        ft.chunkmemset_safe = &chunkmemset_safe_ssse3;
143
2
        ft.inflate_fast = &inflate_fast_ssse3;
144
2
#  endif
145
2
    }
146
2
#endif
147
148
    // X86 - SSE4.1
149
2
#if defined(X86_SSE41) && !defined(X86_PCLMULQDQ_NATIVE)
150
2
#  ifndef X86_SSE41_NATIVE
151
2
    if (cf.x86.has_sse41)
152
2
#  endif
153
2
    {
154
2
#  ifdef CRC32_CHORBA_SSE_FALLBACK
155
2
        ft.crc32 = &crc32_chorba_sse41;
156
2
        ft.crc32_copy = &crc32_copy_chorba_sse41;
157
2
#  endif
158
2
    }
159
2
#endif
160
161
    // X86 - SSE4.2
162
2
#if defined(X86_SSE42) && !defined(X86_AVX512_NATIVE)
163
2
#  ifndef X86_SSE42_NATIVE
164
2
    if (cf.x86.has_sse42)
165
2
#  endif
166
2
    {
167
2
        ft.adler32_copy = &adler32_copy_sse42;
168
2
    }
169
2
#endif
170
    // X86 - PCLMUL
171
2
#if defined(X86_PCLMULQDQ_CRC) && !defined(X86_VPCLMULQDQ_NATIVE)
172
2
#  ifndef X86_PCLMULQDQ_NATIVE
173
2
    if (cf.x86.has_pclmulqdq)
174
2
#  endif
175
2
    {
176
2
        ft.crc32 = &crc32_pclmulqdq;
177
2
        ft.crc32_copy = &crc32_copy_pclmulqdq;
178
2
    }
179
2
#endif
180
    // X86 - AVX2
181
2
#ifdef X86_AVX2
182
    /* BMI2 support is all but implicit with AVX2 but let's sanity check this just in case. Enabling BMI2 allows for
183
     * flagless shifts, resulting in fewer flag stalls for the pipeline, and allows us to set destination registers
184
     * for the shift results as an operand, eliminating several register-register moves when the original value needs
185
     * to remain intact. They also allow for a count operand that isn't the CL register, avoiding contention there */
186
2
#  ifndef X86_AVX2_NATIVE
187
2
    if (cf.x86.has_avx2 && cf.x86.has_bmi2)
188
2
#  endif
189
2
    {
190
2
#  ifndef X86_AVX512_NATIVE
191
2
        ft.adler32 = &adler32_avx2;
192
2
        ft.adler32_copy = &adler32_copy_avx2;
193
2
        ft.chunkmemset_safe = &chunkmemset_safe_avx2;
194
2
        ft.compare256 = &compare256_avx2;
195
2
        ft.inflate_fast = &inflate_fast_avx2;
196
2
        ft.longest_match = &longest_match_avx2;
197
2
        ft.longest_match_slow_knuth = &longest_match_slow_knuth_avx2;
198
2
        ft.longest_match_slow_roll = &longest_match_slow_roll_avx2;
199
2
#  endif
200
2
        ft.slide_hash = &slide_hash_avx2;
201
2
        ft.slide_hash_head = &slide_hash_head_avx2;
202
2
    }
203
2
#endif
204
2
#ifdef X86_AVX2VNNI
205
2
    if (cf.x86.has_avx2vnni) {
206
0
        ft.adler32 = &adler32_avx2_vnni;
207
        //ft.adler32_copy = &adler32_copy_avx2_vnni;
208
0
    }
209
2
#endif
210
    // X86 - AVX512 (F,DQ,BW,Vl)
211
2
#ifdef X86_AVX512
212
2
#  ifndef X86_AVX512_NATIVE
213
2
    if (cf.x86.has_avx512_common)
214
0
#  endif
215
0
    {
216
0
#  ifndef X86_AVX512VNNI_NATIVE
217
0
        ft.adler32 = &adler32_avx512;
218
0
        ft.adler32_copy = &adler32_copy_avx512;
219
0
#  endif
220
0
        ft.chunkmemset_safe = &chunkmemset_safe_avx512;
221
0
        ft.compare256 = &compare256_avx512;
222
0
        ft.inflate_fast = &inflate_fast_avx512;
223
0
        ft.longest_match = &longest_match_avx512;
224
0
        ft.longest_match_slow_knuth = &longest_match_slow_knuth_avx512;
225
0
        ft.longest_match_slow_roll = &longest_match_slow_roll_avx512;
226
0
    }
227
2
#endif
228
2
#ifdef X86_AVX512VNNI
229
2
#  ifndef X86_AVX512VNNI_NATIVE
230
2
    if (cf.x86.has_avx512vnni)
231
0
#  endif
232
0
    {
233
0
        ft.adler32 = &adler32_avx512_vnni;
234
0
        ft.adler32_copy = &adler32_copy_avx512_vnni;
235
0
    }
236
2
#endif
237
    // X86 - VPCLMULQDQ (AVX2)
238
2
#ifdef X86_VPCLMULQDQ_AVX2
239
2
#  ifndef X86_VPCLMULQDQ_AVX2_NATIVE
240
2
    if (cf.x86.has_pclmulqdq && cf.x86.has_avx2 && cf.x86.has_vpclmulqdq)
241
0
#  endif
242
0
    {
243
0
        ft.crc32 = &crc32_vpclmulqdq_avx2;
244
0
        ft.crc32_copy = &crc32_copy_vpclmulqdq_avx2;
245
0
    }
246
2
#endif
247
    // X86 - VPCLMULQDQ (AVX-512)
248
2
#ifdef X86_VPCLMULQDQ_AVX512
249
2
#  ifndef X86_VPCLMULQDQ_AVX512_NATIVE
250
2
    if (cf.x86.has_pclmulqdq && cf.x86.has_avx512_common && cf.x86.has_vpclmulqdq)
251
0
#  endif
252
0
    {
253
0
        ft.crc32 = &crc32_vpclmulqdq_avx512;
254
0
        ft.crc32_copy = &crc32_copy_vpclmulqdq_avx512;
255
0
    }
256
2
#endif
257
258
259
    // ARM - SIMD
260
#if defined(ARM_SIMD) && !defined(ARM_NEON_NATIVE)
261
#  ifndef ARM_SIMD_NATIVE
262
    if (cf.arm.has_simd)
263
#  endif
264
    {
265
        ft.slide_hash = &slide_hash_armv6;
266
        ft.slide_hash_head = &slide_hash_head_armv6;
267
    }
268
#endif
269
    // ARM - NEON
270
#ifdef ARM_NEON
271
#  ifndef ARM_NEON_NATIVE
272
    if (cf.arm.has_neon)
273
#  endif
274
    {
275
        ft.adler32 = &adler32_neon;
276
        ft.adler32_copy = &adler32_copy_neon;
277
        ft.chunkmemset_safe = &chunkmemset_safe_neon;
278
        ft.compare256 = &compare256_neon;
279
        ft.inflate_fast = &inflate_fast_neon;
280
        ft.longest_match = &longest_match_neon;
281
        ft.longest_match_slow_knuth = &longest_match_slow_knuth_neon;
282
        ft.longest_match_slow_roll = &longest_match_slow_roll_neon;
283
        ft.slide_hash = &slide_hash_neon;
284
        ft.slide_hash_head = &slide_hash_head_neon;
285
    }
286
#endif
287
    // ARM - NEON DotProd
288
#ifdef ARM_NEON_DOTPROD
289
#  ifndef ARM_NEON_DOTPROD_NATIVE
290
    if (cf.arm.has_neon && cf.arm.has_dotprod)
291
#  endif
292
    {
293
        ft.adler32 = &adler32_neon_dotprod;
294
        ft.adler32_copy = &adler32_copy_neon_dotprod;
295
    }
296
#endif
297
    // ARM - CRC32
298
#if defined(ARM_CRC32) && !defined(ARM_PMULL_EOR3_NATIVE)
299
#  ifndef ARM_CRC32_NATIVE
300
    if (cf.arm.has_crc32)
301
#  endif
302
    {
303
        ft.crc32 = &crc32_armv8;
304
        ft.crc32_copy = &crc32_copy_armv8;
305
    }
306
#endif
307
    // ARM - PMULL EOR3
308
#ifdef ARM_PMULL_EOR3
309
#  ifndef ARM_PMULL_EOR3_NATIVE
310
    if (cf.arm.has_crc32 && cf.arm.has_pmull && cf.arm.has_eor3 && cf.arm.has_fast_pmull)
311
#  endif
312
    {
313
        ft.crc32 = &crc32_armv8_pmull_eor3;
314
        ft.crc32_copy = &crc32_copy_armv8_pmull_eor3;
315
    }
316
#endif
317
318
    // Power - VMX
319
#ifdef PPC_VMX
320
#  ifndef PPC_VMX_NATIVE
321
    if (cf.power.has_altivec)
322
#  endif
323
    {
324
        ft.adler32 = &adler32_vmx;
325
        ft.adler32_copy = &adler32_copy_vmx;
326
        ft.slide_hash = &slide_hash_vmx;
327
        ft.slide_hash_head = &slide_hash_head_vmx;
328
    }
329
#endif
330
    // Power8 - VSX
331
#ifdef POWER8_VSX
332
#  ifndef POWER8_VSX_NATIVE
333
    if (cf.power.has_arch_2_07)
334
#  endif
335
    {
336
        ft.adler32 = &adler32_power8;
337
        ft.adler32_copy = &adler32_copy_power8;
338
        ft.chunkmemset_safe = &chunkmemset_safe_power8;
339
        ft.inflate_fast = &inflate_fast_power8;
340
        ft.slide_hash = &slide_hash_power8;
341
        ft.slide_hash_head = &slide_hash_head_power8;
342
    }
343
#endif
344
#ifdef POWER8_VSX_CRC32
345
#  ifndef POWER8_VSX_CRC32_NATIVE
346
    if (cf.power.has_arch_2_07)
347
#  endif
348
    {
349
        ft.crc32 = &crc32_power8;
350
        ft.crc32_copy = &crc32_copy_power8;
351
    }
352
#endif
353
    // Power9
354
#ifdef POWER9
355
#  ifndef POWER9_NATIVE
356
    if (cf.power.has_arch_3_00)
357
#  endif
358
    {
359
        ft.compare256 = &compare256_power9;
360
        ft.longest_match = &longest_match_power9;
361
        ft.longest_match_slow_knuth = &longest_match_slow_knuth_power9;
362
        ft.longest_match_slow_roll = &longest_match_slow_roll_power9;
363
    }
364
#endif
365
366
367
    // RISCV - RVV
368
#ifdef RISCV_RVV
369
#  ifndef RISCV_RVV_NATIVE
370
    if (cf.riscv.has_rvv)
371
#  endif
372
    {
373
        ft.adler32 = &adler32_rvv;
374
        ft.adler32_copy = &adler32_copy_rvv;
375
        ft.chunkmemset_safe = &chunkmemset_safe_rvv;
376
        ft.compare256 = &compare256_rvv;
377
        ft.inflate_fast = &inflate_fast_rvv;
378
        ft.longest_match = &longest_match_rvv;
379
        ft.longest_match_slow_knuth = &longest_match_slow_knuth_rvv;
380
        ft.longest_match_slow_roll = &longest_match_slow_roll_rvv;
381
        ft.slide_hash = &slide_hash_rvv;
382
        ft.slide_hash_head = &slide_hash_head_rvv;
383
    }
384
#endif
385
386
    // RISCV - ZBC
387
#ifdef RISCV_CRC32_ZBC
388
#  ifndef RISCV_ZBC_NATIVE
389
    if (cf.riscv.has_zbc)
390
#  endif
391
    {
392
        ft.crc32 = &crc32_riscv64_zbc;
393
        ft.crc32_copy = &crc32_copy_riscv64_zbc;
394
    }
395
#endif
396
397
    // S390
398
#ifdef S390_VX
399
#  ifndef S390_VX_NATIVE
400
    if (cf.s390.has_vx)
401
#  endif
402
    {
403
        ft.crc32 = &crc32_s390_vx;
404
        ft.crc32_copy = &crc32_copy_s390_vx;
405
        ft.slide_hash = &slide_hash_vx;
406
        ft.slide_hash_head = &slide_hash_head_vx;
407
    }
408
#endif
409
410
    // LOONGARCH
411
#ifdef LOONGARCH_CRC
412
#  ifndef LOONGARCH_CRC_NATIVE
413
    if (cf.loongarch.has_crc)
414
#  endif
415
    {
416
        ft.crc32 = &crc32_loongarch64;
417
        ft.crc32_copy = &crc32_copy_loongarch64;
418
    }
419
#endif
420
#if defined(LOONGARCH_LSX) && !defined(LOONGARCH_LASX_NATIVE)
421
#  ifndef LOONGARCH_LSX_NATIVE
422
    if (cf.loongarch.has_lsx)
423
#  endif
424
    {
425
        ft.adler32 = &adler32_lsx;
426
        ft.adler32_copy = &adler32_copy_lsx;
427
        ft.chunkmemset_safe = &chunkmemset_safe_lsx;
428
        ft.compare256 = &compare256_lsx;
429
        ft.inflate_fast = &inflate_fast_lsx;
430
        ft.longest_match = &longest_match_lsx;
431
        ft.longest_match_slow_knuth = &longest_match_slow_knuth_lsx;
432
        ft.longest_match_slow_roll = &longest_match_slow_roll_lsx;
433
        ft.slide_hash = &slide_hash_lsx;
434
        ft.slide_hash_head = &slide_hash_head_lsx;
435
    }
436
#endif
437
#ifdef LOONGARCH_LASX
438
#  ifndef LOONGARCH_LASX_NATIVE
439
    if (cf.loongarch.has_lasx)
440
#  endif
441
    {
442
        ft.adler32 = &adler32_lasx;
443
        ft.adler32_copy = &adler32_copy_lasx;
444
        ft.chunkmemset_safe = &chunkmemset_safe_lasx;
445
        ft.compare256 = &compare256_lasx;
446
        ft.inflate_fast = &inflate_fast_lasx;
447
        ft.longest_match = &longest_match_lasx;
448
        ft.longest_match_slow_knuth = &longest_match_slow_knuth_lasx;
449
        ft.longest_match_slow_roll = &longest_match_slow_roll_lasx;
450
        ft.slide_hash = &slide_hash_lasx;
451
        ft.slide_hash_head = &slide_hash_head_lasx;
452
    }
453
#endif
454
455
2
#endif // WITH_OPTIM
456
457
    // Assign function pointers individually for atomic operation
458
2
    FUNCTABLE_ASSIGN(ft, force_init);
459
2
    FUNCTABLE_VERIFY_ASSIGN(ft, adler32);
460
2
    FUNCTABLE_VERIFY_ASSIGN(ft, adler32_copy);
461
2
    FUNCTABLE_VERIFY_ASSIGN(ft, chunkmemset_safe);
462
2
    FUNCTABLE_VERIFY_ASSIGN(ft, compare256);
463
2
    FUNCTABLE_VERIFY_ASSIGN(ft, crc32);
464
2
    FUNCTABLE_VERIFY_ASSIGN(ft, crc32_copy);
465
2
    FUNCTABLE_VERIFY_ASSIGN(ft, inflate_fast);
466
2
    FUNCTABLE_VERIFY_ASSIGN(ft, longest_match);
467
2
    FUNCTABLE_VERIFY_ASSIGN(ft, longest_match_slow_knuth);
468
2
    FUNCTABLE_VERIFY_ASSIGN(ft, longest_match_slow_roll);
469
2
    FUNCTABLE_VERIFY_ASSIGN(ft, slide_hash);
470
2
    FUNCTABLE_VERIFY_ASSIGN(ft, slide_hash_head);
471
472
    // Memory barrier for weak memory order CPUs
473
2
    FUNCTABLE_BARRIER();
474
475
2
    return Z_OK;
476
2
}
477
478
#if !defined(_WIN32) && (defined(__GNUC__) || defined(__clang__))
479
2
static void __attribute__((constructor)) functable_constructor(void) {
480
2
    FUNCTABLE_INIT_ABORT;
481
2
}
482
#endif
483
484
/* stub functions */
485
0
static int force_init_stub(void) {
486
0
    return init_functable();
487
0
}
488
489
0
static uint32_t adler32_stub(uint32_t adler, const uint8_t* buf, size_t len) {
490
0
    FUNCTABLE_INIT_ABORT;
491
0
    return functable.adler32(adler, buf, len);
492
0
}
493
494
0
static uint32_t adler32_copy_stub(uint32_t adler, uint8_t* dst, const uint8_t* src, size_t len) {
495
0
    FUNCTABLE_INIT_ABORT;
496
0
    return functable.adler32_copy(adler, dst, src, len);
497
0
}
498
499
0
static uint8_t* chunkmemset_safe_stub(uint8_t* out, uint8_t *from, size_t len, size_t left) {
500
0
    FUNCTABLE_INIT_ABORT;
501
0
    return functable.chunkmemset_safe(out, from, len, left);
502
0
}
503
504
0
static uint32_t compare256_stub(const uint8_t* src0, const uint8_t* src1) {
505
0
    FUNCTABLE_INIT_ABORT;
506
0
    return functable.compare256(src0, src1);
507
0
}
508
509
0
static uint32_t crc32_stub(uint32_t crc, const uint8_t* buf, size_t len) {
510
0
    FUNCTABLE_INIT_ABORT;
511
0
    return functable.crc32(crc, buf, len);
512
0
}
513
514
0
static uint32_t crc32_copy_stub(uint32_t crc, uint8_t *dst, const uint8_t *src, size_t len) {
515
0
    FUNCTABLE_INIT_ABORT;
516
0
    return functable.crc32_copy(crc, dst, src, len);
517
0
}
518
519
0
static void inflate_fast_stub(PREFIX3(stream) *strm, uint32_t start, int safe_mode) {
520
0
    FUNCTABLE_INIT_ABORT;
521
0
    functable.inflate_fast(strm, start, safe_mode);
522
0
}
523
524
0
static uint32_t longest_match_stub(deflate_state* const s, uint32_t cur_match) {
525
0
    FUNCTABLE_INIT_ABORT;
526
0
    return functable.longest_match(s, cur_match);
527
0
}
528
529
0
static uint32_t longest_match_slow_knuth_stub(deflate_state* const s, uint32_t cur_match) {
530
0
    FUNCTABLE_INIT_ABORT;
531
0
    return functable.longest_match_slow_knuth(s, cur_match);
532
0
}
533
534
0
static uint32_t longest_match_slow_roll_stub(deflate_state* const s, uint32_t cur_match) {
535
0
    FUNCTABLE_INIT_ABORT;
536
0
    return functable.longest_match_slow_roll(s, cur_match);
537
0
}
538
539
0
static void slide_hash_stub(deflate_state* s) {
540
0
    FUNCTABLE_INIT_ABORT;
541
0
    functable.slide_hash(s);
542
0
}
543
544
0
static void slide_hash_head_stub(deflate_state *s) {
545
0
    FUNCTABLE_INIT_ABORT;
546
0
    functable.slide_hash_head(s);
547
0
}
548
549
/* functable init */
550
Z_INTERNAL struct functable_s functable = {
551
    force_init_stub,
552
    adler32_stub,
553
    adler32_copy_stub,
554
    chunkmemset_safe_stub,
555
    compare256_stub,
556
    crc32_stub,
557
    crc32_copy_stub,
558
    inflate_fast_stub,
559
    longest_match_stub,
560
    longest_match_slow_knuth_stub,
561
    longest_match_slow_roll_stub,
562
    slide_hash_stub,
563
    slide_hash_head_stub,
564
};
565
566
#endif