diff --git a/ci/intrinsic-test.sh b/ci/intrinsic-test.sh index be63f0c0c6..25a62e79e7 100755 --- a/ci/intrinsic-test.sh +++ b/ci/intrinsic-test.sh @@ -75,7 +75,7 @@ case ${TARGET} in TEST_CXX_COMPILER="clang++" TEST_RUNNER="${CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER}" TEST_SKIP_INTRINSICS=crates/intrinsic-test/missing_x86.txt - : "${TEST_SAMPLE_INTRINSICS_PERCENTAGE:=5}" + : "${TEST_SAMPLE_INTRINSICS_PERCENTAGE:=20}" ;; *) ;; diff --git a/crates/intrinsic-test/missing_x86.txt b/crates/intrinsic-test/missing_x86.txt index 58e37b92a1..53fb965ebb 100644 --- a/crates/intrinsic-test/missing_x86.txt +++ b/crates/intrinsic-test/missing_x86.txt @@ -890,7 +890,7 @@ _mm256_extract_epi16 _mm256_extract_epi8 _mm512_castsi128_si512 _mm512_castsi256_si512 -# _mm512_conj_pch +_mm512_conj_pch _mm512_mask_reduce_max_pd _mm512_mask_reduce_max_ps _mm512_mask_reduce_min_pd @@ -898,7 +898,6 @@ _mm512_mask_reduce_min_ps _mm_comineq_sh _mm_extract_epi16 _mm_extract_epi8 -_mm_mask_cvtepi16_epi8 _mm_mask_cvtpd_epi32 _mm_mask_cvtpd_ps _mm_ucomineq_sh \ No newline at end of file diff --git a/crates/intrinsic-test/src/common/cli.rs b/crates/intrinsic-test/src/common/cli.rs index 461ab542ea..ff34ef3d2d 100644 --- a/crates/intrinsic-test/src/common/cli.rs +++ b/crates/intrinsic-test/src/common/cli.rs @@ -7,12 +7,6 @@ pub enum Language { C, } -pub enum FailureReason { - RunC(String), - RunRust(String), - Difference(String, String, String), -} - /// Intrinsic test tool #[derive(clap::Parser)] #[command( diff --git a/crates/intrinsic-test/src/common/compare.rs b/crates/intrinsic-test/src/common/compare.rs index c0459b743a..c4c2a1e3e4 100644 --- a/crates/intrinsic-test/src/common/compare.rs +++ b/crates/intrinsic-test/src/common/compare.rs @@ -1,7 +1,8 @@ -use super::cli::FailureReason; +use itertools::Itertools; use rayon::prelude::*; -use std::process::Command; +use std::{collections::HashMap, process::Command}; +pub const INTRINSIC_DELIMITER: &str = "############"; fn runner_command(runner: &str) -> Command { let mut it = runner.split_whitespace(); let mut cmd = Command::new(it.next().unwrap()); @@ -11,85 +12,106 @@ fn runner_command(runner: &str) -> Command { } pub fn compare_outputs(intrinsic_name_list: &Vec, runner: &str, target: &str) -> bool { - let intrinsics = intrinsic_name_list - .par_iter() - .filter_map(|intrinsic_name| { - let c = runner_command(runner) + let (c, rust) = rayon::join( + || { + runner_command(runner) .arg("./intrinsic-test-programs") - .arg(intrinsic_name) .current_dir("c_programs") - .output(); - - let rust = runner_command(runner) + .output() + }, + || { + runner_command(runner) .arg(format!("./target/{target}/release/intrinsic-test-programs")) - .arg(intrinsic_name) .current_dir("rust_programs") - .output(); + .output() + }, + ); + let (c, rust) = match (c, rust) { + (Ok(c), Ok(rust)) => (c, rust), + failure => panic!("Failed to run: {failure:#?}"), + }; - let (c, rust) = match (c, rust) { - (Ok(c), Ok(rust)) => (c, rust), - a => panic!("{a:#?}"), - }; + if !c.status.success() { + error!( + "Failed to run C program.\nstdout: {stdout}\nstderr: {stderr}", + stdout = std::str::from_utf8(&c.stdout).unwrap_or(""), + stderr = std::str::from_utf8(&c.stderr).unwrap_or(""), + ); + } - if !c.status.success() { - error!( - "Failed to run C program for intrinsic `{intrinsic_name}`\nstdout: {stdout}\nstderr: {stderr}", - stdout = std::str::from_utf8(&c.stdout).unwrap_or(""), - stderr = std::str::from_utf8(&c.stderr).unwrap_or(""), - ); - return Some(FailureReason::RunC(intrinsic_name.clone())); - } + if !rust.status.success() { + error!( + "Failed to run Rust program.\nstdout: {stdout}\nstderr: {stderr}", + stdout = std::str::from_utf8(&rust.stdout).unwrap_or(""), + stderr = std::str::from_utf8(&rust.stderr).unwrap_or(""), + ); + } - if !rust.status.success() { - error!( - "Failed to run Rust program for intrinsic `{intrinsic_name}`\nstdout: {stdout}\nstderr: {stderr}", - stdout = std::str::from_utf8(&rust.stdout).unwrap_or(""), - stderr = std::str::from_utf8(&rust.stderr).unwrap_or(""), - ); - return Some(FailureReason::RunRust(intrinsic_name.clone())); - } + info!("Completed running C++ and Rust test binaries"); + let c = std::str::from_utf8(&c.stdout) + .unwrap() + .to_lowercase() + .replace("-nan", "nan"); + let rust = std::str::from_utf8(&rust.stdout) + .unwrap() + .to_lowercase() + .replace("-nan", "nan"); - info!("Comparing intrinsic: {intrinsic_name}"); + let c_output_map = c + .split(INTRINSIC_DELIMITER) + .filter_map(|output| output.trim().split_once("\n")) + .collect::>(); + let rust_output_map = rust + .split(INTRINSIC_DELIMITER) + .filter_map(|output| output.trim().split_once("\n")) + .collect::>(); - let c = std::str::from_utf8(&c.stdout) - .unwrap() - .to_lowercase() - .replace("-nan", "nan"); - let rust = std::str::from_utf8(&rust.stdout) - .unwrap() - .to_lowercase() - .replace("-nan", "nan"); + let intrinsics = c_output_map + .keys() + .chain(rust_output_map.keys()) + .unique() + .collect_vec(); - if c == rust { + info!("Comparing outputs"); + let intrinsics_diff_count = intrinsics + .par_iter() + .filter_map(|&&intrinsic| { + let c_output = c_output_map.get(intrinsic).unwrap(); + let rust_output = rust_output_map.get(intrinsic).unwrap(); + if rust_output.eq(c_output) { None } else { - Some(FailureReason::Difference(intrinsic_name.clone(), c, rust)) + let diff = diff::lines(c_output, rust_output); + let diffs = diff + .into_iter() + .filter_map(|diff| match diff { + diff::Result::Left(_) | diff::Result::Right(_) => Some(diff), + diff::Result::Both(_, _) => None, + }) + .collect_vec(); + if diffs.len() > 0 { + Some((intrinsic, diffs)) + } else { + None + } } }) - .collect::>(); - - intrinsics.iter().for_each(|reason| match reason { - FailureReason::Difference(intrinsic, c, rust) => { + .inspect(|(intrinsic, diffs)| { println!("Difference for intrinsic: {intrinsic}"); - let diff = diff::lines(c, rust); - diff.iter().for_each(|diff| match diff { + diffs.into_iter().for_each(|diff| match diff { diff::Result::Left(c) => println!("C: {c}"), diff::Result::Right(rust) => println!("Rust: {rust}"), - diff::Result::Both(_, _) => (), + _ => (), }); println!("****************************************************************"); - } - FailureReason::RunC(intrinsic) => { - println!("Failed to run C program for intrinsic {intrinsic}") - } - FailureReason::RunRust(intrinsic) => { - println!("Failed to run rust program for intrinsic {intrinsic}") - } - }); + }) + .count(); + println!( "{} differences found (tested {} intrinsics)", - intrinsics.len(), + intrinsics_diff_count, intrinsic_name_list.len() ); - intrinsics.is_empty() + + intrinsics_diff_count == 0 } diff --git a/crates/intrinsic-test/src/common/gen_c.rs b/crates/intrinsic-test/src/common/gen_c.rs index 04741e4f80..a95b4c36b7 100644 --- a/crates/intrinsic-test/src/common/gen_c.rs +++ b/crates/intrinsic-test/src/common/gen_c.rs @@ -1,6 +1,7 @@ use crate::common::intrinsic::Intrinsic; use super::argument::Argument; +use super::compare::INTRINSIC_DELIMITER; use super::indentation::Indentation; use super::intrinsic_helpers::IntrinsicTypeDefinition; @@ -147,22 +148,17 @@ pub fn write_main_cpp<'a>( } writeln!(w, "int main(int argc, char **argv) {{")?; - writeln!(w, " std::string intrinsic_name = argv[1];")?; - - writeln!(w, " if (false) {{")?; for intrinsic in intrinsics { - writeln!(w, " }} else if (intrinsic_name == \"{intrinsic}\") {{")?; - writeln!(w, " return run_{intrinsic}();")?; + writeln!( + w, + " std::cout << \"{INTRINSIC_DELIMITER}\" << std::endl;" + )?; + writeln!(w, " std::cout << \"{intrinsic}\" << std::endl;")?; + writeln!(w, " run_{intrinsic}();\n")?; } - writeln!(w, " }} else {{")?; - writeln!( - w, - " std::cerr << \"Unknown command: \" << intrinsic_name << \"\\n\";" - )?; - writeln!(w, " return -1;")?; - writeln!(w, " }}")?; + writeln!(w, " return 0;")?; writeln!(w, "}}")?; diff --git a/crates/intrinsic-test/src/common/gen_rust.rs b/crates/intrinsic-test/src/common/gen_rust.rs index c8d815e46e..fb047e2612 100644 --- a/crates/intrinsic-test/src/common/gen_rust.rs +++ b/crates/intrinsic-test/src/common/gen_rust.rs @@ -1,11 +1,11 @@ use itertools::Itertools; use std::process::Command; -use crate::common::argument::ArgumentList; -use crate::common::intrinsic::Intrinsic; - +use super::compare::INTRINSIC_DELIMITER; use super::indentation::Indentation; use super::intrinsic_helpers::IntrinsicTypeDefinition; +use crate::common::argument::ArgumentList; +use crate::common::intrinsic::Intrinsic; // The number of times each intrinsic will be called. pub(crate) const PASSES: u32 = 20; @@ -86,18 +86,12 @@ pub fn write_main_rs<'a>( writeln!(w, "fn main() {{")?; - writeln!(w, " match std::env::args().nth(1).unwrap().as_str() {{")?; - for binary in intrinsics { - writeln!(w, " \"{binary}\" => run_{binary}(),")?; + writeln!(w, " println!(\"{INTRINSIC_DELIMITER}\");")?; + writeln!(w, " println!(\"{binary}\");")?; + writeln!(w, " run_{binary}();\n")?; } - writeln!( - w, - " other => panic!(\"unknown intrinsic `{{}}`\", other)," - )?; - - writeln!(w, " }}")?; writeln!(w, "}}")?; Ok(()) diff --git a/crates/intrinsic-test/src/main.rs b/crates/intrinsic-test/src/main.rs index 3580d80bd1..e5c846877c 100644 --- a/crates/intrinsic-test/src/main.rs +++ b/crates/intrinsic-test/src/main.rs @@ -34,7 +34,7 @@ fn run(test_environment: impl SupportedArchitectureTest) { if !test_environment.build_rust_file() { std::process::exit(3); } - info!("comparing outputs"); + info!("Running binaries"); if !test_environment.compare_outputs() { std::process::exit(1); }