Commit cd259272c8 for perl

commit cd259272c85e6878239ce1ff2fc8402a661b74fe
Author: Richard Leach <rich+perl@hyphen-dash-hyphen.info>
Date:   Fri Oct 2 16:07:28 2026 +0000

    S_find_next_masked: widen search to check 512 bits at a time

    The following were used to test throughput of this function:
    * string:  `my $run_nanyofm = ('B' x 2_000_000) . 'A';`
    * pattern: `$run_nanyofm =~ /\A[^A]+/;`

    The following results were seen:
                                        Rate
    blead (doesn't scale with -march)    4741/s
    this commit, no -march              16365/s
    this commit, -march=x86-64-v2       16290/s
    this commit, -march=x86-64-v3       27534/s

    (No CPU to hand that supports -march=x86-64-v4.)

diff --git a/regexec.c b/regexec.c
index 3b5e09fa8d..f3896cb924 100644
--- a/regexec.c
+++ b/regexec.c
@@ -791,22 +791,48 @@ S_find_next_masked(U8 * s, const U8 * send, const U8 byte, const U8 mask)

     /* Returns the position of the first byte in the sequence between 's'
      * and 'send-1' inclusive that when ANDed with 'mask' yields 'byte';
-     * returns 'send' if none found.  It uses word-level operations instead of
-     * byte to speed up the process */
+     * returns 'send' if none found. */

-    const U8 * const per_byte_end = WORTH_PER_WORD_LOOP(s, send, 1);
-    if (per_byte_end) {
+    /* Walk leading bytes until "s" is word-aligned, for the benefit of those
+     * platforms where unaligned access is much slower than aligned access. */
+    {
+        const U8 * const word_end = s + BYTES_REMAINING_IN_WORD(s);
+        const U8 * const per_byte_end = (word_end < send) ? word_end : send;
         while (s < per_byte_end ) {
             if (((*s) & mask) == byte) {
                 return s;
             }
             s++;
         }
+    }
+    /* Fast path: fixed-length masked reduction per PERL_FSE_SIZE block.
+     * This should vectorize given a capable compiler and compile target(s).
+     * Testing on an AMD Zen processor showed codegen improving and
+     * throughput increasing from:
+     *     bog standard build -> -march=x86-64-v2 -> -march=x86-64-v3
+     */

+    if (WORTH_PER_WORD_LOOP_BINMODE(s, send, PERL_FSE_SIZE / PERL_WORDSIZE)) {
+        while (s + PERL_FSE_SIZE <= send) {
+            U8 hit = 0;
+            unsigned k;
+            for (k = 0; k < PERL_FSE_SIZE; k++) {
+                U8 d = (U8) (((U8) (s[k] & mask)) ^ byte);  /* 0 iff match */
+                hit |= (U8) (d == 0 ? 0xFF : 0x00);
+            }
+            if (hit) {
+                break; /* Let the per-word code find the first hit */
+            }
+            s += PERL_FSE_SIZE;
+        }
+    }
+
+    /* Process per-word as long as we have at least a full word left */
+    if (WORTH_PER_WORD_LOOP_BINMODE(s, send, 1)) {
         PERL_UINTMAX_T word = PERL_COUNT_MULTIPLIER * byte;
         PERL_UINTMAX_T mask_word = PERL_COUNT_MULTIPLIER * mask;

-        do {
+        while (s + PERL_WORDSIZE <= send) {
             PERL_UINTMAX_T masked = (* (PERL_UINTMAX_T *) s) & mask_word;

             /* If 'masked' contains bytes with the bit pattern of 'byte' within
@@ -838,7 +864,7 @@ S_find_next_masked(U8 * s, const U8 * send, const U8 byte, const U8 mask)
             s += variant_byte_number(masked);
             return s;

-        } while (s + PERL_WORDSIZE <= send);
+        }
     }

     while (s < send) {