test: make the avx512 mirror reproduce the kernel's real expression
The scalar AVX-512 mirror built its whitespace mask from ws_tab lookups, so a bug in the kernel's actual predicate - the (x - 9) < 5 unsigned range trick plus newline/space/NBSP compares - would pass the selftest on hosts without AVX-512 and only surface on real hardware. The mirror now computes the mask with the kernel's exact expression, and check_kernel gains an exhaustive 256-byte ramp (forward and reversed) so any divergence from the reference table changes a count. Verified by mutation: shifting the range constant to (x - 8) < 5 makes the selftest fail.
This commit is contained in:
+30
-6
@@ -952,8 +952,11 @@ static long long ref_words(const unsigned char *s, size_t n, int *prev_ws)
|
||||
/*
|
||||
* Scalar mirror of the AVX-512 kernel: identical 64-byte chunking and
|
||||
* 64-bit mask arithmetic (bit-63 carry, 64-bit shift/OR, popcnt) for
|
||||
* hosts that cannot execute the real zmm code. AVX-2 already proves
|
||||
* the algorithm; this proves the width.
|
||||
* hosts that cannot execute the real zmm code. It reproduces the
|
||||
* kernel's exact whitespace expression - newline/space/NBSP equality
|
||||
* plus the (x - 9) < 5 unsigned range trick - rather than consulting
|
||||
* ws_tab, so a bug in the kernel's expression is caught here against
|
||||
* the reference instead of only on real AVX-512 hardware.
|
||||
*/
|
||||
static lw_t count_lw_avx512_mirror(const unsigned char *s, size_t n,
|
||||
int *prev_ws, int need_lines, int need_words)
|
||||
@@ -967,10 +970,13 @@ static lw_t count_lw_avx512_mirror(const unsigned char *s, size_t n,
|
||||
uint64_t nl_mask = 0, ws = 0;
|
||||
for (size_t j = 0; j < 64; j++)
|
||||
{
|
||||
if (s[i + j] == '\n')
|
||||
nl_mask |= (uint64_t)1 << j;
|
||||
if (ws_tab[s[i + j]])
|
||||
ws |= (uint64_t)1 << j;
|
||||
unsigned char c = s[i + j];
|
||||
uint64_t bit = (uint64_t)1 << j;
|
||||
|
||||
if (c == '\n')
|
||||
nl_mask |= bit;
|
||||
if (c == '\n' || c == ' ' || c == 0xa0 || (uint8_t)(c - 9) < 5)
|
||||
ws |= bit;
|
||||
}
|
||||
if (need_lines)
|
||||
lines += (long long)__builtin_popcountll(nl_mask);
|
||||
@@ -1065,6 +1071,24 @@ static int check_kernel(const char *name, count_lw_fn fn)
|
||||
}
|
||||
}
|
||||
|
||||
/* exhaustive predicate check: every byte value in a 256-byte ramp,
|
||||
* forward and reversed, so a divergence between the kernel's
|
||||
* whitespace expression and the reference table changes a count */
|
||||
for (int pass = 0; pass < 2; pass++)
|
||||
{
|
||||
for (k = 0; k < 256; k++)
|
||||
buf[k] = pass == 0 ? (unsigned char)k : (unsigned char)(255 - k);
|
||||
int a = 1, b = 1;
|
||||
lw_t got = fn(buf, 256, &a, 1, 1);
|
||||
|
||||
if (got.lines != ref_lines(buf, 256) ||
|
||||
got.words != ref_words(buf, 256, &b) || a != b)
|
||||
{
|
||||
printf("%s: predicate ramp pass=%d failed\n", name, pass);
|
||||
fails++;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s: %s\n", name, fails ? "FAIL" : "ok");
|
||||
return fails;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user