diff --git a/.github/workflows/testable-simd-models.yml b/.github/workflows/testable-simd-models.yml new file mode 100644 index 0000000000000..7bd27d768fd12 --- /dev/null +++ b/.github/workflows/testable-simd-models.yml @@ -0,0 +1,31 @@ +# This workflow runs the tests for testable simd models. + +name: Testable simd models + +on: + workflow_dispatch: + merge_group: + pull_request: + branches: [ main ] + push: + paths: + - '.github/workflows/testable-simd-models.yml' + - 'testable-simd-models/**' + +defaults: + run: + shell: bash + +jobs: + testable-simd-models: + name: Test testable simd models + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Run tests + working-directory: testable-simd-models + run: cargo test -- --test-threads=1 --nocapture + \ No newline at end of file diff --git a/testable-simd-models/README.md b/testable-simd-models/README.md index 470c51072c8e5..ca552bfe843f9 100644 --- a/testable-simd-models/README.md +++ b/testable-simd-models/README.md @@ -125,10 +125,11 @@ pub fn phaddw(a: i16x16, b: i16x16) -> i16x16 { ### Modeling defined intrinsics semi-automatically -To model a defined intrinsic, we essentially copy the Rust code of -the intrinsic from `core::arch` and adapt it to use our underlying abstractions. The -changes needed to the code are sometimes scriptable, and indeed most -of our models were generated from a script, but some changes are still +To model a defined intrinsic, we essentially copy the Rust code of the +intrinsic from `core::arch` and adapt it to use our underlying +abstractions. The changes needed to the code are sometimes +scriptable, and indeed most of our models were generated from a script +(see the ANNEX at the bottom of this file), but some changes are still needed by hand. For example, let us say the intrinsic we are modeling is @@ -176,8 +177,19 @@ pub fn _mm256_bsrli_epi128(a: __m256i) -> __m256i { ``` Thus, we then go to `core_arch/x86/models/avx2.rs`, and add this implementation. -The only change it requires here is that the `simd_shuffle` macro is a function in our model, -and we discard all the function attributes. +The only changes it requires here are that the `simd_shuffle` macro is a function in our model, +the `ZERO` constant is now a function, and we discard all the function attributes. + +The exact diff between the original and edited code for this function is: + +```diff +13,14c13,14 +< let r: i8x32 = simd_shuffle( +< i8x32::ZERO(), +--- +> let r: i8x32 = simd_shuffle!( +> i8x32::ZERO, +``` For other intrinsics, we sometimes need to make more changes. Since our model of the builtin intrinsics is more precise concerning the type of their arguments compared to their Rust counterparts, we @@ -224,3 +236,84 @@ us](https://github.com/rust-lang/stdarch/issues/1822) using a failing test case generated from the testable model and then fixed by [our PR](https://github.com/rust-lang/stdarch/pull/1823) in the 2025-06-30 version of `stdarch`. + + +## ANNEX: Extraction Script + +The following Rust program is a simple script that uses the `syn` crate to process an input Rust file +containing SIMD intrinsics into one suitable for the models described in this document. This code +is provided as illustration; for each set of core libraries we wish to model and test, there will +likely be need for a similar (or extended) script to automate the modeling process. + +```rust +use syn::*; +use std::fs; +use std::env; + +fn extract_model(input_file_path: &str, output_file_path: &str) -> Result<()> { + let source_code = fs::read_to_string(input_file_path).expect("unable to read file"); + let mut syntax_tree: File = parse_file(&source_code)?; + + syntax_tree.items.retain(|item| + match item { + Item::Use(_) => false, + _ => true + } + ); + + // Clear attributes from the file's top-level items + for item in &mut syntax_tree.items { + match item { + Item::Const(const_item) => { + const_item.attrs.retain(|attr| attr.path().is_ident("doc")); + }, + Item::Fn(item_fn) => { + item_fn.attrs.retain(|attr| attr.path().is_ident("doc")); + item_fn.block.stmts.retain(|stmt| + match stmt { + Stmt::Item(Item::ForeignMod(_)) => false, + _ => true + } + ); + for stmt in &mut item_fn.block.stmts { + match stmt { + Stmt::Expr(Expr::Unsafe(u), tok) => *stmt = Stmt::Expr(Expr::Block( + ExprBlock {attrs : Vec::new(), label : None, block : u.block.clone()}), *tok), + _ => () + } + } + }, + Item::Struct(item_struct) => { + item_struct.attrs.clear(); + for field in &mut item_struct.fields { + field.attrs.retain(|attr| attr.path().is_ident("doc")); + } + }, + Item::Enum(item_enum) => { + item_enum.attrs.clear(); + for variant in &mut item_enum.variants { + variant.attrs.retain(|attr| attr.path().is_ident("doc")); + } + }, + // Add more cases for other Item types (e.g., Item::Mod, Item::Impl, etc.) + _ => { + // For other item types, if they have an 'attrs' field, clear it. + // This requires more specific matching or a helper trait. + } + } + } + + let formatted_string = prettyplease::unparse(&syntax_tree); + fs::write(output_file_path, formatted_string).expect("unable to write file"); + + Ok(()) +} + +fn main() -> Result<()> { + let args: Vec = env::args().collect(); + if args.len() < 3 { + println!("usage: modelize ") + } + extract_model(&args[1], &args[2]) +} +``` diff --git a/testable-simd-models/src/abstractions/bitvec.rs b/testable-simd-models/src/abstractions/bitvec.rs index ac73749482e37..74e7141fc5266 100644 --- a/testable-simd-models/src/abstractions/bitvec.rs +++ b/testable-simd-models/src/abstractions/bitvec.rs @@ -106,16 +106,6 @@ impl BitVec { .map(int_from_bit_slice) .collect() } - - /// Generate a random BitVec. - pub fn rand() -> Self { - use rand::prelude::*; - let random_source: Vec<_> = { - let mut rng = rand::rng(); - (0..N).map(|_| rng.random::()).collect() - }; - Self::from_fn(|i| random_source[i as usize].into()) - } } impl BitVec { diff --git a/testable-simd-models/src/core_arch/arm_shared/models/neon.rs b/testable-simd-models/src/core_arch/arm_shared/models/neon.rs index 794fd25285b47..1cdca6f62512f 100644 --- a/testable-simd-models/src/core_arch/arm_shared/models/neon.rs +++ b/testable-simd-models/src/core_arch/arm_shared/models/neon.rs @@ -870,4 +870,4 @@ pub fn vcle_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { pub fn vcleq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { simd_le(a, b) -} +} \ No newline at end of file diff --git a/testable-simd-models/src/core_arch/x86/models/avx2_handwritten.rs b/testable-simd-models/src/core_arch/x86/models/avx2_handwritten.rs index 43f0a840b54bd..1183eb2524edf 100644 --- a/testable-simd-models/src/core_arch/x86/models/avx2_handwritten.rs +++ b/testable-simd-models/src/core_arch/x86/models/avx2_handwritten.rs @@ -419,7 +419,6 @@ pub fn psravd(a: i32x4, count: i32x4) -> i32x4 { } pub fn psravd256(a: i32x8, count: i32x8) -> i32x8 { - dbg!(a, count); i32x8::from_fn(|i| { if count[i] > 31 || count[i] < 0 { if a[i] < 0 { diff --git a/testable-simd-models/src/core_arch/x86/tests/avx.rs b/testable-simd-models/src/core_arch/x86/tests/avx.rs index 02b1d81173ad0..c6e8684d32ca5 100644 --- a/testable-simd-models/src/core_arch/x86/tests/avx.rs +++ b/testable-simd-models/src/core_arch/x86/tests/avx.rs @@ -49,7 +49,9 @@ fn _mm256_movemask_ps() { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx::_mm256_movemask_ps(a.into()), - unsafe { upstream::_mm256_movemask_ps(a.into()) } + unsafe { upstream::_mm256_movemask_ps(a.into()) }, + "Failed with input value: {:?}", + a ); } } @@ -62,7 +64,9 @@ fn _mm256_movemask_pd() { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx::_mm256_movemask_pd(a.into()), - unsafe { upstream::_mm256_movemask_pd(a.into()) } + unsafe { upstream::_mm256_movemask_pd(a.into()) }, + "Failed with input value: {:?}", + a ); } } @@ -76,7 +80,10 @@ fn _mm256_testz_si256() { let b: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx::_mm256_testz_si256(a.into(), b.into()), - unsafe { upstream::_mm256_testz_si256(a.into(), b.into()) } + unsafe { upstream::_mm256_testz_si256(a.into(), b.into()) }, + "Failed with input values: {:?}, {:?}", + a, + b ); } } @@ -90,7 +97,10 @@ fn _mm256_testc_si256() { let b: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx::_mm256_testc_si256(a.into(), b.into()), - unsafe { upstream::_mm256_testc_si256(a.into(), b.into()) } + unsafe { upstream::_mm256_testc_si256(a.into(), b.into()) }, + "Failed with input values: {:?}, {:?}", + a, + b ); } } @@ -116,7 +126,9 @@ fn _mm256_cvtsi256_si32() { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx::_mm256_cvtsi256_si32(a.into()), - unsafe { upstream::_mm256_cvtsi256_si32(a.into()) } + unsafe { upstream::_mm256_cvtsi256_si32(a.into()) }, + "Failed with input value: {:?}", + a ); } } diff --git a/testable-simd-models/src/core_arch/x86/tests/avx2.rs b/testable-simd-models/src/core_arch/x86/tests/avx2.rs index dcabcbb58b1e0..50ca3c63b4813 100644 --- a/testable-simd-models/src/core_arch/x86/tests/avx2.rs +++ b/testable-simd-models/src/core_arch/x86/tests/avx2.rs @@ -120,7 +120,9 @@ fn _mm256_movemask_epi8() { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_movemask_epi8(a.into()), - unsafe { upstream::_mm256_movemask_epi8(a.into()) } + unsafe { upstream::_mm256_movemask_epi8(a.into()) }, + "Failed with input value: {:?}", + a ); } } @@ -191,224 +193,288 @@ fn _mm256_extract_epi8() { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<0>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<0>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<0>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<1>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<1>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<1>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<2>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<2>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<2>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<3>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<3>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<3>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<4>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<4>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<4>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<5>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<5>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<5>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<6>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<6>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<6>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<7>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<7>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<7>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<8>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<8>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<8>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<9>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<9>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<9>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<10>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<10>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<10>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<11>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<11>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<11>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<12>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<12>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<12>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<13>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<13>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<13>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<14>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<14>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<14>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<15>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<15>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<15>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<16>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<16>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<16>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<17>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<17>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<17>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<18>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<18>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<18>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<19>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<19>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<19>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<20>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<20>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<20>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<21>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<21>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<21>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<22>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<22>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<22>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<23>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<23>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<23>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<24>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<24>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<24>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<25>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<25>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<25>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<26>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<26>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<26>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<27>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<27>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<27>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<28>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<28>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<28>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<29>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<29>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<29>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<30>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<30>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<30>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi8::<31>(a.into()), - unsafe { upstream::_mm256_extract_epi8::<31>(a.into()) } + unsafe { upstream::_mm256_extract_epi8::<31>(a.into()) }, + "Failed with input value: {:?}", + a ); } } @@ -421,112 +487,144 @@ fn _mm256_extract_epi16() { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<0>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<0>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<0>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<1>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<1>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<1>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<2>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<2>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<2>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<3>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<3>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<3>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<4>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<4>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<4>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<5>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<5>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<5>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<6>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<6>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<6>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<7>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<7>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<7>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<8>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<8>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<8>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<9>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<9>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<9>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<10>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<10>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<10>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<11>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<11>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<11>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<12>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<12>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<12>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<13>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<13>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<13>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<14>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<14>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<14>(a.into()) }, + "Failed with input value: {:?}", + a ); } for _ in 0..n { let a: BitVec<256> = BitVec::random(); assert_eq!( super::super::models::avx2::_mm256_extract_epi16::<15>(a.into()), - unsafe { upstream::_mm256_extract_epi16::<15>(a.into()) } + unsafe { upstream::_mm256_extract_epi16::<15>(a.into()) }, + "Failed with input value: {:?}", + a ); } } diff --git a/testable-simd-models/src/helpers.rs b/testable-simd-models/src/helpers.rs index 1a30bf251a877..2d58cde1b71f8 100644 --- a/testable-simd-models/src/helpers.rs +++ b/testable-simd-models/src/helpers.rs @@ -2,6 +2,13 @@ pub mod test { use crate::abstractions::{bit::Bit, bitvec::BitVec, funarr::FunArray}; use rand::prelude::*; + use std::sync::{LazyLock, Mutex}; + + static RNG: LazyLock> = LazyLock::new(|| { + let seed = rand::rng().random(); + println!("\nRandomness seed set to: {:?}", seed); + Mutex::new(StdRng::from_seed(seed)) + }); /// Helper trait to generate random values pub trait HasRandom { @@ -11,8 +18,7 @@ pub mod test { ($($ty:ty),*) => { $(impl HasRandom for $ty { fn random() -> Self { - let mut rng = rand::rng(); - rng.random() + RNG.lock().unwrap().random() } })* };