1 /* compare258.c -- aligned and unaligned versions of compare258
2 * Copyright (C) 2020 Nathan Moinvaziri
3 * For conditions of distribution and use, see copyright notice in zlib.h
4 */
5
6 #include "zbuild.h"
7 #include "zutil.h"
8
9 #include "fallback_builtins.h"
10
11 /* ALIGNED, byte comparison */
compare256_c_static(const unsigned char * src0,const unsigned char * src1)12 static inline uint32_t compare256_c_static(const unsigned char *src0, const unsigned char *src1) {
13 uint32_t len = 0;
14
15 do {
16 if (*src0 != *src1)
17 return len + (*src0 == *src1);
18 src0 += 1, src1 += 1, len += 1;
19 if (*src0 != *src1)
20 return len + (*src0 == *src1);
21 src0 += 1, src1 += 1, len += 1;
22 if (*src0 != *src1)
23 return len + (*src0 == *src1);
24 src0 += 1, src1 += 1, len += 1;
25 if (*src0 != *src1)
26 return len + (*src0 == *src1);
27 src0 += 1, src1 += 1, len += 1;
28 if (*src0 != *src1)
29 return len + (*src0 == *src1);
30 src0 += 1, src1 += 1, len += 1;
31 if (*src0 != *src1)
32 return len + (*src0 == *src1);
33 src0 += 1, src1 += 1, len += 1;
34 if (*src0 != *src1)
35 return len + (*src0 == *src1);
36 src0 += 1, src1 += 1, len += 1;
37 if (*src0 != *src1)
38 return len + (*src0 == *src1);
39 src0 += 1, src1 += 1, len += 1;
40 } while (len < 256);
41
42 return 256;
43 }
44
compare258_c_static(const unsigned char * src0,const unsigned char * src1)45 static inline uint32_t compare258_c_static(const unsigned char *src0, const unsigned char *src1) {
46 if (*src0 != *src1)
47 return 0;
48 src0 += 1, src1 += 1;
49 if (*src0 != *src1)
50 return 1;
51 src0 += 1, src1 += 1;
52
53 return compare256_c_static(src0, src1) + 2;
54 }
55
compare258_c(const unsigned char * src0,const unsigned char * src1)56 Z_INTERNAL uint32_t compare258_c(const unsigned char *src0, const unsigned char *src1) {
57 return compare258_c_static(src0, src1);
58 }
59
60 #define LONGEST_MATCH longest_match_c
61 #define COMPARE256 compare256_c_static
62 #define COMPARE258 compare258_c_static
63
64 #include "match_tpl.h"
65
66 #ifdef UNALIGNED_OK
67 /* UNALIGNED_OK, 16-bit integer comparison */
compare256_unaligned_16_static(const unsigned char * src0,const unsigned char * src1)68 static inline uint32_t compare256_unaligned_16_static(const unsigned char *src0, const unsigned char *src1) {
69 uint32_t len = 0;
70
71 do {
72 if (*(uint16_t *)src0 != *(uint16_t *)src1)
73 return len + (*src0 == *src1);
74 src0 += 2, src1 += 2, len += 2;
75 if (*(uint16_t *)src0 != *(uint16_t *)src1)
76 return len + (*src0 == *src1);
77 src0 += 2, src1 += 2, len += 2;
78 if (*(uint16_t *)src0 != *(uint16_t *)src1)
79 return len + (*src0 == *src1);
80 src0 += 2, src1 += 2, len += 2;
81 if (*(uint16_t *)src0 != *(uint16_t *)src1)
82 return len + (*src0 == *src1);
83 src0 += 2, src1 += 2, len += 2;
84 } while (len < 256);
85
86 return 256;
87 }
88
compare258_unaligned_16_static(const unsigned char * src0,const unsigned char * src1)89 static inline uint32_t compare258_unaligned_16_static(const unsigned char *src0, const unsigned char *src1) {
90 if (*(uint16_t *)src0 != *(uint16_t *)src1)
91 return (*src0 == *src1);
92
93 return compare256_unaligned_16_static(src0+2, src1+2) + 2;
94 }
95
compare258_unaligned_16(const unsigned char * src0,const unsigned char * src1)96 Z_INTERNAL uint32_t compare258_unaligned_16(const unsigned char *src0, const unsigned char *src1) {
97 return compare258_unaligned_16_static(src0, src1);
98 }
99
100 #define LONGEST_MATCH longest_match_unaligned_16
101 #define COMPARE256 compare256_unaligned_16_static
102 #define COMPARE258 compare258_unaligned_16_static
103
104 #include "match_tpl.h"
105
106 #ifdef HAVE_BUILTIN_CTZ
107 /* UNALIGNED_OK, 32-bit integer comparison */
compare256_unaligned_32_static(const unsigned char * src0,const unsigned char * src1)108 static inline uint32_t compare256_unaligned_32_static(const unsigned char *src0, const unsigned char *src1) {
109 uint32_t len = 0;
110
111 do {
112 uint32_t sv = *(uint32_t *)src0;
113 uint32_t mv = *(uint32_t *)src1;
114 uint32_t diff = sv ^ mv;
115
116 if (diff) {
117 uint32_t match_byte = __builtin_ctz(diff) / 8;
118 return len + match_byte;
119 }
120
121 src0 += 4, src1 += 4, len += 4;
122 } while (len < 256);
123
124 return 256;
125 }
126
compare258_unaligned_32_static(const unsigned char * src0,const unsigned char * src1)127 static inline uint32_t compare258_unaligned_32_static(const unsigned char *src0, const unsigned char *src1) {
128 if (*(uint16_t *)src0 != *(uint16_t *)src1)
129 return (*src0 == *src1);
130
131 return compare256_unaligned_32_static(src0+2, src1+2) + 2;
132 }
133
compare258_unaligned_32(const unsigned char * src0,const unsigned char * src1)134 Z_INTERNAL uint32_t compare258_unaligned_32(const unsigned char *src0, const unsigned char *src1) {
135 return compare258_unaligned_32_static(src0, src1);
136 }
137
138 #define LONGEST_MATCH longest_match_unaligned_32
139 #define COMPARE256 compare256_unaligned_32_static
140 #define COMPARE258 compare258_unaligned_32_static
141
142 #include "match_tpl.h"
143
144 #endif
145
146 #if defined(UNALIGNED64_OK) && defined(HAVE_BUILTIN_CTZLL)
147 /* UNALIGNED64_OK, 64-bit integer comparison */
compare256_unaligned_64_static(const unsigned char * src0,const unsigned char * src1)148 static inline uint32_t compare256_unaligned_64_static(const unsigned char *src0, const unsigned char *src1) {
149 uint32_t len = 0;
150
151 do {
152 uint64_t sv = *(uint64_t *)src0;
153 uint64_t mv = *(uint64_t *)src1;
154 uint64_t diff = sv ^ mv;
155
156 if (diff) {
157 uint64_t match_byte = __builtin_ctzll(diff) / 8;
158 return len + match_byte;
159 }
160
161 src0 += 8, src1 += 8, len += 8;
162 } while (len < 256);
163
164 return 256;
165 }
166
compare258_unaligned_64_static(const unsigned char * src0,const unsigned char * src1)167 static inline uint32_t compare258_unaligned_64_static(const unsigned char *src0, const unsigned char *src1) {
168 if (*(uint16_t *)src0 != *(uint16_t *)src1)
169 return (*src0 == *src1);
170
171 return compare256_unaligned_64_static(src0+2, src1+2) + 2;
172 }
173
compare258_unaligned_64(const unsigned char * src0,const unsigned char * src1)174 Z_INTERNAL uint32_t compare258_unaligned_64(const unsigned char *src0, const unsigned char *src1) {
175 return compare258_unaligned_64_static(src0, src1);
176 }
177
178 #define LONGEST_MATCH longest_match_unaligned_64
179 #define COMPARE256 compare256_unaligned_64_static
180 #define COMPARE258 compare258_unaligned_64_static
181
182 #include "match_tpl.h"
183
184 #endif
185
186 #endif
187