/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 |