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

    simd: add the reverse non-zero byte scan kernel
    
    Index one past the last non-zero byte, which is what a trailing-length scan over
    a row of cells asks for. Walks backwards a vector at a time and takes the
    highest set lane of the first block that has one.
    
    No caller yet -- the line-length scan takes it up.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 src/bin/simd/simd.c        | 57 ++++++++++++++++++++++++++++++++++++++++++++++
 src/bin/simd/simd.h        |  7 ++++++
 src/bin/simd/simd_neon.c   | 32 ++++++++++++++++++++++++++
 src/bin/simd/simd_scalar.c | 11 +++++++++
 4 files changed, 107 insertions(+)

diff --git a/src/bin/simd/simd.c b/src/bin/simd/simd.c
index 9e98572d..b7e11ef8 100644
--- a/src/bin/simd/simd.c
+++ b/src/bin/simd/simd.c
@@ -48,6 +48,16 @@ simd_scan_plain_ascii_u32(const Eina_Unicode *buf, size_t len)
    return simd_scan_plain_ascii_u32_scalar(buf, len);
 }
 
+size_t
+simd_rscan_nonzero(const unsigned char *buf, size_t len)
+{
+#if defined(TERMINOLOGY_HAVE_NEON)
+   if (EINA_LIKELY(_use_simd))
+     return simd_rscan_nonzero_neon(buf, len);
+#endif
+   return simd_rscan_nonzero_scalar(buf, len);
+}
+
 void
 simd_widen_ascii(const unsigned char *buf, size_t len, Eina_Unicode *out)
 {
@@ -214,6 +224,52 @@ _test_scan_u32(void)
      }
 }
 
+static void
+_test_rscan(void)
+{
+   size_t len, off, pos;
+   int density;
+
+   for (len = 0; len <= 70; len++)
+     {
+        for (density = 0; density <= 100; density += 25)
+          {
+             for (off = 0; off < 16; off++)
+               {
+                  unsigned char *base = _alloc_guarded(off + len);
+                  unsigned char *p = base + GUARD + off;
+
+                  memset(p, 0, len);
+                  for (pos = 0; pos < len; pos++)
+                    {
+                       if ((int)(_rnd() % 100) < density)
+                         p[pos] = (unsigned char)(1 + (_rnd() % 255));
+                    }
+
+                  assert(simd_rscan_nonzero_scalar(p, len) ==
+                         simd_rscan_nonzero_neon(p, len));
+                  assert(_guards_intact(base, off + len));
+                  free(base);
+               }
+          }
+     }
+
+   /* One non-zero byte walked across every position: pins down the lane
+    * arithmetic rather than trusting the random fill to have covered it. */
+   for (len = 1; len <= 40; len++)
+     {
+        for (pos = 0; pos < len; pos++)
+          {
+             unsigned char buf[48];
+
+             memset(buf, 0, sizeof(buf));
+             buf[pos] = 0x01;
+             assert(simd_rscan_nonzero_scalar(buf, len) == pos + 1);
+             assert(simd_rscan_nonzero_neon(buf, len) == pos + 1);
+          }
+     }
+}
+
 static void
 _test_widen(void)
 {
@@ -310,6 +366,7 @@ tytest_simd_parity(void)
 #if defined(TERMINOLOGY_HAVE_NEON)
    _test_scan();
    _test_scan_u32();
+   _test_rscan();
    _test_widen();
    _test_every_byte();
    _test_every_u32_boundary();
diff --git a/src/bin/simd/simd.h b/src/bin/simd/simd.h
index 7f47291e..343fe7fa 100644
--- a/src/bin/simd/simd.h
+++ b/src/bin/simd/simd.h
@@ -28,6 +28,13 @@ size_t simd_scan_plain_ascii_u32_scalar(const Eina_Unicode *buf, size_t len);
 size_t simd_scan_plain_ascii_u32_neon(const Eina_Unicode *buf, size_t len);
 #endif
 
+/* Index one past the last non-zero byte, or 0 if every byte is zero. */
+size_t simd_rscan_nonzero(const unsigned char *buf, size_t len);
+size_t simd_rscan_nonzero_scalar(const unsigned char *buf, size_t len);
+#if defined(TERMINOLOGY_HAVE_NEON)
+size_t simd_rscan_nonzero_neon(const unsigned char *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 cad10609..c132260b 100644
--- a/src/bin/simd/simd_neon.c
+++ b/src/bin/simd/simd_neon.c
@@ -74,6 +74,38 @@ simd_scan_plain_ascii_u32_neon(const Eina_Unicode *buf, size_t len)
    return len;
 }
 
+size_t
+simd_rscan_nonzero_neon(const unsigned char *buf, size_t len)
+{
+   size_t i = len;
+
+   while (i >= 16)
+     {
+        uint8x16_t v = vld1q_u8(buf + i - 16);
+        uint64_t m;
+
+        /* vtstq_u8(v, v) is 0xff in every lane whose byte is non-zero. */
+        m = vget_lane_u64(vreinterpret_u64_u8(
+                             vshrn_n_u16(vreinterpretq_u16_u8(vtstq_u8(v, v)),
+                                         4)), 0);
+        if (m)
+          {
+             /* Highest set nibble is the last non-zero byte of this block. */
+             size_t lane = (size_t)(63 - __builtin_clzll(m)) >> 2;
+
+             return i - 16 + lane + 1;
+          }
+        i -= 16;
+     }
+
+   while (i > 0)
+     {
+        if (buf[i - 1]) return i;
+        i--;
+     }
+   return 0;
+}
+
 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 3702ac57..3676b94c 100644
--- a/src/bin/simd/simd_scalar.c
+++ b/src/bin/simd/simd_scalar.c
@@ -31,6 +31,17 @@ simd_scan_plain_ascii_u32_scalar(const Eina_Unicode *buf, size_t len)
    return len;
 }
 
+size_t
+simd_rscan_nonzero_scalar(const unsigned char *buf, size_t len)
+{
+   while (len > 0)
+     {
+        if (buf[len - 1]) return len;
+        len--;
+     }
+   return 0;
+}
+
 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