vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! Deterministic witness RNG for algebra law checking.

/// Deterministic PRNG seeded from op id and law name.
#[cfg(loom)]
pub struct SimpleRng {
    state: u64,
}

/// Deterministic PRNG seeded from op id and law name.
#[cfg(not(loom))]
pub(crate) struct SimpleRng {
    state: u64,
}

impl SimpleRng {
    #[cfg(loom)]
    /// Return the next deterministic u32 witness.
    #[inline]
    pub fn next_u32(&mut self) -> u32 {
        next_u32(&mut self.state)
    }

    #[cfg(not(loom))]
    /// Return the next deterministic u32 witness.
    #[inline]
    pub(crate) fn next_u32(&mut self) -> u32 {
        next_u32(&mut self.state)
    }
}

fn next_u32(state: &mut u64) -> u32 {
    *state = state.wrapping_add(0x9E37_79B9_7F4A_7C15);
    let mut z = *state;
    z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
    z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
    z = z ^ (z >> 31);
    z as u32
}

#[cfg(loom)]
/// Build a deterministic RNG for a law checker.
#[inline]
pub fn simple_rng(op_id: &str, law_name: &str) -> SimpleRng {
    SimpleRng {
        state: seed(op_id, law_name),
    }
}

#[cfg(not(loom))]
/// Build a deterministic RNG for a law checker.
#[inline]
pub(crate) fn simple_rng(op_id: &str, law_name: &str) -> SimpleRng {
    SimpleRng {
        state: seed(op_id, law_name),
    }
}

fn seed(op_id: &str, law_name: &str) -> u64 {
    let mut hash = 0xcbf2_9ce4_8422_2325_u64;
    if let Ok(seed) = std::env::var("VYRE_CONFORM_SEED") {
        mix_bytes(&mut hash, seed.as_bytes());
    }
    mix_bytes(&mut hash, op_id.as_bytes());
    mix_bytes(&mut hash, law_name.as_bytes());
    hash
}

fn mix_bytes(hash: &mut u64, bytes: &[u8]) {
    for byte in bytes {
        *hash ^= u64::from(*byte);
        *hash = hash.wrapping_mul(0x0000_0100_0000_01B3);
    }
}