//
// V6 DIAGNOSTIC โ€” V1 with both Blake2b calls stripped.
//
// Synthesize the seed-hash bytes from gid via a cheap hash mix (splitmix
// style), do the 32 random reads + 256-bit sum, then XOR the sum (NOT
// hashed) into the accumulator. Compares to V1 to measure how much of
// V1's time is Blake2b compute vs random-read memory.
//
// Correctness: this kernel does NOT compute the real Autolykos d; its
// XOR accumulator will differ from V1's. The host treats this as a
// diagnostic-only kernel and does not verify against CPU reference.
//

#include <metal_stdlib>
using namespace metal;

struct Params {
    uchar  m[32];
    ulong  n;
    ulong  nonce_base;
    uint   count;
    uint   _pad;
};

static inline void add256_v4(thread ulong* sum, ulong4 r) {
    ulong t = sum[0] + r.x;
    ulong c = (t < sum[0]) ? 1UL : 0UL;
    sum[0] = t;
    t = sum[1] + r.y;
    ulong c1 = (t < sum[1]) ? 1UL : 0UL;
    ulong t2 = t + c;
    ulong c2 = (t2 < t) ? 1UL : 0UL;
    sum[1] = t2;
    c = c1 + c2;
    t = sum[2] + r.z;
    c1 = (t < sum[2]) ? 1UL : 0UL;
    t2 = t + c;
    c2 = (t2 < t) ? 1UL : 0UL;
    sum[2] = t2;
    c = c1 + c2;
    t = sum[3] + r.w;
    t2 = t + c;
    sum[3] = t2;
}

kernel void mine_kernel_v6(
    device   const ulong4*     R          buffer(0),
    device   atomic_uint*      acc        buffer(1),
    constant Params&           p          buffer(2),
    uint                       gid        thread_position_in_grid
) {
    if (gid >= p.count) return;
    ulong nonce = p.nonce_base + (ulong)gid;

    // Synthesize "seed hash" bytes from nonce via splitmix64.
    // No Blake2b โ€” this is the diagnostic strip.
    ulong x = nonce + 0x9E3779B97F4A7C15UL;
    x = (x ^ (x >> 30)) * 0xBF58476D1CE4E5B9UL;
    x = (x ^ (x >> 27)) * 0x94D049BB133111EBUL;
    x ^= x >> 31;

    ulong eb0 = x;
    ulong eb1 = x * 0x9E3779B97F4A7C15UL;
    ulong eb2 = eb1 * 0xBF58476D1CE4E5B9UL;
    ulong eb3 = eb2 * 0x94D049BB133111EBUL;
    ulong eb4 = eb0 & 0xFFFFFFUL;

    #define SBYTE6(k) (\
        ((k) <  8) ? ((eb0 >> ((k)      * 8)) & 0xFFUL) :  \
        ((k) < 16) ? ((eb1 >> (((k)-8)  * 8)) & 0xFFUL) :  \
        ((k) < 24) ? ((eb2 >> (((k)-16) * 8)) & 0xFFUL) :  \
        ((k) < 32) ? ((eb3 >> (((k)-24) * 8)) & 0xFFUL) :  \
                     ((eb4 >> (((k)-32) * 8)) & 0xFFUL) )

    #define IDX6(i) ((ulong)((uint)((SBYTE6(i  ) << 24) |  \
                                   (SBYTE6(i+1) << 16) |  \
                                   (SBYTE6(i+2) <<  8) |  \
                                    SBYTE6(i+3))) % p.n)

    #define LOAD6(i) add256_v4(sum, R[IDX6(i)])

    ulong sum[4] = {0,0,0,0};
    LOAD6( 0); LOAD6( 1); LOAD6( 2); LOAD6( 3);
    LOAD6( 4); LOAD6( 5); LOAD6( 6); LOAD6( 7);
    LOAD6( 8); LOAD6( 9); LOAD6(10); LOAD6(11);
    LOAD6(12); LOAD6(13); LOAD6(14); LOAD6(15);
    LOAD6(16); LOAD6(17); LOAD6(18); LOAD6(19);
    LOAD6(20); LOAD6(21); LOAD6(22); LOAD6(23);
    LOAD6(24); LOAD6(25); LOAD6(26); LOAD6(27);
    LOAD6(28); LOAD6(29); LOAD6(30); LOAD6(31);

    // No second Blake2b โ€” XOR the sum directly into the accumulator.
    atomic_fetch_xor_explicit(&acc[0], (uint)(sum[0] & 0xFFFFFFFFUL), memory_order_relaxed);
    atomic_fetch_xor_explicit(&acc[1], (uint)(sum[0] >> 32),          memory_order_relaxed);
    atomic_fetch_xor_explicit(&acc[2], (uint)(sum[1] & 0xFFFFFFFFUL), memory_order_relaxed);
    atomic_fetch_xor_explicit(&acc[3], (uint)(sum[1] >> 32),          memory_order_relaxed);
    atomic_fetch_xor_explicit(&acc[4], (uint)(sum[2] & 0xFFFFFFFFUL), memory_order_relaxed);
    atomic_fetch_xor_explicit(&acc[5], (uint)(sum[2] >> 32),          memory_order_relaxed);
    atomic_fetch_xor_explicit(&acc[6], (uint)(sum[3] & 0xFFFFFFFFUL), memory_order_relaxed);
    atomic_fetch_xor_explicit(&acc[7], (uint)(sum[3] >> 32),          memory_order_relaxed);
}

Graph