vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
use super::{pair_bytes, sig, triple_bytes, u32_bytes, InputGenerator};
use crate::spec::types::OpSignature;

/// Generates uniformly random u32 and u32-pair inputs with deterministic seeding.
pub struct RandomUniform;

struct XorShift64 {
    state: u64,
}

impl XorShift64 {
    fn new(seed: u64) -> Self {
        let state = if seed == 0 {
            0x9E37_79B9_7F4A_7C15
        } else {
            seed
        };
        Self { state }
    }

    fn next_u32(&mut self) -> u32 {
        let mut x = self.state;
        x ^= x << 13;
        x ^= x >> 7;
        x ^= x << 17;
        self.state = x;
        (x >> 32) as u32
    }
}

impl InputGenerator for RandomUniform {
    fn name(&self) -> &'static str {
        "random_uniform"
    }

    fn handles(&self, signature: &OpSignature) -> bool {
        sig::is_u32_any(signature) || sig::is_byte_input(signature)
    }

    fn generate(&self, signature: &OpSignature, seed: u64) -> Vec<(String, Vec<u8>)> {
        let mut rng = XorShift64::new(seed);
        if sig::is_unary_u32(signature) {
            (0..1024)
                .map(|idx| {
                    let value = rng.next_u32();
                    (format!("random:u32:{idx}"), u32_bytes(value))
                })
                .collect()
        } else if sig::is_binary_u32(signature) {
            (0..2048)
                .map(|idx| {
                    let left = rng.next_u32();
                    let right = rng.next_u32();
                    (format!("random:pair:{idx}"), pair_bytes(left, right))
                })
                .collect()
        } else if sig::is_ternary_u32(signature) {
            (0..2048)
                .map(|idx| {
                    let a = rng.next_u32();
                    let b = rng.next_u32();
                    let c = rng.next_u32();
                    (format!("random:triple:{idx}"), triple_bytes(a, b, c))
                })
                .collect()
        } else if sig::is_byte_input(signature) {
            random_buffers(&mut rng)
        } else {
            Vec::new()
        }
    }
}

fn random_buffers(rng: &mut XorShift64) -> Vec<(String, Vec<u8>)> {
    let mut out = Vec::with_capacity(128);
    for idx in 0..128 {
        let len = (rng.next_u32() as usize) % 4097;
        let mut bytes = Vec::with_capacity(len);
        for _ in 0..len {
            bytes.push((rng.next_u32() & 0xFF) as u8);
        }
        out.push((format!("random:bytes:{idx}:len{len}"), bytes));
    }
    out
}