about summary refs log tree commit diff
path: root/library/stdarch/crates
diff options
context:
space:
mode:
Diffstat (limited to 'library/stdarch/crates')
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/config.rs35
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/functions.rs497
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/mod.rs28
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/compare.rs109
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/gen_c.rs92
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs134
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/mod.rs3
7 files changed, 501 insertions, 397 deletions
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/config.rs b/library/stdarch/crates/intrinsic-test/src/arm/config.rs
new file mode 100644
index 00000000000..8f7467e3a73
--- /dev/null
+++ b/library/stdarch/crates/intrinsic-test/src/arm/config.rs
@@ -0,0 +1,35 @@
+pub fn build_notices(line_prefix: &str) -> String {
+    format!(
+        "\
+{line_prefix}This is a transient test file, not intended for distribution. Some aspects of the
+{line_prefix}test are derived from a JSON specification, published under the same license as the
+{line_prefix}`intrinsic-test` crate.\n
+"
+    )
+}
+
+pub const POLY128_OSTREAM_DEF: &str = 
+r#"std::ostream& operator<<(std::ostream& os, poly128_t value) {
+    std::stringstream temp;
+    do {
+      int n = value % 10;
+      value /= 10;
+      temp << n;
+    } while (value != 0);
+    std::string tempstr(temp.str());
+    std::string res(tempstr.rbegin(), tempstr.rend());
+    os << res;
+    return os;
+}"#;
+
+pub const AARCH_CONFIGURATIONS: &str = r#"
+#![cfg_attr(target_arch = "arm", feature(stdarch_arm_neon_intrinsics))]
+#![cfg_attr(target_arch = "arm", feature(stdarch_aarch32_crc32))]
+#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_fcma))]
+#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_dotprod))]
+#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_i8mm))]
+#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_sha3))]
+#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_sm4))]
+#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_ftts))]
+#![feature(stdarch_neon_f16)]
+"#;
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/functions.rs b/library/stdarch/crates/intrinsic-test/src/arm/functions.rs
index e8b6d0f0e42..995a9ae941a 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/functions.rs
+++ b/library/stdarch/crates/intrinsic-test/src/arm/functions.rs
@@ -1,13 +1,13 @@
-use std::fs::File;
-use std::io::Write;
-use std::process::Command;
-
 use itertools::Itertools;
 use rayon::prelude::*;
+use std::io::Write;
 
 use super::argument::Argument;
+use super::config::{AARCH_CONFIGURATIONS, POLY128_OSTREAM_DEF, build_notices};
 use super::format::Indentation;
 use super::intrinsic::Intrinsic;
+use crate::common::gen_c::{compile_c, create_c_files, generate_c_program};
+use crate::common::gen_rust::{compile_rust, create_rust_files, generate_rust_program};
 
 // The number of times each intrinsic will be called.
 const PASSES: u32 = 20;
@@ -52,12 +52,7 @@ fn gen_code_c(
     }
 }
 
