diff --git a/Cargo.lock b/Cargo.lock index 4806682e6e..21d7d718fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -635,9 +635,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", diff --git a/crates/intrinsic-test/src/arm/mod.rs b/crates/intrinsic-test/src/arm/mod.rs index 0a64a24e73..5d0320c4cd 100644 --- a/crates/intrinsic-test/src/arm/mod.rs +++ b/crates/intrinsic-test/src/arm/mod.rs @@ -13,10 +13,11 @@ use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; use crate::common::compare::compare_outputs; use crate::common::gen_c::{write_main_cpp, write_mod_cpp}; -use crate::common::gen_rust::compile_rust_programs; -use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; +use crate::common::gen_rust::{ + compile_rust_programs, write_bin_cargo_toml, write_lib_cargo_toml, write_lib_rs, write_main_rs, +}; +use crate::common::intrinsic::Intrinsic; use crate::common::intrinsic_helpers::TypeKind; -use crate::common::write_file::write_rust_testfiles; use config::{AARCH_CONFIGURATIONS, F16_FORMATTING_DEF, build_notices}; use intrinsic::ArmIntrinsicType; use json_parser::get_neon_intrinsics; @@ -118,26 +119,60 @@ impl SupportedArchitectureTest for ArmArchitectureTest { } fn build_rust_file(&self) -> bool { - let rust_target = if self.cli_options.target.contains("v7") { + std::fs::create_dir_all("rust_programs/src").unwrap(); + + let architecture = if self.cli_options.target.contains("v7") { "arm" } else { "aarch64" }; + + let (chunk_size, chunk_count) = chunk_info(self.intrinsics.len()); + + let mut cargo = File::create("rust_programs/Cargo.toml").unwrap(); + write_bin_cargo_toml(&mut cargo, chunk_count).unwrap(); + + let mut main_rs = File::create("rust_programs/src/main.rs").unwrap(); + write_main_rs( + &mut main_rs, + chunk_count, + AARCH_CONFIGURATIONS, + "", + self.intrinsics.iter().map(|i| i.name.as_str()), + ) + .unwrap(); + let target = &self.cli_options.target; let toolchain = self.cli_options.toolchain.as_deref(); let linker = self.cli_options.linker.as_deref(); - let intrinsics_name_list = write_rust_testfiles( - self.intrinsics - .iter() - .map(|i| i as &dyn IntrinsicDefinition<_>) - .collect::>(), - rust_target, - &build_notices("// "), - F16_FORMATTING_DEF, - AARCH_CONFIGURATIONS, - ); - compile_rust_programs(intrinsics_name_list, toolchain, target, linker) + let notice = &build_notices("// "); + self.intrinsics + .par_chunks(chunk_size) + .enumerate() + .map(|(i, chunk)| { + std::fs::create_dir_all(format!("rust_programs/mod_{i}/src"))?; + + let rust_filename = format!("rust_programs/mod_{i}/src/lib.rs"); + trace!("generating `{rust_filename}`"); + let mut file = File::create(rust_filename)?; + + let cfg = AARCH_CONFIGURATIONS; + let definitions = F16_FORMATTING_DEF; + write_lib_rs(&mut file, architecture, notice, cfg, definitions, chunk)?; + + let toml_filename = format!("rust_programs/mod_{i}/Cargo.toml"); + trace!("generating `{toml_filename}`"); + let mut file = File::create(toml_filename).unwrap(); + + write_lib_cargo_toml(&mut file, &format!("mod_{i}"))?; + + Ok(()) + }) + .collect::>() + .unwrap(); + + compile_rust_programs(toolchain, target, linker) } fn compare_outputs(&self) -> bool { diff --git a/crates/intrinsic-test/src/arm/types.rs b/crates/intrinsic-test/src/arm/types.rs index 77f5e8d0e5..c06e9355c4 100644 --- a/crates/intrinsic-test/src/arm/types.rs +++ b/crates/intrinsic-test/src/arm/types.rs @@ -33,25 +33,6 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { } } - fn rust_type(&self) -> String { - let rust_prefix = self.0.kind.rust_prefix(); - let c_prefix = self.0.kind.c_prefix(); - if self.0.ptr_constant { - self.c_type() - } else if let (Some(bit_len), simd_len, vec_len) = - (self.0.bit_len, self.0.simd_len, self.0.vec_len) - { - match (simd_len, vec_len) { - (None, None) => format!("{rust_prefix}{bit_len}"), - (Some(simd), None) => format!("{c_prefix}{bit_len}x{simd}_t"), - (Some(simd), Some(vec)) => format!("{c_prefix}{bit_len}x{simd}x{vec}_t"), - (None, Some(_)) => todo!("{:#?}", self), // Likely an invalid case - } - } else { - todo!("{:#?}", self) - } - } - /// Determines the load function for this type. fn get_load_function(&self, language: Language) -> String { if let IntrinsicType { diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index 1df4f55995..1550cbd97f 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -114,14 +114,6 @@ where .join(", ") } - pub fn as_constraint_parameters_rust(&self) -> String { - self.iter() - .filter(|a| a.has_constraint()) - .map(|arg| arg.name.clone()) - .collect::>() - .join(", ") - } - /// Creates a line for each argument that initializes an array for C from which `loads` argument /// values can be loaded as a sliding window. /// e.g `const int32x2_t a_vals = {0x3effffff, 0x3effffff, 0x3f7fffff}`, if loads=2. @@ -146,21 +138,25 @@ where /// Creates a line for each argument that initializes an array for Rust from which `loads` argument /// values can be loaded as a sliding window, e.g `const A_VALS: [u32; 20] = [...];` - pub fn gen_arglists_rust(&self, indentation: Indentation, loads: u32) -> String { - self.iter() - .filter(|&arg| !arg.has_constraint()) - .map(|arg| { - format!( - "{indentation}{bind} {name}: [{ty}; {load_size}] = {values};", - bind = arg.rust_vals_array_binding(), - name = arg.rust_vals_array_name(), - ty = arg.ty.rust_scalar_type(), - load_size = arg.ty.num_lanes() * arg.ty.num_vectors() + loads - 1, - values = arg.ty.populate_random(indentation, loads, &Language::Rust) - ) - }) - .collect::>() - .join("\n") + pub fn gen_arglists_rust( + &self, + w: &mut impl std::io::Write, + indentation: Indentation, + loads: u32, + ) -> std::io::Result<()> { + for arg in self.iter().filter(|&arg| !arg.has_constraint()) { + writeln!( + w, + "{indentation}{bind} {name}: [{ty}; {load_size}] = {values};", + bind = arg.rust_vals_array_binding(), + name = arg.rust_vals_array_name(), + ty = arg.ty.rust_scalar_type(), + load_size = arg.ty.num_lanes() * arg.ty.num_vectors() + loads - 1, + values = arg.ty.populate_random(indentation, loads, &Language::Rust) + )? + } + + Ok(()) } /// Creates a line for each argument that initializes the argument from an array `[arg]_vals` at diff --git a/crates/intrinsic-test/src/common/compare.rs b/crates/intrinsic-test/src/common/compare.rs index cb55922eb1..1ad00839ef 100644 --- a/crates/intrinsic-test/src/common/compare.rs +++ b/crates/intrinsic-test/src/common/compare.rs @@ -2,25 +2,29 @@ use super::cli::FailureReason; use rayon::prelude::*; use std::process::Command; -pub fn compare_outputs(intrinsic_name_list: &Vec, runner: &str, target: &str) -> bool { - fn runner_command(runner: &str) -> Command { - let mut it = runner.split_whitespace(); - let mut cmd = Command::new(it.next().unwrap()); - cmd.args(it); +fn runner_command(runner: &str) -> Command { + let mut it = runner.split_whitespace(); + let mut cmd = Command::new(it.next().unwrap()); + cmd.args(it); - cmd - } + cmd +} +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) - .arg("./c_programs/intrinsic-test-programs") + .arg("intrinsic-test-programs") .arg(intrinsic_name) + .current_dir("c_programs") .output(); let rust = runner_command(runner) - .arg(format!("target/{target}/release/{intrinsic_name}")) + .arg(format!("target/{target}/release/intrinsic-test-programs")) + .arg(intrinsic_name) + .current_dir("rust_programs") .output(); let (c, rust) = match (c, rust) { @@ -30,7 +34,7 @@ pub fn compare_outputs(intrinsic_name_list: &Vec, runner: &str, target: if !c.status.success() { error!( - "Failed to run C program for intrinsic {intrinsic_name}\nstdout: {stdout}\nstderr: {stderr}", + "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(""), ); @@ -39,9 +43,9 @@ pub fn compare_outputs(intrinsic_name_list: &Vec, runner: &str, target: if !rust.status.success() { error!( - "Failed to run Rust program for intrinsic {intrinsic_name}\nstdout: {stdout}\nstderr: {stderr}", - stdout = String::from_utf8_lossy(&rust.stdout), - stderr = String::from_utf8_lossy(&rust.stderr), + "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())); } diff --git a/crates/intrinsic-test/src/common/gen_rust.rs b/crates/intrinsic-test/src/common/gen_rust.rs index 0e4a95ab52..60bb577a80 100644 --- a/crates/intrinsic-test/src/common/gen_rust.rs +++ b/crates/intrinsic-test/src/common/gen_rust.rs @@ -1,10 +1,6 @@ use itertools::Itertools; -use rayon::prelude::*; -use std::collections::BTreeMap; -use std::fs::File; use std::process::Command; -use super::argument::Argument; use super::indentation::Indentation; use super::intrinsic::{IntrinsicDefinition, format_f16_return_value}; use super::intrinsic_helpers::IntrinsicTypeDefinition; @@ -12,86 +8,140 @@ use super::intrinsic_helpers::IntrinsicTypeDefinition; // The number of times each intrinsic will be called. const PASSES: u32 = 20; -pub fn format_rust_main_template( - notices: &str, - definitions: &str, - configurations: &str, - arch_definition: &str, - arglists: &str, - passes: &str, -) -> String { - format!( - r#"{notices}#![feature(simd_ffi)] -#![feature(f16)] -#![allow(unused)] -{configurations} -{definitions} - -use core_arch::arch::{arch_definition}::*; - -fn main() {{ -{arglists} -{passes} -}} -"#, - ) -} - -fn write_cargo_toml(w: &mut impl std::io::Write, binaries: &[String]) -> std::io::Result<()> { +fn write_cargo_toml_header(w: &mut impl std::io::Write, name: &str) -> std::io::Result<()> { writeln!( w, concat!( "[package]\n", - "name = \"intrinsic-test-programs\"\n", + "name = \"{name}\"\n", "version = \"{version}\"\n", "authors = [{authors}]\n", "license = \"{license}\"\n", "edition = \"2018\"\n", - "[workspace]\n", - "[dependencies]\n", - "core_arch = {{ path = \"../crates/core_arch\" }}", ), + name = name, version = env!("CARGO_PKG_VERSION"), authors = env!("CARGO_PKG_AUTHORS") .split(":") .format_with(", ", |author, fmt| fmt(&format_args!("\"{author}\""))), license = env!("CARGO_PKG_LICENSE"), - )?; + ) +} + +pub fn write_bin_cargo_toml( + w: &mut impl std::io::Write, + module_count: usize, +) -> std::io::Result<()> { + write_cargo_toml_header(w, "intrinsic-test-programs")?; + + writeln!(w, "[dependencies]")?; - for binary in binaries { - writeln!( - w, - concat!( - "[[bin]]\n", - "name = \"{binary}\"\n", - "path = \"{binary}/main.rs\"\n", - ), - binary = binary, - )?; + for i in 0..module_count { + writeln!(w, "mod_{i} = {{ path = \"mod_{i}/\" }}")?; } Ok(()) } -pub fn compile_rust_programs( - binaries: Vec, - toolchain: Option<&str>, - target: &str, - linker: Option<&str>, -) -> bool { - let mut cargo = File::create("rust_programs/Cargo.toml").unwrap(); - write_cargo_toml(&mut cargo, &binaries).unwrap(); +pub fn write_lib_cargo_toml(w: &mut impl std::io::Write, name: &str) -> std::io::Result<()> { + write_cargo_toml_header(w, name)?; + writeln!(w, "[dependencies]")?; + writeln!(w, "core_arch = {{ path = \"../../crates/core_arch\" }}")?; + + Ok(()) +} + +pub fn write_main_rs<'a>( + w: &mut impl std::io::Write, + chunk_count: usize, + cfg: &str, + definitions: &str, + intrinsics: impl Iterator + Clone, +) -> std::io::Result<()> { + writeln!(w, "#![feature(simd_ffi)]")?; + writeln!(w, "#![feature(f16)]")?; + writeln!(w, "#![allow(unused)]")?; + + // Cargo will spam the logs if these warnings are not silenced. + writeln!(w, "#![allow(non_upper_case_globals)]")?; + writeln!(w, "#![allow(non_camel_case_types)]")?; + writeln!(w, "#![allow(non_snake_case)]")?; + + writeln!(w, "{cfg}")?; + writeln!(w, "{definitions}")?; + + for module in 0..chunk_count { + writeln!(w, "use mod_{module}::*;")?; + } + + 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, + " other => panic!(\"unknown intrinsic `{{}}`\", other)," + )?; + + writeln!(w, " }}")?; + writeln!(w, "}}")?; + + Ok(()) +} + +pub fn write_lib_rs( + w: &mut impl std::io::Write, + architecture: &str, + notice: &str, + cfg: &str, + definitions: &str, + intrinsics: &[impl IntrinsicDefinition], +) -> std::io::Result<()> { + write!(w, "{notice}")?; + + writeln!(w, "#![feature(simd_ffi)]")?; + writeln!(w, "#![feature(f16)]")?; + writeln!(w, "#![allow(unused)]")?; + + // Cargo will spam the logs if these warnings are not silenced. + writeln!(w, "#![allow(non_upper_case_globals)]")?; + writeln!(w, "#![allow(non_camel_case_types)]")?; + writeln!(w, "#![allow(non_snake_case)]")?; + + writeln!(w, "{cfg}")?; + + writeln!(w, "use core_arch::arch::{architecture}::*;")?; + + writeln!(w, "{definitions}")?; + + for intrinsic in intrinsics { + crate::common::gen_rust::create_rust_test_module(w, intrinsic)?; + } + + Ok(()) +} + +pub fn compile_rust_programs(toolchain: Option<&str>, target: &str, linker: Option<&str>) -> bool { /* If there has been a linker explicitly set from the command line then * we want to set it via setting it in the RUSTFLAGS*/ + trace!("Building cargo command"); + let mut cargo_command = Command::new("cargo"); cargo_command.current_dir("rust_programs"); - if let Some(toolchain) = toolchain { - if !toolchain.is_empty() { - cargo_command.arg(toolchain); - } + // Do not use the target directory of the workspace please. + cargo_command.env("CARGO_TARGET_DIR", "target"); + + if let Some(toolchain) = toolchain + && !toolchain.is_empty() + { + cargo_command.arg(toolchain); } cargo_command.args(["build", "--target", target, "--release"]); @@ -105,7 +155,16 @@ pub fn compile_rust_programs( } cargo_command.env("RUSTFLAGS", rust_flags); + + trace!("running cargo"); + + if log::log_enabled!(log::Level::Trace) { + cargo_command.stdout(std::process::Stdio::inherit()); + cargo_command.stderr(std::process::Stdio::inherit()); + } + let output = cargo_command.output(); + trace!("cargo is done"); if let Ok(output) = output { if output.status.success() { @@ -124,119 +183,117 @@ pub fn compile_rust_programs( } } -// Creates directory structure and file path mappings -pub fn setup_rust_file_paths(identifiers: &Vec) -> BTreeMap<&String, String> { - identifiers - .par_iter() - .map(|identifier| { - let rust_dir = format!("rust_programs/{identifier}"); - let _ = std::fs::create_dir_all(&rust_dir); - let rust_filename = format!("{rust_dir}/main.rs"); - - (identifier, rust_filename) - }) - .collect::>() -} - pub fn generate_rust_test_loop( + w: &mut impl std::io::Write, intrinsic: &dyn IntrinsicDefinition, indentation: Indentation, - additional: &str, + specializations: &[Vec], passes: u32, -) -> String { - let constraints = intrinsic.arguments().as_constraint_parameters_rust(); - let constraints = if !constraints.is_empty() { - format!("::<{constraints}>") - } else { - constraints - }; +) -> std::io::Result<()> { + let intrinsic_name = intrinsic.name(); + + // Each function (and each specialization) has its own type. Erase that type with a cast. + let mut coerce = String::from("unsafe fn("); + for _ in intrinsic.arguments().iter().filter(|a| !a.has_constraint()) { + coerce += "_, "; + } + coerce += ") -> _"; + + match specializations { + [] => { + writeln!(w, " let specializations = [(\"\", {intrinsic_name})];")?; + } + [const_args] if const_args.is_empty() => { + writeln!(w, " let specializations = [(\"\", {intrinsic_name})];")?; + } + _ => { + writeln!(w, " let specializations = [")?; + + for specialization in specializations { + let mut specialization: Vec<_> = + specialization.iter().map(|d| d.to_string()).collect(); + + let const_args = specialization.join(","); + + // The identifier is reversed. + specialization.reverse(); + let id = specialization.join("-"); + + writeln!( + w, + " (\"-{id}\", {intrinsic_name}::<{const_args}> as {coerce})," + )?; + } + + writeln!(w, " ];")?; + } + } let return_value = format_f16_return_value(intrinsic); let indentation2 = indentation.nested(); let indentation3 = indentation2.nested(); - format!( - "{indentation}for i in 0..{passes} {{\n\ - {indentation2}unsafe {{\n\ - {loaded_args}\ - {indentation3}let __return_value = {intrinsic_call}{const}({args});\n\ - {indentation3}println!(\"Result {additional}-{{}}: {{:?}}\", i + 1, {return_value});\n\ - {indentation2}}}\n\ - {indentation}}}", + writeln!( + w, + "\ + for (id, f) in specializations {{\n\ + for i in 0..{passes} {{\n\ + unsafe {{\n\ + {loaded_args}\ + let __return_value = f({args});\n\ + println!(\"Result {{id}}-{{}}: {{:?}}\", i + 1, {return_value});\n\ + }}\n\ + }}\n\ + }}", loaded_args = intrinsic.arguments().load_values_rust(indentation3), - intrinsic_call = intrinsic.name(), - const = constraints, args = intrinsic.arguments().as_call_param_rust(), ) } -pub fn generate_rust_constraint_blocks( - intrinsic: &dyn IntrinsicDefinition, - indentation: Indentation, - constraints: &[&Argument], - name: String, -) -> String { - if let Some((current, constraints)) = constraints.split_last() { - let range = current - .constraint - .iter() - .map(|c| c.to_range()) - .flat_map(|r| r.into_iter()); - - let body_indentation = indentation.nested(); - range - .map(|i| { - format!( - "{indentation}{{\n\ - {body_indentation}const {name}: {ty} = {val};\n\ - {pass}\n\ - {indentation}}}", - name = current.name, - ty = current.ty.rust_type(), - val = i, - pass = generate_rust_constraint_blocks( - intrinsic, - body_indentation, - constraints, - format!("{name}-{i}") - ) - ) +/// Generate the specializations (unique sequences of const-generic arguments) for this intrinsic. +fn generate_rust_specializations<'a>( + constraints: &mut impl Iterator>, +) -> Vec> { + let mut specializations = vec![vec![]]; + + for constraint in constraints { + specializations = constraint + .flat_map(|right| { + specializations.iter().map(move |left| { + let mut left = left.clone(); + left.push(u8::try_from(right).unwrap()); + left + }) }) - .join("\n") - } else { - generate_rust_test_loop(intrinsic, indentation, &name, PASSES) + .collect(); } + + specializations } // Top-level function to create complete test program -pub fn create_rust_test_program( +pub fn create_rust_test_module( + w: &mut impl std::io::Write, intrinsic: &dyn IntrinsicDefinition, - target: &str, - notice: &str, - definitions: &str, - cfg: &str, -) -> String { +) -> std::io::Result<()> { + trace!("generating `{}`", intrinsic.name()); + let indentation = Indentation::default(); + + writeln!(w, "pub fn run_{}() {{", intrinsic.name())?; + + // Define the arrays of arguments. let arguments = intrinsic.arguments(); - let constraints = arguments - .iter() - .filter(|i| i.has_constraint()) - .collect_vec(); + arguments.gen_arglists_rust(w, indentation.nested(), PASSES)?; - let indentation = Indentation::default(); - format_rust_main_template( - notice, - definitions, - cfg, - target, - intrinsic - .arguments() - .gen_arglists_rust(indentation.nested(), PASSES) - .as_str(), - generate_rust_constraint_blocks( - intrinsic, - indentation.nested(), - &constraints, - Default::default(), - ) - .as_str(), - ) + // Define any const generics as `const` items, then generate the actual test loop. + let specializations = generate_rust_specializations( + &mut arguments + .iter() + .filter_map(|i| i.constraint.as_ref().map(|v| v.to_range())), + ); + + generate_rust_test_loop(w, intrinsic, indentation, &specializations, PASSES)?; + + writeln!(w, "}}")?; + + Ok(()) } diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index 697f9c8754..b53047b2d3 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -332,7 +332,4 @@ pub trait IntrinsicTypeDefinition: Deref { /// can be directly defined in `impl` blocks fn c_single_vector_type(&self) -> String; - - /// can be defined in `impl` blocks - fn rust_type(&self) -> String; } diff --git a/crates/intrinsic-test/src/common/mod.rs b/crates/intrinsic-test/src/common/mod.rs index 5d51d3460e..6c3154af38 100644 --- a/crates/intrinsic-test/src/common/mod.rs +++ b/crates/intrinsic-test/src/common/mod.rs @@ -11,7 +11,6 @@ pub mod indentation; pub mod intrinsic; pub mod intrinsic_helpers; pub mod values; -pub mod write_file; /// Architectures must support this trait /// to be successfully tested. diff --git a/crates/intrinsic-test/src/common/write_file.rs b/crates/intrinsic-test/src/common/write_file.rs deleted file mode 100644 index 92dd70b7c5..0000000000 --- a/crates/intrinsic-test/src/common/write_file.rs +++ /dev/null @@ -1,33 +0,0 @@ -use super::gen_rust::{create_rust_test_program, setup_rust_file_paths}; -use super::intrinsic::IntrinsicDefinition; -use super::intrinsic_helpers::IntrinsicTypeDefinition; -use std::fs::File; -use std::io::Write; - -pub fn write_file(filename: &String, code: String) { - let mut file = File::create(filename).unwrap(); - file.write_all(code.into_bytes().as_slice()).unwrap(); -} - -pub fn write_rust_testfiles( - intrinsics: Vec<&dyn IntrinsicDefinition>, - rust_target: &str, - notice: &str, - definitions: &str, - cfg: &str, -) -> Vec { - let intrinsics_name_list = intrinsics - .iter() - .map(|i| i.name().clone()) - .collect::>(); - let filename_mapping = setup_rust_file_paths(&intrinsics_name_list); - - intrinsics.iter().for_each(|&i| { - let rust_code = create_rust_test_program(i, rust_target, notice, definitions, cfg); - if let Some(filename) = filename_mapping.get(&i.name()) { - write_file(filename, rust_code) - } - }); - - intrinsics_name_list -}