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.