Skip to content

Commit c0f99d1

Browse files
Load words with memcpy and finish with one overlapping read
1 parent 1daa7ee commit c0f99d1

1 file changed

Lines changed: 42 additions & 44 deletions

File tree

‎Objects/stringlib/find_max_char.h‎

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -54,48 +54,31 @@
5454

5555
/* OR all characters into a single size_t accumulator and test the high bits
5656
at the end, instead of comparing each character. The accumulation loop has
57-
no branches, so compilers vectorize it, and the result does not depend on
58-
where each byte sits in the word, so unaligned ends can be read in smaller
59-
pieces. Every 16 words, check whether the widest kind is already known and
60-
exit early. */
57+
no branches, so compilers vectorize it. The words are loaded with memcpy,
58+
so the data does not need to be aligned, and the tail re-reads the last
59+
word of the buffer, which may overlap data already seen. Every 16 words,
60+
check whether the widest kind is already known and exit early. */
6161
Py_LOCAL_INLINE(Py_UCS4)
6262
STRINGLIB(find_max_char)(const STRINGLIB_CHAR *begin, const STRINGLIB_CHAR *end)
6363
{
6464
const unsigned char *p = (const unsigned char *)begin;
6565
const unsigned char *_end = (const unsigned char *)end;
66-
6766
size_t value = 0;
6867

69-
if (!_Py_IS_ALIGNED(p, ALIGNOF_SIZE_T)) {
70-
#if STRINGLIB_SIZEOF_CHAR <= 1
71-
if (!_Py_IS_ALIGNED(p, sizeof(uint16_t)) && p + 1 <= _end) {
72-
value |= *p++;
73-
}
74-
#endif
75-
#if STRINGLIB_SIZEOF_CHAR <= 2
76-
if (!_Py_IS_ALIGNED(p, sizeof(uint32_t)) && p + sizeof(uint16_t) <= _end) {
77-
value |= *(const uint16_t*)p;
78-
p += sizeof(uint16_t);
79-
}
80-
#endif
81-
#if SIZEOF_SIZE_T == 8
82-
if (!_Py_IS_ALIGNED(p, SIZEOF_SIZE_T) && p + sizeof(uint32_t) <= _end) {
83-
value |= *(const uint32_t*)p;
84-
p += sizeof(uint32_t);
85-
}
86-
#endif
87-
}
88-
8968
while (p + SIZEOF_SIZE_T * 16 <= _end) {
90-
const size_t *pp = (const size_t *)p;
9169
/* Four independent accumulators so the loop does not serialize on
9270
one register when the compiler does not vectorize it. */
9371
size_t v0 = 0, v1 = 0, v2 = 0, v3 = 0;
94-
for (int i = 0; i < 16; i += 4) {
95-
v0 |= pp[i];
96-
v1 |= pp[i + 1];
97-
v2 |= pp[i + 2];
98-
v3 |= pp[i + 3];
72+
for (int i = 0; i < 16 * SIZEOF_SIZE_T; i += 4 * SIZEOF_SIZE_T) {
73+
size_t a, b, c, d;
74+
memcpy(&a, p + i, SIZEOF_SIZE_T);
75+
memcpy(&b, p + i + SIZEOF_SIZE_T, SIZEOF_SIZE_T);
76+
memcpy(&c, p + i + 2 * SIZEOF_SIZE_T, SIZEOF_SIZE_T);
77+
memcpy(&d, p + i + 3 * SIZEOF_SIZE_T, SIZEOF_SIZE_T);
78+
v0 |= a;
79+
v1 |= b;
80+
v2 |= c;
81+
v3 |= d;
9982
}
10083
value |= v0 | v1 | v2 | v3;
10184
if (value & MASK_MAX_CHAR) {
@@ -105,26 +88,41 @@ STRINGLIB(find_max_char)(const STRINGLIB_CHAR *begin, const STRINGLIB_CHAR *end)
10588
}
10689

10790
while (p + SIZEOF_SIZE_T <= _end) {
108-
value |= *(const size_t *)p;
91+
size_t a;
92+
memcpy(&a, p, SIZEOF_SIZE_T);
93+
value |= a;
10994
p += SIZEOF_SIZE_T;
11095
}
96+
97+
if (p < _end) {
98+
size_t n = (size_t)(_end - (const unsigned char *)begin);
99+
if (n >= SIZEOF_SIZE_T) {
100+
size_t a;
101+
memcpy(&a, _end - SIZEOF_SIZE_T, SIZEOF_SIZE_T);
102+
value |= a;
103+
}
111104
#if SIZEOF_SIZE_T == 8
112-
if (p + sizeof(uint32_t) <= _end) {
113-
value |= *(const uint32_t*)p;
114-
p += sizeof(uint32_t);
115-
}
105+
else if (n >= 4) {
106+
uint32_t a, b;
107+
memcpy(&a, p, 4);
108+
memcpy(&b, _end - 4, 4);
109+
value |= a | b;
110+
}
116111
#endif
117112
#if STRINGLIB_SIZEOF_CHAR <= 2
118-
if (p + sizeof(uint16_t) <= _end) {
119-
value |= *(const uint16_t*)p;
120-
p += sizeof(uint16_t);
121-
}
113+
else if (n >= 2) {
114+
uint16_t a, b;
115+
memcpy(&a, p, 2);
116+
memcpy(&b, _end - 2, 2);
117+
value |= a | b;
118+
}
122119
#endif
123-
#if STRINGLIB_SIZEOF_CHAR <= 1
124-
if (p + 1 <= _end) {
125-
value |= *p++;
126-
}
120+
#if STRINGLIB_SIZEOF_CHAR == 1
121+
else {
122+
value |= *p;
123+
}
127124
#endif
125+
}
128126

129127
#ifdef MASK_UCS2
130128
if (value & MASK_UCS2) {

0 commit comments

Comments
 (0)