This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch master
in repository terminology.

View the commit online.

commit 12a0e8dfc3d3a53fa9bfed4509f25b65e4e9471c
Author: Cedric BAIL <[email protected]>
AuthorDate: Mon Aug 3 13:27:46 2026 -0600

    simd: add the plain-ASCII byte scan kernel
    
    Where does this run of printable ASCII end: a loop shaped like memchr, over the
    one range the UTF-8 decoder can widen without per-character work. The NEON form
    collapses sixteen lanes into sixteen nibbles of one 64-bit word, so the first
    offending byte is a trailing-zero count over four -- aarch64 has no PMOVMSKB
    equivalent.
    
    Intrinsics, not hand-written assembly. EFL's only .S file is ARMv7-only and its
    meson gate excludes it from every aarch64 build; all of EFL's aarch64 SIMD is
    arm_neon.h intrinsics, and for a loop this shape there is nothing an .S buys
    that the compiler does not already do.
    
    Both forms are exported, not just the dispatcher: a kernel reachable only
    through dispatch cannot be compared against the reference it is meant to match.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 src/bin/meson.build        |  2 ++
 src/bin/simd/simd.c        | 10 ++++++++++
 src/bin/simd/simd.h        |  8 ++++++++
 src/bin/simd/simd_neon.c   | 48 ++++++++++++++++++++++++++++++++++++++++++++++
 src/bin/simd/simd_scalar.c | 18 +++++++++++++++++
 5 files changed, 86 insertions(+)

diff --git a/src/bin/meson.build b/src/bin/meson.build
index 718882dc..b636ddd6 100644
--- a/src/bin/meson.build
+++ b/src/bin/meson.build
@@ -1,4 +1,6 @@
 simd_sources = ['simd/simd.c',
+                'simd/simd_scalar.c',
+                'simd/simd_neon.c',
                 'simd/simd.h']
 
 terminology_sources = ['private.h',
diff --git a/src/bin/simd/simd.c b/src/bin/simd/simd.c
index a8b48335..d04987ae 100644
--- a/src/bin/simd/simd.c
+++ b/src/bin/simd/simd.c
@@ -27,3 +27,13 @@ simd_enabled(void)
 {
    return _use_simd;
 }
+
+size_t
+simd_scan_plain_ascii(const unsigned char *buf, size_t len)
+{
+#if defined(TERMINOLOGY_HAVE_NEON)
+   if (EINA_LIKELY(_use_simd))
+     return simd_scan_plain_ascii_neon(buf, len);
+#endif
+   return simd_scan_plain_ascii_scalar(buf, len);
+}
diff --git a/src/bin/simd/simd.h b/src/bin/simd/simd.h
index 8d43d335..ded8372e 100644
--- a/src/bin/simd/simd.h
+++ b/src/bin/simd/simd.h
@@ -13,6 +13,14 @@
 # define TERMINOLOGY_HAVE_NEON 1
 #endif
 
+/* Index of the first byte that is not plain printable ASCII (0x20..0x7e),
+ * or len. */
+size_t simd_scan_plain_ascii(const unsigned char *buf, size_t len);
+size_t simd_scan_plain_ascii_scalar(const unsigned char *buf, size_t len);
+#if defined(TERMINOLOGY_HAVE_NEON)
+size_t simd_scan_plain_ascii_neon(const unsigned char *buf, size_t len);
+#endif
+
 /* Read TERMINOLOGY_SIMD_DISABLE, which switches the vector kernels off without
  * a rebuild. Modelled on EFL's EVAS_NEON_DISABLE. */
 void simd_init(void);
diff --git a/src/bin/simd/simd_neon.c b/src/bin/simd/simd_neon.c
new file mode 100644
index 00000000..ab6f88b7
--- /dev/null
+++ b/src/bin/simd/simd_neon.c
@@ -0,0 +1,48 @@
+/* NEON implementations of the intake kernels, using arm_neon.h intrinsics as
+ * EFL's own aarch64 code does. */
+#include "private.h"
+#include "simd.h"
+#include <string.h>
+
+#if defined(TERMINOLOGY_HAVE_NEON)
+
+#include <arm_neon.h>
+
+size_t
+simd_scan_plain_ascii_neon(const unsigned char *buf, size_t len)
+{
+   const uint8x16_t lo    = vdupq_n_u8(0x20);
+   const uint8x16_t hi    = vdupq_n_u8(0x7f);
+   size_t i = 0;
+
+   for (; i + 16 <= len; i += 16)
+     {
+        uint8x16_t v = vld1q_u8(buf + i);
+        uint8x16_t bad;
+        uint64_t m;
+
+        /* c < 0x20 || c >= 0x7f. The second test folds DEL and every
+         * high-bit-set byte into one comparison, which is why the range is
+         * expressed as ">= 0x7f" rather than "== 0x7f || >= 0x80". */
+        bad = vorrq_u8(vcltq_u8(v, lo), vcgeq_u8(v, hi));
+
+        /* Collapse the 16 lanes into 16 nibbles of one 64-bit word, so the
+         * first offending byte is a trailing-zero count over four. aarch64 has
+         * no PMOVMSKB equivalent. */
+        m = vget_lane_u64(vreinterpret_u64_u8(
+                             vshrn_n_u16(vreinterpretq_u16_u8(bad), 4)), 0);
+        if (m) return i + (size_t)(__builtin_ctzll(m) >> 2);
+     }
+
+   /* Tail: fewer than 16 bytes left. */
+   for (; i < len; i++)
+     {
+        unsigned char c = buf[i];
+
+        if ((c < 0x20) || (c >= 0x7f)) return i;
+     }
+   return len;
+}
+
+
+#endif
diff --git a/src/bin/simd/simd_scalar.c b/src/bin/simd/simd_scalar.c
new file mode 100644
index 00000000..f36098ce
--- /dev/null
+++ b/src/bin/simd/simd_scalar.c
@@ -0,0 +1,18 @@
+/* Scalar reference implementations. The vector kernels must agree with these
+ * byte for byte; keep them obvious rather than clever. */
+#include "private.h"
+#include "simd.h"
+
+size_t
+simd_scan_plain_ascii_scalar(const unsigned char *buf, size_t len)
+{
+   size_t i;
+
+   for (i = 0; i < len; i++)
+     {
+        unsigned char c = buf[i];
+
+        if ((c < 0x20) || (c >= 0x7f)) return i;
+     }
+   return len;
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to