cyb/honeycrisp/acpu/tests/gemv_admission.rs

#![cfg(target_arch = "aarch64")]

use acpu::gemm::{
    gemv_amx_asm::gemv_pure_asm,
    gemv_kern::gemv_asm,
    matvec::{matvec_f32, matvec_f32_set},
};
use std::panic::{catch_unwind, AssertUnwindSafe};

type Kernel = fn(&[f32], &[f32], &mut [f32], usize, usize);

fn kernels() -> [Kernel; 4] {
    [matvec_f32, matvec_f32_set, gemv_asm, gemv_pure_asm]
}

#[test]
fn malformed_dimensions_preserve_output() {
    for kernel in kernels() {
        for (a_len, b_len, c_len) in [(7, 64, 8), (8, 63, 8), (8, 64, 7)] {
            let a = vec![1.0; a_len];
            let b = vec![2.0; b_len];
            let mut c = vec![13.5; c_len];
            let before = c.clone();
            assert!(catch_unwind(AssertUnwindSafe(|| kernel(&a, &b, &mut c, 8, 8))).is_err());
            assert_eq!(c, before);
        }
    }
}

#[test]
fn overflowing_dimensions_preserve_output() {
    for kernel in kernels() {
        let mut c = [13.5; 3];
        let error = catch_unwind(AssertUnwindSafe(|| {
            kernel(&[1.0; 8], &[], &mut c, usize::MAX, 8);
        }))
        .expect_err("overflowing dimensions must fail before access");
        let message = error
            .downcast_ref::<String>()
            .map(String::as_str)
            .or_else(|| error.downcast_ref::<&str>().copied())
            .unwrap_or("");
        assert!(message.contains("k*n overflow"), "{message}");
        assert_eq!(c, [13.5; 3]);
    }
}

#[test]
fn pure_assembly_retains_k_multiple_of_eight_precondition() {
    let mut c = [13.5; 8];
    assert!(catch_unwind(AssertUnwindSafe(|| {
        gemv_pure_asm(&[1.0; 7], &[2.0; 56], &mut c, 8, 7);
    }))
    .is_err());
    assert_eq!(c, [13.5; 8]);
}

#[test]
fn empty_dimensions_follow_accumulate_and_overwrite_contracts() {
    for kernel in kernels() {
        kernel(&[], &[], &mut [], 0, 0);
        kernel(&[1.0; 8], &[], &mut [], 0, 8);
    }
    for n in [1, 16, 128, 1024, 1025] {
        let mut c = vec![13.5; n];
        matvec_f32(&[], &[], &mut c, n, 0);
        assert_eq!(c, vec![13.5; n]);
        for kernel in [matvec_f32_set, gemv_asm, gemv_pure_asm] {
            c.fill(13.5);
            kernel(&[], &[], &mut c, n, 0);
            assert_eq!(c, vec![0.0; n]);
        }
    }
}

Graph