diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b5b45f5f0d..f162ffa113 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -325,9 +325,10 @@ jobs: - name: Install Rust run: rustup update nightly && rustup default nightly && rustup component add rustfmt - name: Check arm spec + env: + STDARCH_GEN_MODE: check run: | cargo run --bin=stdarch-gen-arm --release -- crates/stdarch-gen-arm/spec - git diff --exit-code - name: Check loongarch lsx env: STDARCH_GEN_MODE: check diff --git a/Cargo.lock b/Cargo.lock index 427981218f..9923b630cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -831,6 +831,7 @@ dependencies = [ "serde", "serde_with", "serde_yaml", + "stdarch-gen-common", "walkdir", ] diff --git a/crates/stdarch-gen-arm/Cargo.toml b/crates/stdarch-gen-arm/Cargo.toml index 84f6249bb9..cb284d5f2c 100644 --- a/crates/stdarch-gen-arm/Cargo.toml +++ b/crates/stdarch-gen-arm/Cargo.toml @@ -17,6 +17,7 @@ proc-macro2 = "1.0" quote = "1.0" regex = "1.5" serde = { version = "1.0", features = ["derive"] } +stdarch-gen-common = { path = "../stdarch-gen-common" } serde_with = { version = "3.2.0", default-features = false, features = ["macros"] } serde_yaml = "0.8" walkdir = "2.3.2" diff --git a/crates/stdarch-gen-arm/src/main.rs b/crates/stdarch-gen-arm/src/main.rs index 717a1707aa..d6d407775f 100644 --- a/crates/stdarch-gen-arm/src/main.rs +++ b/crates/stdarch-gen-arm/src/main.rs @@ -21,87 +21,97 @@ use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; +use stdarch_gen_common::{Mode, run_generator}; use walkdir::WalkDir; fn main() -> Result<(), String> { - parse_args() + let (in_path, out_base) = parse_args(); + let mode = Mode::from_env(); + + for filepath in WalkDir::new(&in_path) .into_iter() - .map(|(filepath, out)| { - File::open(&filepath) - .map(|f| (f, filepath, out)) - .map_err(|e| format!("could not read input file: {e}")) - }) - .map(|res| { - let (file, filepath, out) = res?; - serde_yaml::from_reader(file) - .map(|input: input::GeneratorInput| (input, filepath, out)) - .map_err(|e| format!("could not parse input file: {e}")) + .filter_map(Result::ok) + .filter(|f| f.file_type().is_file()) + .filter(|f| f.file_name().to_string_lossy().ends_with(".yml")) + .map(|f| f.into_path()) + { + // The output folder for this spec file (`///`) the + // directory the harness checks/blesses against. + let committed = make_output_filepath(&filepath, &out_base) + .parent() + .expect("generated output path must have a parent directory") + .to_path_buf(); + + run_generator(&committed, mode, |scratch: &Path| { + generate_spec(&filepath, scratch) }) - .collect::, _>>()? - .into_iter() - .map(|(input, filepath, out)| { - let intrinsics = input.intrinsics.into_iter() - .map(|intrinsic| { - intrinsic.generate_variants(&input.ctx) - }) - .try_collect() - .map(|mut vv: Vec<_>| { - vv.sort_by_cached_key(|variants| { - variants.first().map_or_else(String::default, |variant| { - variant.signature.fn_name().to_string() - }) - }); - vv.into_iter().flatten().collect_vec() - })?; + .map_err(|e| e.to_string())?; + } + Ok(()) +} - if input.ctx.generate_load_store_tests { - let loads = intrinsics.iter() - .filter_map(|i| { - if matches!(i.test, Test::Load(..)) { - Some(i.clone()) - } else { - None - } - }).collect(); - let stores = intrinsics.iter() - .filter_map(|i| { - if matches!(i.test, Test::Store(..)) { - Some(i.clone()) - } else { - None - } - }).collect(); - load_store_tests::generate_load_store_tests(loads, stores, out.as_ref().map(|o| make_tests_filepath(&filepath, o)).as_ref())?; - } +/// Generate the output files for a single spec file into `out_dir`. +fn generate_spec(filepath: &Path, out_dir: &Path) -> Result<(), String> { + let file = File::open(filepath).map_err(|e| format!("could not read input file: {e}"))?; + let input: input::GeneratorInput = + serde_yaml::from_reader(file).map_err(|e| format!("could not parse input file: {e}"))?; - Ok(( - input::GeneratorInput { - intrinsics, - ctx: input.ctx, - }, - filepath, - out, - )) - }) - .try_for_each( - |result: context::Result<(input::GeneratorInput, PathBuf, Option)>| -> context::Result { - let (generated, filepath, out) = result?; + let intrinsics = input + .intrinsics + .into_iter() + .map(|intrinsic| intrinsic.generate_variants(&input.ctx)) + .try_collect() + .map(|mut vv: Vec<_>| { + vv.sort_by_cached_key(|variants| { + variants.first().map_or_else(String::default, |variant| { + variant.signature.fn_name().to_string() + }) + }); + vv.into_iter().flatten().collect_vec() + })?; - let w = match out { - Some(out) => Box::new( - File::create(make_output_filepath(&filepath, &out)) - .map_err(|e| format!("could not create output file: {e}"))?, - ) as Box, - None => Box::new(std::io::stdout()) as Box, - }; + if input.ctx.generate_load_store_tests { + let loads = intrinsics + .iter() + .filter_map(|i| { + if matches!(i.test, Test::Load(..)) { + Some(i.clone()) + } else { + None + } + }) + .collect(); + let stores = intrinsics + .iter() + .filter_map(|i| { + if matches!(i.test, Test::Store(..)) { + Some(i.clone()) + } else { + None + } + }) + .collect(); + // Reuse make_tests_filepath to derive the correct leaf name + // (`ld_st_tests_.rs`), then write it into out_dir. + let tests_name = make_tests_filepath(filepath, Path::new("")) + .file_name() + .expect("load/store test path must have a file name") + .to_owned(); + let tests_path = out_dir.join(tests_name); + load_store_tests::generate_load_store_tests(loads, stores, Some(&tests_path))?; + } - generate_file(generated, w) - .map_err(|e| format!("could not generate output file: {e}")) - }, - ) + let generated = input::GeneratorInput { + intrinsics, + ctx: input.ctx, + }; + let out_file = File::create(out_dir.join("generated.rs")) + .map_err(|e| format!("could not create output file: {e}"))?; + generate_file(generated, Box::new(out_file) as Box) + .map_err(|e| format!("could not generate output file: {e}")) } -fn parse_args() -> Vec<(PathBuf, Option)> { +fn parse_args() -> (PathBuf, PathBuf) { let mut args_it = std::env::args().skip(1); assert!( 1 <= args_it.len() && args_it.len() <= 2, @@ -117,31 +127,26 @@ fn parse_args() -> Vec<(PathBuf, Option)> { "invalid path {in_path:#?} given" ); - let out_dir = if let Some(dir) = args_it.next() { + let out_base = if let Some(dir) = args_it.next() { let out_path = Path::new(dir.as_str()).to_path_buf(); assert!( out_path.exists() && out_path.is_dir(), "invalid path {out_path:#?} given" ); - Some(out_path) + out_path } else { std::env::current_exe() + .ok() .map(|mut f| { f.pop(); f.push("../../crates/core_arch/src/"); - f.exists().then_some(f) + f }) - .ok() - .flatten() + .filter(|f| f.exists()) + .expect("could not locate crates/core_arch/src; pass OUTPUT_DIR command-line argument explicitly") }; - WalkDir::new(in_path) - .into_iter() - .filter_map(Result::ok) - .filter(|f| f.file_type().is_file()) - .filter(|f| f.file_name().to_string_lossy().ends_with(".yml")) - .map(|f| (f.into_path(), out_dir.clone())) - .collect() + (in_path, out_base) } fn generate_file(