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 563f62a3ea076e3825de7bd814d4e889f79fbdb1
Author: Cedric BAIL <[email protected]>
AuthorDate: Mon Aug 3 13:27:46 2026 -0600

    simd: add the codepoint plain-ASCII scan kernel
    
    The same question as the byte scan, over already-decoded codepoints, for the
    callers that hold cells rather than bytes. One unsigned compare instead of two:
    g - 0x20 wraps for anything below 0x20, pushing it above the 0x5e span that
    0x20..0x7e occupies.
    
    No caller yet -- the cell-write path takes it up.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 src/bin/simd/simd.c        | 85 ++++++++++++++++++++++++++++++++++++++++++++++
 src/bin/simd/simd.h        |  7 ++++
 src/bin/simd/simd_neon.c   | 30 ++++++++++++++++
 src/bin/simd/simd_scalar.c | 14 ++++++++
 4 files changed, 136 insertions(+)

diff --git a/src/bin/simd/simd.c b/src/bin/simd/simd.c
index 78de8b09..9e98572d 100644
--- a/src/bin/simd/simd.c
+++ b/src/bin/simd/simd.c
@@ -38,6 +38,16 @@ simd_scan_plain_ascii(const unsigned char *buf, size_t len)
    return simd_scan_plain_ascii_scalar(buf, len);
 }
 
+size_t
+simd_scan_plain_ascii_u32(const Eina_Unicode *buf, size_t len)
+{
+#if defined(TERMINOLOGY_HAVE_NEON)
+   if (EINA_LIKELY(_use_simd))
+     return simd_scan_plain_ascii_u32_neon(buf, len);
+#endif
+   return simd_scan_plain_ascii_u32_scalar(buf, len);
+}
+
 void
 simd_widen_ascii(const unsigned char *buf, size_t len, Eina_Unicode *out)
 {
@@ -157,6 +167,53 @@ _test_scan(void)
      }
 }
 
+static void
+_test_scan_u32(void)
+{
+   size_t len, off, i;
+   int density;
+
+   for (len = 0; len <= 40; len++)
+     {
+        for (density = 0; density <= 100; density += 10)
+          {
+             for (off = 0; off < 8; off++)
+               {
+                  /* Guarded in bytes, so an overread past the payload lands in
+                   * guard bytes rather than in slack. */
+                  unsigned char *base =
+                     _alloc_guarded((off + len) * sizeof(Eina_Unicode));
+                  Eina_Unicode *p = (Eina_Unicode *)(base + GUARD) + off;
+
+                  for (i = 0; i < len; i++)
+                    {
+                       if ((int)(_rnd() % 100) < density)
+                         {
+                            switch (_rnd() % 7)
+                              {
+                               case 0: p[i] = 0x00; break;
+                               case 1: p[i] = 0x1f; break;
+                               case 2: p[i] = 0x7f; break;
+                               case 3: p[i] = 0x80; break;
+                               case 4: p[i] = 0x4e2d; break;
+                               case 5: p[i] = 0x1f600; break;
+                               default: p[i] = 0x80000000u | 0x1234; break;
+                              }
+                         }
+                       else
+                         p[i] = 0x20 + (_rnd() % 0x5f);
+                    }
+
+                  assert(simd_scan_plain_ascii_u32_scalar(p, len) ==
+                         simd_scan_plain_ascii_u32_neon(p, len));
+                  assert(_guards_intact(base,
+                                        (off + len) * sizeof(Eina_Unicode)));
+                  free(base);
+               }
+          }
+     }
+}
+
 static void
 _test_widen(void)
 {
@@ -219,6 +276,32 @@ _test_every_byte(void)
      }
 }
 
+static void
+_test_every_u32_boundary(void)
+{
+   static const Eina_Unicode vals[] = {
+        0x00, 0x01, 0x1f, 0x20, 0x21, 0x7d, 0x7e, 0x7f, 0x80, 0xa0,
+        0x200b, 0x300, 0x4e2d, 0xfe00, 0x1f600, 0x80000000u
+   };
+   size_t v, len, pos, i;
+
+   for (v = 0; v < sizeof(vals) / sizeof(vals[0]); v++)
+     {
+        for (len = 1; len <= 20; len++)
+          {
+             for (pos = 0; pos < len; pos++)
+               {
+                  Eina_Unicode buf[24];
+
+                  for (i = 0; i < len; i++) buf[i] = 'x';
+                  buf[pos] = vals[v];
+                  assert(simd_scan_plain_ascii_u32_scalar(buf, len) ==
+                         simd_scan_plain_ascii_u32_neon(buf, len));
+               }
+          }
+     }
+}
+
 #endif
 
 int
