vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
use vyre::ir::{BufferDecl, DataType, Expr, Node, Program};
use vyre_conform::{reference::interp, spec::value::Value};

macro_rules! test_unary_op {
    ($name:ident, $op_id:literal, $cases:tt) => {
        #[test]
        fn $name() {
            let program = Program::new(
                vec![
                    BufferDecl::read("input", 0, DataType::U32),
                    BufferDecl::read_write("out", 1, DataType::U32),
                ],
                [1, 1, 1],
                vec![Node::store(
                    "out",
                    Expr::u32(0),
                    Expr::call($op_id, vec![Expr::load("input", Expr::u32(0))]),
                )],
            );
            let cases: &[(u32, u32, &str)] = &$cases;
            for &(input, expected, note) in cases {
                let outputs = interp::run(&program, &[Value::U32(input)]).unwrap();
                assert_eq!(outputs.len(), 1);
                assert_eq!(
                    outputs[0].to_bytes(),
                    Value::U32(expected).to_bytes(),
                    "{}: input={:08x} expected={:08x} — {}",
                    $op_id,
                    input,
                    expected,
                    note
                );
            }
        }
    };
}

macro_rules! test_binary_op {
    ($name:ident, $op_id:literal, $cases:tt) => {
        #[test]
        fn $name() {
            let program = Program::new(
                vec![
                    BufferDecl::read("a", 0, DataType::U32),
                    BufferDecl::read("b", 1, DataType::U32),
                    BufferDecl::read_write("out", 2, DataType::U32),
                ],
                [1, 1, 1],
                vec![Node::store(
                    "out",
                    Expr::u32(0),
                    Expr::call(
                        $op_id,
                        vec![Expr::load("a", Expr::u32(0)), Expr::load("b", Expr::u32(0))],
                    ),
                )],
            );
            let cases: &[(u32, u32, u32, &str)] = &$cases;
            for &(a, b, expected, note) in cases {
                let outputs = interp::run(&program, &[Value::U32(a), Value::U32(b)]).unwrap();
                assert_eq!(outputs.len(), 1);
                assert_eq!(
                    outputs[0].to_bytes(),
                    Value::U32(expected).to_bytes(),
                    "{}: a={:08x} b={:08x} expected={:08x} — {}",
                    $op_id,
                    a,
                    b,
                    expected,
                    note
                );
            }
        }
    };
}

// ─── Bitwise unary ops ────────────────────────────────────────────────
include!("reference_self_test/bitwise_unary.rs");

// ─── Bitwise binary ops (and, or, xor) ───────────────────────────────
include!("reference_self_test/bitwise_binary.rs");

// ─── Bitwise shift and rotate ops ────────────────────────────────────
include!("reference_self_test/bitwise_shift_rotate.rs");

// ─── Bitwise extract/insert ops ──────────────────────────────────────
include!("reference_self_test/bitwise_extract_insert.rs");

// ─── Math unary ops ──────────────────────────────────────────────────
include!("reference_self_test/math_unary.rs");

// ─── Math binary ops (add, sub, mul, div, mod, min, max, clamp) ─────
include!("reference_self_test/math_binary.rs");

// ─── Math extra ops (add_sat, sub_sat, abs_diff, gcd, lcm) ──────────
include!("reference_self_test/math_extra.rs");

// ─── Math signed ops (neg, sign) ────────────────────────────────────
include!("reference_self_test/math_signed.rs");

// ─── Compare unary ops ──────────────────────────────────────────────
include!("reference_self_test/compare_unary.rs");

// ─── Compare binary ops (eq, ne, lt, gt, le, ge, select, logical) ───
include!("reference_self_test/compare_binary.rs");