igneum/proto-cuda/packs-readwidth/scr4k128/kernel_bound.cu

136 lines
9.6 KiB
Text

// Generated by igneum-pow export (generator v2) for seed "igneum-genesis". Do not edit by hand.
// Header-bound twin of igneum_hash in kernel.cu: the init words come from a kernel argument, not SEEDW.
// Host declarations (also in program_bound.h if present):
// struct IgneumInitWords { uint32_t w[8]; };
// cudaError_t igneum_launch_hash_bound(const uint32_t* ds, uint64_t* out, uint32_t baseNonce, uint32_t mask,
// IgneumInitWords iw, uint32_t nonces, uint32_t blockWarps);
// cudaError_t igneum_hash_bound_info(int* numRegs, int* blocksPerSM, uint32_t blockWarps);
#include <cuda_runtime.h>
#include <cstdint>
#include "program.h"
struct IgneumInitWords { uint32_t w[8]; };
__device__ __forceinline__ uint32_t splitmix32(uint32_t x) {
x ^= x >> 16; x *= 0x7feb352du;
x ^= x >> 15; x *= 0x846ca68bu;
x ^= x >> 16;
return x;
}
__device__ __forceinline__ uint32_t rotl_imm(uint32_t x, uint32_t n) { return (x << n) | (x >> (32u - n)); }
__device__ __forceinline__ uint32_t rotr_var(uint32_t x, uint32_t n) { n &= 31u; return (x >> n) | (x << ((32u - n) & 31u)); }
// Variant 5 (read-width experiment, 5 October 2026, NOT the lottery hash): a 128 KiB scratch per warp, 256 slots of
// 16 bytes per lane, lane-major. A slot starts the unit as the fill words below (tagged lazily: a slot whose tag is not
// this unit's reads as its fill) and holds what the unit wrote afterwards. scr_fill mirrors verify::scratch_fill.
__device__ __forceinline__ uint32_t scr_fill(uint32_t gbase, uint32_t lane, uint32_t slot, uint32_t j) { uint32_t sw = (j == 0u) ? 0x67a9a7beu : ((j == 1u) ? 0x1a155b25u : 0xfddfb732u); return splitmix32(((gbase + lane) ^ sw) + slot * 0x9e3779b1u + (j + 1u) * 0x85ebca77u); }
__global__ void igneum_hash_bound(const uint32_t* ds, uint64_t* out, uint32_t baseNonce, uint32_t mask, IgneumInitWords iw, uint32_t* scratch, uint32_t groups, uint32_t salt) {
uint32_t lane = (blockIdx.x * blockDim.x + threadIdx.x) & 31u;
uint32_t warp_ = (blockIdx.x * blockDim.x + threadIdx.x) >> 5;
uint32_t nwarps_ = (gridDim.x * blockDim.x) >> 5;
uint32_t* arena = scratch + ((size_t)warp_ * 32u + lane) * 1024u;
for (uint32_t g_ = warp_; g_ < groups; g_ += nwarps_) {
uint32_t gid = g_ * 32u + lane;
uint32_t gbase = baseNonce + g_ * 32u;
uint32_t tag = salt + g_;
uint32_t nonce = baseNonce + gid;
uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
{ uint32_t x = nonce ^ iw.w[0]; x += 0x9e3779b9u * 1u; x = splitmix32(x); r0 = x ^ iw.w[1]; }
{ uint32_t x = nonce ^ iw.w[1]; x += 0x9e3779b9u * 2u; x = splitmix32(x); r1 = x ^ iw.w[2]; }
{ uint32_t x = nonce ^ iw.w[2]; x += 0x9e3779b9u * 3u; x = splitmix32(x); r2 = x ^ iw.w[3]; }
{ uint32_t x = nonce ^ iw.w[3]; x += 0x9e3779b9u * 4u; x = splitmix32(x); r3 = x ^ iw.w[4]; }
{ uint32_t x = nonce ^ iw.w[4]; x += 0x9e3779b9u * 5u; x = splitmix32(x); r4 = x ^ iw.w[5]; }
{ uint32_t x = nonce ^ iw.w[5]; x += 0x9e3779b9u * 6u; x = splitmix32(x); r5 = x ^ iw.w[6]; }
{ uint32_t x = nonce ^ iw.w[6]; x += 0x9e3779b9u * 7u; x = splitmix32(x); r6 = x ^ iw.w[7]; }
{ uint32_t x = nonce ^ iw.w[7]; x += 0x9e3779b9u * 8u; x = splitmix32(x); r7 = x ^ iw.w[0]; }
for (uint32_t it = 0u; it < 8u; ++it) {
uint32_t sel = r0;
r2 = r3 * r4 + r2; // 0 mad
r1 = r1 + r7 + ((((sel >> 4u) & 1u) != 0u) ? 0xc3bd2355u : 0x42da7657u); // 1 add
r2 = r2 + r3 + ((((sel >> 26u) & 1u) != 0u) ? 0x2735a174u : 0x61f0b51cu); // 2 add
r4 = r0 * r6 + r4; // 3 mad
r7 = r7 ^ ds[r2 & mask]; // 4 load
r4 = r4 ^ ds[r1 & mask]; // 5 load
r6 = r6 ^ __shfl_xor_sync(0xffffffffu, r3, 4); // 6 shfl
r1 = r1 ^ __shfl_xor_sync(0xffffffffu, r5, 8); // 7 shfl
r7 = r7 ^ r5; // 8 xor
r3 = r3 | r4; // 9 or
r1 = r1 | r2; // 10 or
r4 = r4 ^ ds[r3 & mask]; // 11 load
r6 = r6 | r2; // 12 or
r2 = r2 * r5; // 13 mul
r1 = r1 ^ ds[r2 & mask]; // 14 load
r7 = rotl_imm(r7, 1u); // 15 rotl
{ uint32_t s_ = r6 & 255u; uint4 v_ = *(const uint4*)(arena + s_ * 4u); uint32_t m_ = (v_.x == tag) ? 0xffffffffu : 0u; uint32_t w0_ = (v_.y & m_) | (scr_fill(gbase, lane, s_, 0u) & ~m_); uint32_t w1_ = (v_.z & m_) | (scr_fill(gbase, lane, s_, 1u) & ~m_); uint32_t w2_ = (v_.w & m_) | (scr_fill(gbase, lane, s_, 2u) & ~m_); uint32_t x_ = r3 ^ w0_; x_ = (rotl_imm(x_, 11u) * 0x9e3779b1u) ^ w1_; x_ = (rotl_imm(x_, 11u) * 0x9e3779b1u) ^ w2_; r3 = x_; *(uint4*)(arena + s_ * 4u) = make_uint4(tag, x_ ^ w1_, rotl_imm(x_, 7u) ^ w2_, x_ + w0_); } // 16 scratch
r7 = r7 ^ ds[r4 & mask]; // 17 load
r3 = r3 ^ __shfl_xor_sync(0xffffffffu, r4, 2); // 18 shfl
r4 = r0 * r2 + r4; // 19 mad
r0 = r0 ^ __shfl_xor_sync(0xffffffffu, r6, 8); // 20 shfl
r5 = r5 ^ r7; // 21 xor
r2 = __umulhi(r2, r5); // 22 mulhi
r3 = r3 ^ ds[r7 & mask]; // 23 load
r7 = __umulhi(r7, r3); // 24 mulhi
r5 = r5 | r4; // 25 or
r4 = r5 * r2 + r4; // 26 mad
r5 = r5 * r1; // 27 mul
r6 = __umulhi(r6, r7); // 28 mulhi
r6 = r6 + r1 + ((((sel >> 9u) & 1u) != 0u) ? 0x187a9128u : 0x3b2d2124u); // 29 add
r6 = rotr_var(r6, r7); // 30 rotr
r3 = r3 ^ ds[r1 & mask]; // 31 load
{ uint32_t s_ = r0 & 255u; uint4 v_ = *(const uint4*)(arena + s_ * 4u); uint32_t m_ = (v_.x == tag) ? 0xffffffffu : 0u; uint32_t w0_ = (v_.y & m_) | (scr_fill(gbase, lane, s_, 0u) & ~m_); uint32_t w1_ = (v_.z & m_) | (scr_fill(gbase, lane, s_, 1u) & ~m_); uint32_t w2_ = (v_.w & m_) | (scr_fill(gbase, lane, s_, 2u) & ~m_); uint32_t x_ = r1 ^ w0_; x_ = (rotl_imm(x_, 11u) * 0x9e3779b1u) ^ w1_; x_ = (rotl_imm(x_, 11u) * 0x9e3779b1u) ^ w2_; r1 = x_; *(uint4*)(arena + s_ * 4u) = make_uint4(tag, x_ ^ w1_, rotl_imm(x_, 7u) ^ w2_, x_ + w0_); } // 32 scratch
r0 = r0 + r4 + ((((sel >> 18u) & 1u) != 0u) ? 0x351dde38u : 0x2c35699fu); // 33 add
{ uint32_t s_ = r2 & 255u; uint4 v_ = *(const uint4*)(arena + s_ * 4u); uint32_t m_ = (v_.x == tag) ? 0xffffffffu : 0u; uint32_t w0_ = (v_.y & m_) | (scr_fill(gbase, lane, s_, 0u) & ~m_); uint32_t w1_ = (v_.z & m_) | (scr_fill(gbase, lane, s_, 1u) & ~m_); uint32_t w2_ = (v_.w & m_) | (scr_fill(gbase, lane, s_, 2u) & ~m_); uint32_t x_ = r0 ^ w0_; x_ = (rotl_imm(x_, 11u) * 0x9e3779b1u) ^ w1_; x_ = (rotl_imm(x_, 11u) * 0x9e3779b1u) ^ w2_; r0 = x_; *(uint4*)(arena + s_ * 4u) = make_uint4(tag, x_ ^ w1_, rotl_imm(x_, 7u) ^ w2_, x_ + w0_); } // 34 scratch
r0 = r0 * r3; // 35 mul
r2 = r2 ^ r5; // 36 xor
r4 = r4 ^ ds[r0 & mask]; // 37 load
r1 = r3 * r5 + r1; // 38 mad
r0 = r0 + r3 + ((((sel >> 25u) & 1u) != 0u) ? 0x1b053acfu : 0xa907b90bu); // 39 add
r2 = rotr_var(r2, r5); // 40 rotr
r3 = r3 * r2; // 41 mul
r1 = r1 + r5 + ((((sel >> 20u) & 1u) != 0u) ? 0x6058c2e3u : 0xa32e000cu); // 42 add
r3 = r3 ^ r4; // 43 xor
r3 = r3 ^ ds[r5 & mask]; // 44 load
r1 = r1 + r5 + ((((sel >> 7u) & 1u) != 0u) ? 0x1907970cu : 0x81b8bc2cu); // 45 add
r7 = r7 ^ r1; // 46 xor
r0 = r0 + r3 + ((((sel >> 31u) & 1u) != 0u) ? 0x36360066u : 0x838b5065u); // 47 add
r7 = __umulhi(r7, r5); // 48 mulhi
r0 = r0 ^ ds[r2 & mask]; // 49 load
r2 = r2 - r6; // 50 sub
r7 = r7 - r5; // 51 sub
r2 = r2 ^ r3; // 52 xor
r7 = r7 - r0; // 53 sub
r3 = r5 * r0 + r3; // 54 mad
r7 = r7 ^ r5; // 55 xor
r2 = r2 ^ ds[r7 & mask]; // 56 load
r5 = r5 - r6; // 57 sub
r1 = r1 ^ ds[r3 & mask]; // 58 load
{ uint32_t s_ = r4 & 255u; uint4 v_ = *(const uint4*)(arena + s_ * 4u); uint32_t m_ = (v_.x == tag) ? 0xffffffffu : 0u; uint32_t w0_ = (v_.y & m_) | (scr_fill(gbase, lane, s_, 0u) & ~m_); uint32_t w1_ = (v_.z & m_) | (scr_fill(gbase, lane, s_, 1u) & ~m_); uint32_t w2_ = (v_.w & m_) | (scr_fill(gbase, lane, s_, 2u) & ~m_); uint32_t x_ = r1 ^ w0_; x_ = (rotl_imm(x_, 11u) * 0x9e3779b1u) ^ w1_; x_ = (rotl_imm(x_, 11u) * 0x9e3779b1u) ^ w2_; r1 = x_; *(uint4*)(arena + s_ * 4u) = make_uint4(tag, x_ ^ w1_, rotl_imm(x_, 7u) ^ w2_, x_ + w0_); } // 59 scratch
r4 = r4 - r6; // 60 sub
r1 = r1 * r2; // 61 mul
r3 = r6 * r0 + r3; // 62 mad
r0 = r0 + r1 + ((((sel >> 16u) & 1u) != 0u) ? 0xc88e2942u : 0x2fe0e98bu); // 63 add
}
uint32_t lo = r0 ^ rotl_imm(r1, 7u) ^ rotl_imm(r2, 14u) ^ rotl_imm(r3, 21u);
uint32_t hi = r4 ^ rotl_imm(r5, 9u) ^ rotl_imm(r6, 18u) ^ rotl_imm(r7, 27u);
out[gid] = ((uint64_t)hi << 32) | (uint64_t)lo;
}
}
// Variant 5: the wrapper launches `warps` persistent warps over `nonces / 32` units (host.cu does not use it).
cudaError_t igneum_launch_hash_bound(const uint32_t* ds, uint64_t* out, uint32_t baseNonce, uint32_t mask,
IgneumInitWords iw, uint32_t nonces, uint32_t blockWarps, uint32_t* scratch, uint32_t warps, uint32_t salt) {
if (blockWarps == 0u || blockWarps > 32u || warps == 0u || (warps % blockWarps) != 0u) return cudaErrorInvalidValue;
uint32_t block = 32u * blockWarps;
if (nonces == 0u || (nonces % (32u * warps)) != 0u) return cudaErrorInvalidValue;
igneum_hash_bound<<<warps / blockWarps, block>>>(ds, out, baseNonce, mask, iw, scratch, nonces / 32u, salt);
return cudaGetLastError();
}
cudaError_t igneum_hash_bound_info(int* numRegs, int* blocksPerSM, uint32_t blockWarps) {
cudaFuncAttributes attr;
cudaError_t e = cudaFuncGetAttributes(&attr, igneum_hash_bound);
if (e != cudaSuccess) return e;
*numRegs = attr.numRegs;
return cudaOccupancyMaxActiveBlocksPerMultiprocessor(blocksPerSM, igneum_hash_bound, (int)(32u * blockWarps), 0);
}