Coverage Report

Created: 2026-09-13 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zlib-ng/arch/x86/compare256_sse2.c
Line
Count
Source
1
/* compare256_sse2.c -- SSE2 version of compare256
2
 * Copyright Adam Stylinski <kungfujesus06@gmail.com>
3
 * For conditions of distribution and use, see copyright notice in zlib.h
4
 */
5
6
#include "zbuild.h"
7
#include "zendian.h"
8
#include "zmemory.h"
9
#include "deflate.h"
10
#include "fallback_builtins.h"
11
12
#ifdef X86_SSE2
13
14
#include <emmintrin.h>
15
16
0
Z_FORCEINLINE static uint32_t compare256_sse2_static(const uint8_t *src0, const uint8_t *src1) {
17
0
    __m128i xmm_src0, xmm_src1, xmm_cmp;
18
19
    /* Do the first load unaligned, than all subsequent ones we have at least
20
     * one aligned load. Sadly aligning both loads is probably unrealistic */
21
0
    xmm_src0 = _mm_loadu_si128((__m128i*)src0);
22
0
    xmm_src1 = _mm_loadu_si128((__m128i*)src1);
23
0
    xmm_cmp = _mm_cmpeq_epi8(xmm_src0, xmm_src1);
24
25
0
    unsigned mask = (unsigned)_mm_movemask_epi8(xmm_cmp);
26
27
    /* Compiler _may_ turn this branch into a ptest + movemask,
28
     * since a lot of those uops are shared and fused */
29
0
    if (mask != 0xFFFF)
30
0
        return zng_ctz32(~mask);
31
32
0
    const uint8_t *last0 = src0 + 240;
33
0
    const uint8_t *last1 = src1 + 240;
34
35
0
    int align_offset = ((uintptr_t)src0) & 15;
36
0
    int align_adv = 16 - align_offset;
37
0
    uint32_t len = align_adv;
38
39
0
    src0 += align_adv;
40
0
    src1 += align_adv;
41
42
0
    for (int i = 0; i < 15; ++i) {
43
0
        xmm_src0 = _mm_load_si128((__m128i*)src0);
44
0
        xmm_src1 = _mm_loadu_si128((__m128i*)src1);
45
0
        xmm_cmp = _mm_cmpeq_epi8(xmm_src0, xmm_src1);
46
47
0
        mask = (unsigned)_mm_movemask_epi8(xmm_cmp);
48
49
        /* Compiler _may_ turn this branch into a ptest + movemask,
50
         * since a lot of those uops are shared and fused */
51
0
        if (mask != 0xFFFF)
52
0
            return len + zng_ctz32(~mask);
53
54
0
        len += 16, src0 += 16, src1 += 16;
55
0
    }
56
57
0
    if (align_offset) {
58
0
        xmm_src0 = _mm_loadu_si128((__m128i*)last0);
59
0
        xmm_src1 = _mm_loadu_si128((__m128i*)last1);
60
0
        xmm_cmp = _mm_cmpeq_epi8(xmm_src0, xmm_src1);
61
62
0
        mask = (unsigned)_mm_movemask_epi8(xmm_cmp);
63
64
0
        if (mask != 0xFFFF)
65
0
            return 240 + zng_ctz32(~mask);
66
0
    }
67
68
0
    return 256;
69
0
}
70
71
0
Z_INTERNAL uint32_t compare256_sse2(const uint8_t *src0, const uint8_t *src1) {
72
0
    return compare256_sse2_static(src0, src1);
73
0
}
74
75
#define LONGEST_MATCH       longest_match_sse2
76
0
#define COMPARE256          compare256_sse2_static
77
78
#include "match_tpl.h"
79
80
#define LONGEST_MATCH_SLOW
81
#define LONGEST_MATCH       longest_match_slow_knuth_sse2
82
0
#define COMPARE256          compare256_sse2_static
83
84
#include "match_tpl.h"
85
86
#define LONGEST_MATCH_SLOW
87
#define LONGEST_MATCH_SLOW_ROLL
88
#define LONGEST_MATCH       longest_match_slow_roll_sse2
89
0
#define COMPARE256          compare256_sse2_static
90
91
#include "match_tpl.h"
92
93
#endif