3131#include "zend_lazy_objects.h"
3232#include "zend_bitset.h"
3333
34- #ifdef ZEND_INTRIN_SSE4_2_NATIVE
34+ #if defined( ZEND_INTRIN_SSE4_2_NATIVE ) || defined( ZEND_INTRIN_SSE4_2_FUNC_PROTO )
3535# include <nmmintrin.h>
3636#endif
37+ #ifdef ZEND_INTRIN_SSE4_2_FUNC_PROTO
38+ # include "zend_cpuinfo.h"
39+ #endif
3740
3841static const char digits [] = "0123456789abcdef" ;
3942
@@ -433,7 +436,7 @@ static zend_always_inline bool php_json_printable_ascii_escape(smart_str *buf, u
433436 return true;
434437}
435438
436- #ifdef ZEND_INTRIN_SSE4_2_NATIVE
439+ #if defined( ZEND_INTRIN_SSE4_2_NATIVE ) || defined( ZEND_INTRIN_SSE4_2_FUNC_PROTO )
437440static zend_always_inline __m128i php_json_create_sse_escape_mask (int options )
438441{
439442 const char sentinel = 1 ; /* outside of the printable range, so no false matches are possible */
@@ -446,6 +449,28 @@ static zend_always_inline __m128i php_json_create_sse_escape_mask(int options)
446449}
447450#endif
448451
452+ #ifdef ZEND_INTRIN_SSE4_2_FUNC_PROTO
453+ static int php_json_sse42_compute_escape_intersection (const __m128i mask , const __m128i input ) __attribute__((ifunc ("resolve_json_escape_intersection" )));
454+
455+ typedef int (* php_json_compute_escape_intersection_t )(const __m128i mask , const __m128i input );
456+
457+ ZEND_INTRIN_SSE4_2_FUNC_DECL (int php_json_sse42_compute_escape_intersection_real (const __m128i mask , const __m128i input ));
458+ zend_always_inline int php_json_sse42_compute_escape_intersection_real (const __m128i mask , const __m128i input )
459+ {
460+ const __m128i result_individual_bytes = _mm_cmpistrm (mask , input , _SIDD_SBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK );
461+ return _mm_cvtsi128_si32 (result_individual_bytes );
462+ }
463+
464+ ZEND_NO_SANITIZE_ADDRESS
465+ ZEND_ATTRIBUTE_UNUSED /* clang mistakenly warns about this */
466+ static php_json_compute_escape_intersection_t resolve_json_escape_intersection (void ) {
467+ if (zend_cpu_supports_sse42 ()) {
468+ return php_json_sse42_compute_escape_intersection_real ;
469+ }
470+ return NULL /*php_json_sse42_compute_escape_intersection_fallback*/ ; // TODO: implement this fallback
471+ }
472+ #endif
473+
449474zend_result php_json_escape_string (
450475 smart_str * buf , const char * s , size_t len ,
451476 int options , php_json_encoder * encoder ) /* {{{ */
@@ -483,7 +508,7 @@ zend_result php_json_escape_string(
483508
484509 pos = 0 ;
485510
486- #ifdef ZEND_INTRIN_SSE4_2_NATIVE
511+ #if defined( ZEND_INTRIN_SSE4_2_NATIVE ) || defined( ZEND_INTRIN_SSE4_2_FUNC_PROTO )
487512 const __m128i sse_escape_mask = php_json_create_sse_escape_mask (options );
488513#endif
489514
@@ -504,9 +529,10 @@ zend_result php_json_escape_string(
504529 max_shift = zend_ulong_ntz (input_range_mask );
505530 }
506531
507- #ifdef ZEND_INTRIN_SSE4_2_NATIVE /* TODO: resolver support */
508- const __m128i result_individual_bytes = _mm_cmpistrm (sse_escape_mask , input , _SIDD_SBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK );
509- int mask = _mm_cvtsi128_si32 (result_individual_bytes );
532+ #ifdef ZEND_INTRIN_SSE4_2_NATIVE
533+ int mask = php_json_sse42_compute_escape_intersection_real (sse_escape_mask , input );
534+ #elif defined(ZEND_INTRIN_SSE4_2_FUNC_PROTO )
535+ int mask = php_json_sse42_compute_escape_intersection (sse_escape_mask , input );
510536#else
511537 const __m128i result_34 = _mm_cmpeq_epi8 (input , _mm_set1_epi8 ('"' ));
512538 const __m128i result_38 = _mm_cmpeq_epi8 (input , _mm_set1_epi8 ('&' ));
0 commit comments