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. */
6161Py_LOCAL_INLINE (Py_UCS4 )
6262STRINGLIB (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