@@ -201,6 +201,45 @@ void initialize_neon(void) {
201201}
202202#endif
203203
204+ #ifdef HAVE_SIMD_SSE4_2
205+
206+ static __m128i hibit_friendly_chars_sse42 [8 ];
207+
208+ // From: https://stackoverflow.com/questions/36998538/fastest-way-to-horizontally-sum-sse-unsigned-byte-vector
209+ inline uint32_t _mm_sum_epu8 (const __m128i v ) {
210+ __m128i vsum = _mm_sad_epu8 (v , _mm_setzero_si128 ());
211+ return _mm_cvtsi128_si32 (vsum ) + _mm_extract_epi16 (vsum , 4 );
212+ }
213+
214+ inline static OJ_TARGET_SSE42 size_t hibit_friendly_size_sse42 (const uint8_t * str , size_t len ) {
215+ size_t size = 0 ;
216+ size_t i = 0 ;
217+
218+ for (; i + sizeof (__m128i ) <= len ; i += sizeof (__m128i ), str += sizeof (__m128i )) {
219+ size += sizeof (__m128i );
220+
221+ __m128i chunk = _mm_loadu_si128 ((__m128i * )str );
222+ __m128i tmp = vector_lookup_sse42 (chunk , hibit_friendly_chars_sse42 , 8 );
223+ size += _mm_sum_epu8 (tmp );
224+ }
225+ size_t total = size + calculate_string_size (str , len - i , hibit_friendly_chars );
226+ return total ;
227+ }
228+
229+ void OJ_TARGET_SSE42 initialize_sse42 (void ) {
230+ for (int i = 0 ; i < 8 ; i ++ ) {
231+ hibit_friendly_chars_sse42 [i ] = _mm_sub_epi8 (
232+ _mm_loadu_si128 ((__m128i * )(hibit_friendly_chars + i * sizeof (__m128i ))),
233+ _mm_set1_epi8 ('1' ));
234+ }
235+ }
236+
237+ #else
238+
239+ #define SIMD_TARGET
240+
241+ #endif /* HAVE_SIMD_SSE4_2 */
242+
204243inline static size_t hibit_friendly_size (const uint8_t * str , size_t len ) {
205244#ifdef HAVE_SIMD_NEON
206245 size_t size = 0 ;
@@ -220,6 +259,13 @@ inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
220259
221260 size_t total = size + calculate_string_size (str , len - i , hibit_friendly_chars );
222261 return total ;
262+ #elif defined(HAVE_SIMD_SSE4_2 )
263+ if (SIMD_Impl == SIMD_SSE42 ) {
264+ if (len >= sizeof (__m128i )) {
265+ return hibit_friendly_size_sse42 (str , len );
266+ }
267+ }
268+ return calculate_string_size (str , len , hibit_friendly_chars );
223269#else
224270 return calculate_string_size (str , len , hibit_friendly_chars );
225271#endif
@@ -944,6 +990,34 @@ neon_update(const char *str, uint8x16x4_t *cmap_neon, int neon_table_size, bool
944990 return result ;
945991}
946992
993+ #elif defined(HAVE_SIMD_SSE4_2 )
994+ typedef struct _sse42_match_result {
995+ __m128i actions ;
996+ bool needs_escape ;
997+ int escape_mask ;
998+ bool has_some_hibit ;
999+ bool do_unicode_validation ;
1000+ } sse42_match_result ;
1001+
1002+ static inline OJ_TARGET_SSE42 sse42_match_result
1003+ sse42_update (const char * str , __m128i * cmap_sse42 , int sse42_tab_size , bool do_unicode_validation , bool has_hi ) {
1004+ sse42_match_result result = {.has_some_hibit = false, .do_unicode_validation = false};
1005+
1006+ __m128i chunk = _mm_loadu_si128 ((__m128i * )str );
1007+ __m128i actions = vector_lookup_sse42 (chunk , cmap_sse42 , sse42_tab_size );
1008+ __m128i needs_escape = _mm_xor_si128 (_mm_cmpeq_epi8 (actions , _mm_setzero_si128 ()), _mm_set1_epi8 (0xFF ));
1009+ result .actions = _mm_add_epi8 (actions , _mm_set1_epi8 ('1' ));
1010+
1011+ result .escape_mask = _mm_movemask_epi8 (needs_escape );
1012+ result .needs_escape = result .escape_mask != 0 ;
1013+ if (has_hi && do_unicode_validation ) {
1014+ __m128i has_some_hibit = _mm_and_si128 (chunk , _mm_set1_epi8 (0x80 ));
1015+ result .has_some_hibit = _mm_movemask_epi8 (has_some_hibit ) != 0 ;
1016+ result .do_unicode_validation = has_hi && do_unicode_validation && result .has_some_hibit ;
1017+ }
1018+ return result ;
1019+ }
1020+
9471021#endif /* HAVE_SIMD_NEON */
9481022
9491023static inline FORCE_INLINE const char * process_character (char action ,
@@ -1023,6 +1097,9 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
10231097#ifdef HAVE_SIMD_NEON
10241098 uint8x16x4_t * cmap_neon = NULL ;
10251099 int neon_table_size = 0 ;
1100+ #elif defined(HAVE_SIMD_SSE4_2 )
1101+ __m128i * cmap_sse42 = NULL ;
1102+ int sse42_tab_size ;
10261103#endif /* HAVE_SIMD_NEON */
10271104 const char * orig = str ;
10281105 bool has_hi = false;
@@ -1091,6 +1168,9 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
10911168#ifdef HAVE_SIMD_NEON
10921169 cmap_neon = hibit_friendly_chars_neon ;
10931170 neon_table_size = 2 ;
1171+ #elif defined(HAVE_SIMD_SSE4_2 )
1172+ cmap_sse42 = hibit_friendly_chars_sse42 ;
1173+ sse42_tab_size = 8 ;
10941174#endif /* HAVE_NEON_SIMD */
10951175 size = hibit_friendly_size ((uint8_t * )str , cnt );
10961176 }
@@ -1118,21 +1198,32 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
11181198 if (is_sym ) {
11191199 * out -> cur ++ = ':' ;
11201200 }
1121- #ifdef HAVE_SIMD_NEON
1122- const char * chunk_start ;
1123- const char * chunk_end ;
1124- const char * cursor = str ;
1125- bool use_neon = (cmap_neon != NULL && cnt >= (sizeof (uint8x16_t ))) ? true : false;
1126- char matches [16 ];
1201+
1202+ #if defined(HAVE_SIMD_NEON ) || defined(HAVE_SIMD_SSE4_2 )
1203+
11271204#define SEARCH_FLUSH \
11281205 if (str > cursor) { \
11291206 APPEND_CHARS(out->cur, cursor, str - cursor); \
11301207 cursor = str; \
11311208 }
11321209
1133- #endif /* HAVE_SIMD_NEON */
1210+ const char * chunk_start ;
1211+ const char * chunk_end ;
1212+ const char * cursor = str ;
1213+ char matches [16 ];
1214+ #endif /* HAVE_SIMD_NEON || HAVE_SIMD_SSE4_2 */
1215+
1216+ #if defined(HAVE_SIMD_NEON )
1217+ bool use_simd = (cmap_neon != NULL && cnt >= (sizeof (uint8x16_t ))) ? true : false;
1218+ #elif defined(HAVE_SIMD_SSE4_2 )
1219+ bool use_simd = false;
1220+ if (SIMD_Impl == SIMD_SSE42 ) {
1221+ use_simd = (cmap_sse42 != NULL && cnt >= (sizeof (__m128i ))) ? true : false;
1222+ }
1223+ #endif
1224+
11341225#ifdef HAVE_SIMD_NEON
1135- if (use_neon ) {
1226+ if (use_simd ) {
11361227 while (str < end ) {
11371228 const char * chunk_ptr = NULL ;
11381229 if (str + sizeof (uint8x16_t ) <= end ) {
@@ -1195,7 +1286,55 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
11951286 }
11961287 SEARCH_FLUSH ;
11971288 }
1198- #endif /* HAVE_SIMD_NEON */
1289+ #endif
1290+
1291+ #ifdef HAVE_SIMD_SSE4_2
1292+ if (SIMD_Impl == SIMD_SSE42 ) {
1293+ if (use_simd ) {
1294+ while (str < end ) {
1295+ const char * chunk_ptr = NULL ;
1296+ if (str + sizeof (__m128i ) <= end ) {
1297+ chunk_ptr = str ;
1298+ chunk_start = str ;
1299+ chunk_end = str + sizeof (__m128i );
1300+ } else if ((end - str ) >= SIMD_MINIMUM_THRESHOLD ) {
1301+ memset (out -> cur , 'A' , sizeof (__m128i ));
1302+ memcpy (out -> cur , str , (end - str ));
1303+ chunk_ptr = out -> cur ;
1304+ chunk_start = str ;
1305+ chunk_end = end ;
1306+ } else {
1307+ break ;
1308+ }
1309+ sse42_match_result result = sse42_update (chunk_ptr ,
1310+ cmap_sse42 ,
1311+ sse42_tab_size ,
1312+ do_unicode_validation ,
1313+ has_hi );
1314+ if ((result .do_unicode_validation ) || result .needs_escape ) {
1315+ SEARCH_FLUSH ;
1316+ _mm_storeu_si128 ((__m128i * )matches , result .actions );
1317+ while (str < chunk_end ) {
1318+ long match_index = str - chunk_start ;
1319+ str = process_character (matches [match_index ],
1320+ str ,
1321+ end ,
1322+ out ,
1323+ orig ,
1324+ do_unicode_validation ,
1325+ & check_start );
1326+ str ++ ;
1327+ }
1328+ cursor = str ;
1329+ continue ;
1330+ }
1331+ str = chunk_end ;
1332+ }
1333+ SEARCH_FLUSH ;
1334+ }
1335+ }
1336+ #endif /* HAVE_SIMD_SSE4_2 */
1337+
11991338 for (; str < end ; str ++ ) {
12001339 str = process_character (cmap [(uint8_t )* str ], str , end , out , orig , do_unicode_validation , & check_start );
12011340 }
0 commit comments