-fn generate_c_program(
-    notices: &str,
-    header_files: &[&str],
-    intrinsic: &Intrinsic,
-    target: &str,
-) -> String {
+fn generate_c_program_arm(header_files: &[&str], intrinsic: &Intrinsic, target: &str) -> String {
     let constraints = intrinsic
         .arguments
         .iter()
@@ -65,63 +60,23 @@ fn generate_c_program(
         .collect_vec();
 
     let indentation = Indentation::default();
-    format!(
-        r#"{notices}{header_files}
-#include <iostream>
-#include <cstring>
-#include <iomanip>
-#include <sstream>
-
-template<typename T1, typename T2> T1 cast(T2 x) {{
-  static_assert(sizeof(T1) == sizeof(T2), "sizeof T1 and T2 must be the same");
-  T1 ret{{}};
-  memcpy(&ret, &x, sizeof(T1));
-  return ret;
-}}
-
-#ifdef __aarch64__
-std::ostream& operator<<(std::ostream& os, poly128_t value) {{
-  std::stringstream temp;
-  do {{
-    int n = value % 10;
-    value /= 10;
-    temp << n;
-  }} while (value != 0);
-  std::string tempstr(temp.str());
-  std::string res(tempstr.rbegin(), tempstr.rend());
-  os << res;
-  return os;
-}}
-#endif
-
-std::ostream& operator<<(std::ostream& os, float16_t value) {{
-    uint16_t temp = 0;
-    memcpy(&temp, &value, sizeof(float16_t));
-    std::stringstream ss;
-    ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << temp;
-    os << ss.str();
-    return os;
-}}
-
-{arglists}
-
-int main(int argc, char **argv) {{
-{passes}
-    return 0;
-}}"#,
-        header_files = header_files
-            .iter()
-            .map(|header| format!("#include <{header}>"))
-            .collect::<Vec<_>>()
-            .join("\n"),
-        arglists = intrinsic.arguments.gen_arglists_c(indentation, PASSES),
-        passes = gen_code_c(
+    generate_c_program(
+        build_notices("// ").as_str(),
+        header_files,
+        "aarch64",
+        &[POLY128_OSTREAM_DEF],
+        intrinsic
+            .arguments
+            .gen_arglists_c(indentation, PASSES)
+            .as_str(),
+        gen_code_c(
             indentation.nested(),
             intrinsic,
             constraints.as_slice(),
             Default::default(),
             target,
-        ),
+        )
+        .as_str(),
     )
 }
 
@@ -163,7 +118,7 @@ fn gen_code_rust(
     }
 }
 
-fn generate_rust_program(notices: &str, intrinsic: &Intrinsic, target: &str) -> String {
+fn generate_rust_program_arm(intrinsic: &Intrinsic, target: &str) -> String {
     let constraints = intrinsic
         .arguments
         .iter()
@@ -171,362 +126,146 @@ fn generate_rust_program(notices: &str, intrinsic: &Intrinsic, target: &str) ->
         .collect_vec();
 
     let indentation = Indentation::default();
-    format!(
-        r#"{notices}#![feature(simd_ffi)]
-#![feature(link_llvm_intrinsics)]
-#![feature(f16)]
-#![cfg_attr(target_arch = "arm", feature(stdarch_arm_neon_intrinsics))]
-#![cfg_attr(target_arch = "arm", feature(stdarch_aarch32_crc32))]
-#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_fcma))]
-#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_dotprod))]
-#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_i8mm))]
-#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_sha3))]
-#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_sm4))]
-#![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_ftts))]
-#![feature(stdarch_neon_f16)]
-#![allow(non_upper_case_globals)]
-use core_arch::arch::{target_arch}::*;
-
-fn main() {{
-{arglists}
-{passes}
-}}
-"#,
-        target_arch = if target.contains("v7") {
-            "arm"
-        } else {
-            "aarch64"
-        },
-        arglists = intrinsic
+    let final_target = if target.contains("v7") {
+        "arm"
+    } else {
+        "aarch64"
+    };
+    generate_rust_program(
+        build_notices("// ").as_str(),
+        AARCH_CONFIGURATIONS,
+        final_target,
+        intrinsic
             .arguments
-            .gen_arglists_rust(indentation.nested(), PASSES),
-        passes = gen_code_rust(
+            .gen_arglists_rust(indentation.nested(), PASSES)
+            .as_str(),
+        gen_code_rust(
             indentation.nested(),
             intrinsic,
             &constraints,
-            Default::default()
+            Default::default(),
         )
+        .as_str(),
     )
 }
 
-fn compile_c(
-    c_filename: &str,
-    intrinsic: &Intrinsic,
+fn compile_c_arm(
+    intrinsics_name_list: Vec<String>,
     compiler: &str,
     target: &str,
     cxx_toolchain_dir: Option<&str>,
 ) -> bool {
-    let flags = std::env::var("CPPFLAGS").unwrap_or("".into());
-    let arch_flags = if target.contains("v7") {
-        "-march=armv8.6-a+crypto+crc+dotprod+fp16"
-    } else {
-        "-march=armv8.6-a+crypto+sha3+crc+dotprod+fp16+faminmax+lut"
-    };
+    let compiler_commands = intrinsics_name_list.iter().map(|intrinsic_name|{
+        let c_filename = format!(r#"c_programs/{}.cpp"#, intrinsic_name);
+        let flags = std::env::var("CPPFLAGS").unwrap_or("".into());
+        let arch_flags = if target.contains("v7") {
+            "-march=armv8.6-a+crypto+crc+dotprod+fp16"
+        } else {
+            "-march=armv8.6-a+crypto+sha3+crc+dotprod+fp16+faminmax+lut"
+        };
 
-    let intrinsic_name = &intrinsic.name;
+        let compiler_command = if target == "aarch64_be-unknown-linux-gnu" {
+            let Some(cxx_toolchain_dir) = cxx_toolchain_dir else {
+                panic!(
+                    "When setting `--target aarch64_be-unknown-linux-gnu` the C++ compilers toolchain directory must be set with `--cxx-toolchain-dir <dest>`"
+                );
+            };
 
-    let compiler_command = if target == "aarch64_be-unknown-linux-gnu" {
-        let Some(cxx_toolchain_dir) = cxx_toolchain_dir else {
-            panic!(
-                "When setting `--target aarch64_be-unknown-linux-gnu` the C++ compilers toolchain directory must be set with `--cxx-toolchain-dir <dest>`"
+            /* clang++ cannot link an aarch64_be object file, so we invoke
+             * aarch64_be-unknown-linux-gnu's C++ linker. This ensures that we
+             * are testing the intrinsics against LLVM.
+             *
+             * Note: setting `--sysroot=<...>` which is the obvious thing to do
+             * does not work as it gets caught up with `#include_next <stdlib.h>`
+             * not existing... */
+            format!(
+                "{compiler} {flags} {arch_flags} \
+                -ffp-contract=off \
+                -Wno-narrowing \
+                -O2 \
+                --target=aarch64_be-unknown-linux-gnu \
+                -I{cxx_toolchain_dir}/include \
+                -I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include \
+                -I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1 \
+                -I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1/aarch64_be-none-linux-gnu \
+                -I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1/backward \
+                -I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/libc/usr/include \
+                -c {c_filename} \
+                -o c_programs/{intrinsic_name}.o && \
+                {cxx_toolchain_dir}/bin/aarch64_be-none-linux-gnu-g++ c_programs/{intrinsic_name}.o -o c_programs/{intrinsic_name} && \
+                rm c_programs/{intrinsic_name}.o",
+            )
+        } else {
+            // -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations
+            let base_compiler_command = format!(
+                "{compiler} {flags} {arch_flags} -o c_programs/{intrinsic_name} {c_filename} -ffp-contract=off -Wno-narrowing -O2"
             );
-        };
 
-        /* clang++ cannot link an aarch64_be object file, so we invoke
-         * aarch64_be-unknown-linux-gnu's C++ linker. This ensures that we
-         * are testing the intrinsics against LLVM.
-         *
-         * Note: setting `--sysroot=<...>` which is the obvious thing to do
-         * does not work as it gets caught up with `#include_next <stdlib.h>`
-         * not existing... */
-        format!(
-            "{compiler} {flags} {arch_flags} \
-            -ffp-contract=off \
-            -Wno-narrowing \
-            -O2 \
-            --target=aarch64_be-unknown-linux-gnu \
-            -I{cxx_toolchain_dir}/include \
-            -I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include \
-            -I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1 \
-            -I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1/aarch64_be-none-linux-gnu \
-            -I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1/backward \
-            -I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/libc/usr/include \
-            -c {c_filename} \
-            -o c_programs/{intrinsic_name}.o && \
-            {cxx_toolchain_dir}/bin/aarch64_be-none-linux-gnu-g++ c_programs/{intrinsic_name}.o -o c_programs/{intrinsic_name} && \
-            rm c_programs/{intrinsic_name}.o",
-        )
-    } else {
-        // -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations
-        let base_compiler_command = format!(
-            "{compiler} {flags} {arch_flags} -o c_programs/{intrinsic_name} {c_filename} -ffp-contract=off -Wno-narrowing -O2"
-        );
+            /* `-target` can be passed to some c++ compilers, however if we want to
+             *   use a c++ compiler does not support this flag we do not want to pass
+             *   the flag. */
+            if compiler.contains("clang") {
+                format!("{base_compiler_command} -target {target}")
+            } else {
+                format!("{base_compiler_command} -flax-vector-conversions")
+            }
+        };
 
-        /* `-target` can be passed to some c++ compilers, however if we want to
-         *   use a c++ compiler does not support this flag we do not want to pass
-         *   the flag. */
-        if compiler.contains("clang") {
-            format!("{base_compiler_command} -target {target}")
-        } else {
-            format!("{base_compiler_command} -flax-vector-conversions")
-        }
-    };
+        compiler_command
+    })
+    .collect::<Vec<_>>();
 
-    let output = Command::new("sh").arg("-c").arg(compiler_command).output();
-    if let Ok(output) = output {
-        if output.status.success() {
-            true
-        } else {
-            error!(
-                "Failed to compile code for intrinsic: {}\n\nstdout:\n{}\n\nstderr:\n{}",
-                intrinsic.name,
-                std::str::from_utf8(&output.stdout).unwrap_or(""),
-                std::str::from_utf8(&output.stderr).unwrap_or("")
-            );
-            false
-        }
-    } else {
-        error!("Command failed: {:#?}", output);
-        false
-    }
+    compile_c(&compiler_commands)
 }
 
 pub fn build_c(
-    notices: &str,
     intrinsics: &Vec<Intrinsic>,
     compiler: Option<&str>,
     target: &str,
     cxx_toolchain_dir: Option<&str>,
 ) -> bool {
     let _ = std::fs::create_dir("c_programs");
-    intrinsics
+    let intrinsics_name_list = intrinsics
         .par_iter()
-        .map(|i| {
-            let c_filename = format!(r#"c_programs/{}.cpp"#, i.name);
-            let mut file = File::create(&c_filename).unwrap();
+        .map(|i| i.name.clone())
+        .collect::<Vec<_>>();
+    let file_mapping = create_c_files(&intrinsics_name_list);
 
-            let c_code = generate_c_program(
-                notices,
-                &["arm_neon.h", "arm_acle.h", "arm_fp16.h"],
-                i,
-                target,
-            );
-            file.write_all(c_code.into_bytes().as_slice()).unwrap();
-            match compiler {
-                None => true,
-                Some(compiler) => compile_c(&c_filename, i, compiler, target, cxx_toolchain_dir),
-            }
-        })
-        .find_any(|x| !x)
-        .is_none()
+    intrinsics.par_iter().for_each(|i| {
+        let c_code = generate_c_program_arm(&["arm_neon.h", "arm_acle.h", "arm_fp16.h"], i, target);
+        match file_mapping.get(&i.name) {
+            Some(mut file) => file.write_all(c_code.into_bytes().as_slice()).unwrap(),
+            None => {}
+        };
+    });
+
+    match compiler {
+        None => true,
+        Some(compiler) => compile_c_arm(intrinsics_name_list, compiler, target, cxx_toolchain_dir),
+    }
 }
 
 pub fn build_rust(
-    notices: &str,
     intrinsics: &[Intrinsic],
     toolchain: Option<&str>,
     target: &str,
     linker: Option<&str>,
 ) -> bool {
-    intrinsics.iter().for_each(|i| {
-        let rust_dir = format!(r#"rust_programs/{}"#, i.name);
-        let _ = std::fs::create_dir_all(&rust_dir);
-        let rust_filename = format!(r#"{rust_dir}/main.rs"#);
-        let mut file = File::create(&rust_filename).unwrap();
-
-        let c_code = generate_rust_program(notices, i, target);
-        file.write_all(c_code.into_bytes().as_slice()).unwrap();
-    });
-
-    let mut cargo = File::create("rust_programs/Cargo.toml").unwrap();
-    cargo
-        .write_all(
-            format!(
-                r#"[package]
-name = "intrinsic-test-programs"
-version = "{version}"
-authors = [{authors}]
-license = "{license}"
-edition = "2018"
-[workspace]
-[dependencies]
-core_arch = {{ path = "../crates/core_arch" }}
-{binaries}"#,
-                version = env!("CARGO_PKG_VERSION"),
-                authors = env!("CARGO_PKG_AUTHORS")
-                    .split(":")
-                    .format_with(", ", |author, fmt| fmt(&format_args!("\"{author}\""))),
-                license = env!("CARGO_PKG_LICENSE"),
-                binaries = intrinsics
-                    .iter()
-                    .map(|i| {
-                        format!(
-                            r#"[[bin]]
-name = "{intrinsic}"
-path = "{intrinsic}/main.rs""#,
-                            intrinsic = i.name
-                        )
-                    })
-                    .collect::<Vec<_>>()
-                    .join("\n")
-            )
-            .into_bytes()
-            .as_slice(),
-        )
-        .unwrap();
-
-    let toolchain = match toolchain {
-        None => return true,
-        Some(t) => t,
-    };
-
-    /* If there has been a linker explicitly set from the command line then
-     * we want to set it via setting it in the RUSTFLAGS*/
-
-    let cargo_command = format!(
-        "cargo {toolchain} build --target {target} --release",
-        toolchain = toolchain,
-        target = target
-    );
-
-    let mut command = Command::new("sh");
-    command
-        .current_dir("rust_programs")
-        .arg("-c")
-        .arg(cargo_command);
-
-    let mut rust_flags = "-Cdebuginfo=0".to_string();
-    if let Some(linker) = linker {
-        rust_flags.push_str(" -C linker=");
-        rust_flags.push_str(linker);
-        rust_flags.push_str(" -C link-args=-static");
-
-        command.env("CPPFLAGS", "-fuse-ld=lld");
-    }
-
-    command.env("RUSTFLAGS", rust_flags);
-    let output = command.output();
-
-    if let Ok(output) = output {
-        if output.status.success() {
-            true
-        } else {
-            error!(
-                "Failed to compile code for rust intrinsics\n\nstdout:\n{}\n\nstderr:\n{}",
-                std::str::from_utf8(&output.stdout).unwrap_or(""),
-                std::str::from_utf8(&output.stderr).unwrap_or("")
-            );
-            false
-        }
-    } else {
-        error!("Command failed: {:#?}", output);
-        false
-    }
-}
-
-enum FailureReason {
-    RunC(String),
-    RunRust(String),
-    Difference(String, String, String),
-}
-
-pub fn compare_outputs(
-    intrinsics: &Vec<Intrinsic>,
-    toolchain: &str,
-    runner: &str,
-    target: &str,
-) -> bool {
-    let intrinsics = intrinsics
+    let intrinsics_name_list = intrinsics
         .par_iter()
-        .filter_map(|intrinsic| {
-            let c = Command::new("sh")
-                .arg("-c")
-                .arg(format!(
-                    "{runner} ./c_programs/{intrinsic}",
-                    runner = runner,
-                    intrinsic = intrinsic.name,
-                ))
-                .output();
-
-            let rust = if target != "aarch64_be-unknown-linux-gnu" {
-                Command::new("sh")
-                    .current_dir("rust_programs")
-                    .arg("-c")
-                    .arg(format!(
-                        "cargo {toolchain} run --target {target} --bin {intrinsic} --release",
-                        intrinsic = intrinsic.name,
-                        toolchain = toolchain,
-                        target = target
-                    ))
-                    .env("RUSTFLAGS", "-Cdebuginfo=0")
-                    .output()
-            } else {
-                Command::new("sh")
-                    .arg("-c")
-                    .arg(format!(
-                        "{runner} ./rust_programs/target/{target}/release/{intrinsic}",
-                        runner = runner,
-                        target = target,
-                        intrinsic = intrinsic.name,
-                    ))
-                    .output()
-            };
-
-            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 for intrinsic {}", intrinsic.name);
-                return Some(FailureReason::RunC(intrinsic.name.clone()));
-            }
-
-            if !rust.status.success() {
-                error!(
-                    "Failed to run rust program for intrinsic {}",
-                    intrinsic.name
-                );
-                return Some(FailureReason::RunRust(intrinsic.name.clone()));
-            }
-
-            info!("Comparing intrinsic: {}", intrinsic.name);
-
-            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");
-
-            if c == rust {
-                None
-            } else {
-                Some(FailureReason::Difference(intrinsic.name.clone(), c, rust))
-            }
-        })
+        .map(|i| i.name.clone())
         .collect::<Vec<_>>();
+    let file_mapping = create_rust_files(&intrinsics_name_list);
 
-    intrinsics.iter().for_each(|reason| match reason {
-        FailureReason::Difference(intrinsic, c, rust) => {
-            println!("Difference for intrinsic: {intrinsic}");
-            let diff = diff::lines(c, rust);
-            diff.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}")
+    intrinsics.par_iter().for_each(|i| {
+        let c_code = generate_rust_program_arm(i, target);
+        match file_mapping.get(&i.name) {
+            Some(mut file) => file.write_all(c_code.into_bytes().as_slice()).unwrap(),
+            None => {}
         }
     });
-    println!("{} differences found", intrinsics.len());
-    intrinsics.is_empty()
+
+    let intrinsics_name_list = intrinsics.iter().map(|i| i.name.as_str()).collect_vec();
+
+    compile_rust(&intrinsics_name_list, toolchain, target, linker)
 }
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs
index 96ac3ca7856..3f2a346daa1 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs
+++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs
@@ -1,4 +1,5 @@
 mod argument;
+mod config;
 mod format;
 mod functions;
 mod intrinsic;
@@ -6,25 +7,15 @@ mod json_parser;
 mod types;
 
 use crate::common::cli::ProcessedCli;
+use crate::common::compare::compare_outputs;
 use crate::common::supporting_test::SupportedArchitectureTest;
-use functions::{build_c, build_rust, compare_outputs};
+use functions::{build_c, build_rust};
 use intrinsic::Intrinsic;
 use json_parser::get_neon_intrinsics;
 use types::TypeKind;
 
-fn build_notices(line_prefix: &str) -> String {
-    format!(
-        "\
-{line_prefix}This is a transient test file, not intended for distribution. Some aspects of the
-{line_prefix}test are derived from a JSON specification, published under the same license as the
-{line_prefix}`intrinsic-test` crate.\n
-"
-    )
-}
-
 pub struct ArmTestProcessor {
     intrinsics: Vec<Intrinsic>,
-    notices: String,
     cli_options: ProcessedCli,
 }
 
@@ -51,18 +42,14 @@ impl SupportedArchitectureTest for ArmTestProcessor {
             .collect::<Vec<_>>();
         intrinsics.dedup();
 
-        let notices = build_notices("// ");
-
         Self {
             intrinsics: intrinsics,
-            notices: notices,
             cli_options: cli_options,
         }
     }
 
     fn build_c_file(&self) -> bool {
         build_c(
-            &self.notices,
             &self.intrinsics,
             self.cli_options.cpp_compiler.as_deref(),
             &self.cli_options.target,
@@ -72,7 +59,6 @@ impl SupportedArchitectureTest for ArmTestProcessor {
 
     fn build_rust_file(&self) -> bool {
         build_rust(
-            &self.notices,
             &self.intrinsics,
             self.cli_options.toolchain.as_deref(),
             &self.cli_options.target,
@@ -82,8 +68,14 @@ impl SupportedArchitectureTest for ArmTestProcessor {
 
     fn compare_outputs(&self) -> bool {
         if let Some(ref toolchain) = self.cli_options.toolchain {
+            let intrinsics_name_list = self
+                .intrinsics
+                .iter()
+                .map(|i| i.name.clone())
+                .collect::<Vec<_>>();
+
             compare_outputs(
-                &self.intrinsics,
+                &intrinsics_name_list,
                 toolchain,
                 &self.cli_options.c_runner,
                 &self.cli_options.target,
diff --git a/library/stdarch/crates/intrinsic-test/src/common/compare.rs b/library/stdarch/crates/intrinsic-test/src/common/compare.rs
new file mode 100644
index 00000000000..4ff319be8cb
--- /dev/null
+++ b/library/stdarch/crates/intrinsic-test/src/common/compare.rs
@@ -0,0 +1,109 @@
+use rayon::prelude::*;
+use std::process::Command;
+
+enum FailureReason {
+    RunC(String),
+    RunRust(String),
+    Difference(String, String, String),
+}
+
+pub fn compare_outputs(
+    intrinsic_name_list: &Vec<String>,
+    toolchain: &str,
+    runner: &str,
+    target: &str,
+) -> bool {
+    let intrinsics = intrinsic_name_list
+        .par_iter()
+        .filter_map(|intrinsic_name| {
+            let c = Command::new("sh")
+                .arg("-c")
+                .arg(format!(
+                    "{runner} ./c_programs/{intrinsic_name}",
+                    runner = runner,
+                    intrinsic_name = intrinsic_name,
+                ))
+                .output();
+
+            let rust = if target != "aarch64_be-unknown-linux-gnu" {
+                Command::new("sh")
+                    .current_dir("rust_programs")
+                    .arg("-c")
+                    .arg(format!(
+                        "cargo {toolchain} run --target {target} --bin {intrinsic_name} --release",
+                        intrinsic_name = intrinsic_name,
+                        toolchain = toolchain,
+                        target = target
+                    ))
+                    .env("RUSTFLAGS", "-Cdebuginfo=0")
+                    .output()
+            } else {
+                Command::new("sh")
+                    .arg("-c")
+                    .arg(format!(
+                        "{runner} ./rust_programs/target/{target}/release/{intrinsic_name}",
+                        runner = runner,
+                        target = target,
+                        intrinsic_name = intrinsic_name,
+                    ))
+                    .output()
+            };
+
+            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 for intrinsic {}", intrinsic_name);
+                return Some(FailureReason::RunC(intrinsic_name.clone()));
+            }
+
+            if !rust.status.success() {
+                error!(
+                    "Failed to run rust program for intrinsic {}",
+                    intrinsic_name
+                );
+                return Some(FailureReason::RunRust(intrinsic_name.clone()));
+            }
+
+            info!("Comparing intrinsic: {}", intrinsic_name);
+
+            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");
+
+            if c == rust {
+                None
+            } else {
+                Some(FailureReason::Difference(intrinsic_name.clone(), c, rust))
+            }
+        })
+        .collect::<Vec<_>>();
+
+    intrinsics.iter().for_each(|reason| match reason {
+        FailureReason::Difference(intrinsic, c, rust) => {
+            println!("Difference for intrinsic: {intrinsic}");
+            let diff = diff::lines(c, rust);
+            diff.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}")
+        }
+    });
+    println!("{} differences found", intrinsics.len());
+    intrinsics.is_empty()
+}
diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs
new file mode 100644
index 00000000000..58ab5823ef7
--- /dev/null
+++ b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs
@@ -0,0 +1,92 @@
+use itertools::Itertools;
+use rayon::prelude::*;
+use std::collections::BTreeMap;
+use std::fs::File;
+use std::process::Command;
+
+pub fn generate_c_program(
+    notices: &str,
+    header_files: &[&str],
+    arch_identifier: &str,
+    arch_specific_definitions: &[&str],
+    arglists: &str,
+    passes: &str,
+) -> String {
+    format!(
+        r#"{notices}{header_files}
+#include <iostream>
+#include <cstring>
+#include <iomanip>
+#include <sstream>
+
+template<typename T1, typename T2> T1 cast(T2 x) {{
+  static_assert(sizeof(T1) == sizeof(T2), "sizeof T1 and T2 must be the same");
+  T1 ret{{}};
+  memcpy(&ret, &x, sizeof(T1));
+  return ret;
+}}
+
+std::ostream& operator<<(std::ostream& os, float16_t value) {{
+    uint16_t temp = 0;
+    memcpy(&temp, &value, sizeof(float16_t));
+    std::stringstream ss;
+    ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << temp;
+    os << ss.str();
+    return os;
+}}
+
+#ifdef __{arch_identifier}__
+{arch_specific_definitions}
+#endif
+
+{arglists}
+
+int main(int argc, char **argv) {{
+{passes}
+    return 0;
+}}"#,
+        header_files = header_files
+            .iter()
+            .map(|header| format!("#include <{header}>"))
+            .collect::<Vec<_>>()
+            .join("\n"),
+        arch_specific_definitions = arch_specific_definitions.into_iter().join("\n"),
+    )
+}
+
+pub fn compile_c(compiler_commands: &[String]) -> bool {
+    compiler_commands
+        .par_iter()
+        .map(|compiler_command| {
+            let output = Command::new("sh").arg("-c").arg(compiler_command).output();
+            if let Ok(output) = output {
+                if output.status.success() {
+                    true
+                } else {
+                    error!(
+                        "Failed to compile code for intrinsics: \n\nstdout:\n{}\n\nstderr:\n{}",
+                        std::str::from_utf8(&output.stdout).unwrap_or(""),
+                        std::str::from_utf8(&output.stderr).unwrap_or("")
+                    );
+                    false
+                }
+            } else {
+                error!("Command failed: {:#?}", output);
+                false
+            }
+        })
+        .find_any(|x| !x)
+        .is_none()
+}
+
+pub fn create_c_files(identifiers: &Vec<String>) -> BTreeMap<&String, File> {
+    identifiers
+        .par_iter()
+        .map(|identifier| {
+            let c_filename = format!(r#"c_programs/{}.cpp"#, identifier);
+            let file = File::create(&c_filename).unwrap();
+
+            (identifier, file)
+        })
+        .collect::<BTreeMap<&String, File>>()
+}
diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs
new file mode 100644
index 00000000000..e405ab4e640
--- /dev/null
+++ b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs
@@ -0,0 +1,134 @@
+use itertools::Itertools;
+use rayon::prelude::*;
+use std::collections::BTreeMap;
+use std::fs::File;
+use std::io::Write;
+use std::process::Command;
+
+pub fn generate_rust_program(
+    notices: &str,
+    configurations: &str,
+    arch_definition: &str,
+    arglists: &str,
+    passes: &str,
+) -> String {
+    format!(
+        r#"{notices}#![feature(simd_ffi)]
+#![feature(link_llvm_intrinsics)]
+#![feature(f16)]
+{configurations}
+#![allow(non_upper_case_globals)]
+use core_arch::arch::{arch_definition}::*;
+
+fn main() {{
+{arglists}
+{passes}
+}}
+"#,
+    )
+}
+
+pub fn compile_rust(
+    binaries: &[&str],
+    toolchain: Option<&str>,
+    target: &str,
+    linker: Option<&str>,
+) -> bool {
+    let mut cargo = File::create("rust_programs/Cargo.toml").unwrap();
+    cargo
+        .write_all(
+            format!(
+                r#"[package]
+name = "intrinsic-test-programs"
+version = "{version}"
+authors = [{authors}]
+license = "{license}"
+edition = "2018"
+[workspace]
+[dependencies]
+core_arch = {{ path = "../crates/core_arch" }}
+{binaries}"#,
+                version = env!("CARGO_PKG_VERSION"),
+                authors = env!("CARGO_PKG_AUTHORS")
+                    .split(":")
+                    .format_with(", ", |author, fmt| fmt(&format_args!("\"{author}\""))),
+                license = env!("CARGO_PKG_LICENSE"),
+                binaries = binaries
+                    .iter()
+                    .map(|binary| {
+                        format!(
+                            r#"[[bin]]
+name = "{binary}"
+path = "{binary}/main.rs""#,
+                        )
+                    })
+                    .collect::<Vec<_>>()
+                    .join("\n")
+            )
+            .into_bytes()
+            .as_slice(),
+        )
+        .unwrap();
+
+    let toolchain = match toolchain {
+        None => return true,
+        Some(t) => t,
+    };
+
+    /* If there has been a linker explicitly set from the command line then
+     * we want to set it via setting it in the RUSTFLAGS*/
+
+    let cargo_command = format!(
+        "cargo {toolchain} build --target {target} --release",
+        toolchain = toolchain,
+        target = target
+    );
+
+    let mut command = Command::new("sh");
+    command
+        .current_dir("rust_programs")
+        .arg("-c")
+        .arg(cargo_command);
+
+    let mut rust_flags = "-Cdebuginfo=0".to_string();
+    if let Some(linker) = linker {
+        rust_flags.push_str(" -C linker=");
+        rust_flags.push_str(linker);
+        rust_flags.push_str(" -C link-args=-static");
+
+        command.env("CPPFLAGS", "-fuse-ld=lld");
+    }
+
+    command.env("RUSTFLAGS", rust_flags);
+    let output = command.output();
+
+    if let Ok(output) = output {
+        if output.status.success() {
+            true
+        } else {
+            error!(
+                "Failed to compile code for rust intrinsics\n\nstdout:\n{}\n\nstderr:\n{}",
+                std::str::from_utf8(&output.stdout).unwrap_or(""),
+                std::str::from_utf8(&output.stderr).unwrap_or("")
+            );
+            false
+        }
+    } else {
+        error!("Command failed: {:#?}", output);
+        false
+    }
+}
+
+pub fn create_rust_files(identifiers: &Vec<String>) -> BTreeMap<&String, File> {
+    identifiers
+        .par_iter()
+        .map(|identifier| {
+            let rust_dir = format!(r#"rust_programs/{}"#, identifier);
+            let _ = std::fs::create_dir_all(&rust_dir);
+            let rust_filename = format!(r#"{rust_dir}/main.rs"#);
+            let file = File::create(&rust_filename).unwrap();
+
+            (identifier, file)
+        })
+        .collect::<BTreeMap<&String, File>>()
+}
diff --git a/library/stdarch/crates/intrinsic-test/src/common/mod.rs b/library/stdarch/crates/intrinsic-test/src/common/mod.rs
index 098451d81b4..13b2854f2e3 100644
--- a/library/stdarch/crates/intrinsic-test/src/common/mod.rs
+++ b/library/stdarch/crates/intrinsic-test/src/common/mod.rs
@@ -1,4 +1,7 @@
 pub mod cli;
+pub mod compare;
+pub mod gen_c;
+pub mod gen_rust;
 pub mod supporting_test;
 pub mod types;
 pub mod values;