@@ -226,8 +309,10 @@ tytest_simd_parity(void)
 {
 #if defined(TERMINOLOGY_HAVE_NEON)
    _test_scan();
+   _test_scan_u32();
    _test_widen();
    _test_every_byte();
+   _test_every_u32_boundary();
 #endif
    /* Without a vector kernel the scalar path is the only path. */
    return 0;
diff --git a/src/bin/simd/simd.h b/src/bin/simd/simd.h
index e64e93e4..7f47291e 100644
--- a/src/bin/simd/simd.h
+++ b/src/bin/simd/simd.h
@@ -21,6 +21,13 @@ size_t simd_scan_plain_ascii_scalar(const unsigned char *buf, size_t len);
 size_t simd_scan_plain_ascii_neon(const unsigned char *buf, size_t len);
 #endif
 
+/* Same, over decoded codepoints. */
+size_t simd_scan_plain_ascii_u32(const Eina_Unicode *buf, size_t len);
+size_t simd_scan_plain_ascii_u32_scalar(const Eina_Unicode *buf, size_t len);
+#if defined(TERMINOLOGY_HAVE_NEON)
+size_t simd_scan_plain_ascii_u32_neon(const Eina_Unicode *buf, size_t len);
+#endif
+
 /* Widen bytes already known to be plain printable ASCII into codepoints. */
 void simd_widen_ascii(const unsigned char *buf, size_t len, Eina_Unicode *out);
 void simd_widen_ascii_scalar(const unsigned char *buf, size_t len,
diff --git a/src/bin/simd/simd_neon.c b/src/bin/simd/simd_neon.c
index 6ed4066f..cad10609 100644
--- a/src/bin/simd/simd_neon.c
+++ b/src/bin/simd/simd_neon.c
@@ -44,6 +44,36 @@ simd_scan_plain_ascii_neon(const unsigned char *buf, size_t len)
    return len;
 }
 
+size_t
+simd_scan_plain_ascii_u32_neon(const Eina_Unicode *buf, size_t len)
+{
+   /* One unsigned compare instead of two: g - 0x20 wraps for anything below
+    * 0x20, pushing it above the 0x5e span that 0x20..0x7e occupies. */
+   const uint32x4_t bias = vdupq_n_u32(0x20);
+   const uint32x4_t span = vdupq_n_u32(0x7e - 0x20);
+   size_t i = 0;
+
+   for (; i + 4 <= len; i += 4)
+     {
+        uint32x4_t v = vld1q_u32((const uint32_t *)(buf + i));
+        uint32x4_t bad = vcgtq_u32(vsubq_u32(v, bias), span);
+        uint64_t m;
+
+        /* Narrow the four 32-bit lanes to four 16-bit ones, so the first
+         * offending lane is a trailing-zero count divided by sixteen. */
+        m = vget_lane_u64(vreinterpret_u64_u16(vmovn_u32(bad)), 0);
+        if (m) return i + (size_t)(__builtin_ctzll(m) >> 4);
+     }
+
+   for (; i < len; i++)
+     {
+        Eina_Unicode g = buf[i];
+
+        if ((g < 0x20) || (g >= 0x7f)) return i;
+     }
+   return len;
+}
+
 void
 simd_widen_ascii_neon(const unsigned char *buf, size_t len, Eina_Unicode *out)
 {
diff --git a/src/bin/simd/simd_scalar.c b/src/bin/simd/simd_scalar.c
index 0045088f..3702ac57 100644
--- a/src/bin/simd/simd_scalar.c
+++ b/src/bin/simd/simd_scalar.c
@@ -17,6 +17,20 @@ simd_scan_plain_ascii_scalar(const unsigned char *buf, size_t len)
    return len;
 }
 
+size_t
+simd_scan_plain_ascii_u32_scalar(const Eina_Unicode *buf, size_t len)
+{
+   size_t i;
+
+   for (i = 0; i < len; i++)
+     {
+        Eina_Unicode g = buf[i];
+
+        if ((g < 0x20) || (g >= 0x7f)) return i;
+     }
+   return len;
+}
+
 void
 simd_widen_ascii_scalar(const unsigned char *buf, size_t len, Eina_Unicode *out)
 {

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

Reply via email to