//! Consistency checks across emulated execution backends. use crate::{ Operation, Simd, emulated::{EmulatedArmV9, EmulatedNeon, EmulatedScalar, EmulatedX86V3, EmulatedX86V4C}, }; use core::fmt::Debug; /// Checks that an operation produces the same result on every emulated backend. /// /// Together, [`EmulatedScalar`], [`EmulatedX86V3`], [`EmulatedX86V4C`], [`EmulatedArmV9`], /// and [`EmulatedNeon`] cover every lane count and algorithm path that /// [`dispatch`](crate::dispatch()) can select. /// /// Call this for each input generated by a test or fuzz harness. `operation` must /// construct a fresh operation with equivalent inputs on each invocation, including /// resetting any mutable state. It is called once per backend because execution /// consumes the operation. /// /// All emulated backends must produce the same output type. Normalize any /// backend-specific registers at this outer boundary. /// /// Include observable buffer changes in [`Operation::Output`] to compare them as well. /// Agreement between backends does not establish correctness against an independent /// reference implementation. /// /// # Panics /// /// Panics if any backend's output differs from the scalar output, or if constructing /// or executing an operation panics. /// /// # Examples /// /// ``` /// use commonware_simd::{check_consistent, Operation, Simd}; /// /// struct Add; /// impl Operation for Add { /// type Output = u32; /// fn portable(self, simd: S) -> u32 { /// let mut output = [0; 16]; /// simd.u32_store(simd.u32_add(simd.u32_splat(1), simd.u32_splat(2)), &mut output); /// output[0] /// } /// } /// check_consistent(|| Add); /// ``` pub fn check_consistent(mut operation: impl FnMut() -> O) where O: Operation + Operation + Operation + Operation + Operation, R: PartialEq + Debug, { let expected = EmulatedScalar.execute(operation()); assert_eq!( EmulatedX86V3.execute(operation()), expected, "EmulatedX86V3 differs from EmulatedScalar" ); assert_eq!( EmulatedX86V4C.execute(operation()), expected, "EmulatedX86V4C differs from EmulatedScalar" ); assert_eq!( EmulatedArmV9.execute(operation()), expected, "EmulatedArmV9 differs from EmulatedScalar" ); assert_eq!( EmulatedNeon.execute(operation()), expected, "EmulatedNeon differs from EmulatedScalar" ); }