vyre 0.4.0

GPU compute intermediate representation with a standard operation library
Documentation
use crate::ir::{BufferDecl, DataType, Expr, Node, Program};
use crate::ops::AlgebraicLaw;
use crate::ops::{OpSpec, BYTES_TO_U32_OUTPUTS};

// WGSL lowering marker for `hash.fnv1a32`.
//
// No special handling is needed. The generic Category A lowerer emits the
// IR composition from `kernel.rs`.

/// Spec-table check value: `hash(empty) == 2166136261`.
pub const EMPTY_HASH: u32 = FNV_OFFSET_BASIS;

/// Build the canonical FNV-1a 32-bit hashing program.
#[must_use]
pub fn fnv1a_program() -> Program {
    Program::new(
        vec![
            BufferDecl::read("input", 0, DataType::Bytes),
            BufferDecl::output("out", 1, DataType::U32),
        ],
        [1, 1, 1],
        vec![
            Node::let_bind("hash", Expr::u32(FNV_OFFSET_BASIS)),
            Node::loop_for(
                "pos",
                Expr::u32(0),
                Expr::buf_len("input"),
                vec![Node::assign(
                    "hash",
                    Expr::mul(
                        Expr::bitxor(Expr::var("hash"), input_byte(Expr::var("pos"))),
                        Expr::u32(FNV_PRIME),
                    ),
                )],
            ),
            Node::if_then(
                Expr::lt(Expr::u32(0), Expr::buf_len("out")),
                vec![Node::store("out", Expr::u32(0), Expr::var("hash"))],
            ),
        ],
    )
}

pub const FNV_OFFSET_BASIS: u32 = 2_166_136_261;

pub const FNV_PRIME: u32 = 16_777_619;

pub fn input_byte(index: Expr) -> Expr {
    Expr::bitand(Expr::load("input", index), Expr::u32(0xff))
}

pub const INPUTS: &[DataType] = &[DataType::Bytes];

pub const LAWS: &[AlgebraicLaw] = &[AlgebraicLaw::Bounded {
    lo: 0,
    hi: u32::MAX,
}];

/// Spec-table check value for a single byte.
#[must_use]
pub const fn single_byte_hash(byte: u32) -> u32 {
    (FNV_OFFSET_BASIS ^ (byte & 0xff)).wrapping_mul(FNV_PRIME)
}

/// Declarative operation specification for `hash.fnv1a32`.
pub const SPEC: OpSpec = OpSpec::composition(
    "hash.fnv1a32",
    INPUTS,
    BYTES_TO_U32_OUTPUTS,
    LAWS,
    fnv1a_program,
);