Skip to content

Commit

Permalink
Update stdarch-gen-arm path generation.
Browse files Browse the repository at this point in the history
Fix both the instructions for how to regenerate each `generated.rs`, and
the logic for inferring the correct output path from each input
`.spec.yml`.
  • Loading branch information
jacobbramley committed Jan 29, 2025
1 parent 25c8002 commit 6be8c4c
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 46 deletions.
6 changes: 3 additions & 3 deletions crates/stdarch-gen-arm/src/load_store_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ pub fn generate_load_store_tests(
format!(
"// This code is automatically generated. DO NOT MODIFY.
//
// Instead, modify `crates/stdarch-gen2/spec/sve` and run the following command to re-generate this
// file:
// Instead, modify `crates/stdarch-gen-arm/spec/sve` and run the following command to re-generate
// this file:
//
// ```
// cargo run --bin=stdarch-gen2 -- crates/stdarch-gen2/spec
// cargo run --bin=stdarch-gen-arm -- crates/stdarch-gen-arm/spec
// ```
{}",
quote! { #preamble #(#tests)* #manual_tests }
Expand Down
117 changes: 74 additions & 43 deletions crates/stdarch-gen-arm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ fn parse_args() -> Vec<(PathBuf, Option<PathBuf>)> {
let mut args_it = std::env::args().skip(1);
assert!(
1 <= args_it.len() && args_it.len() <= 2,
"Usage: cargo run -p stdarch-gen2 -- INPUT_DIR [OUTPUT_DIR]"
"Usage: cargo run -p stdarch-gen-arm -- INPUT_DIR [OUTPUT_DIR]\n\
where:\n\
- INPUT_DIR contains a tree like: INPUT_DIR/<feature>/<arch>.spec.yml\n\
- OUTPUT_DIR is a directory like: crates/core_arch/src/"
);

let in_path = Path::new(args_it.next().unwrap().as_str()).to_path_buf();
Expand All @@ -124,7 +127,7 @@ fn parse_args() -> Vec<(PathBuf, Option<PathBuf>)> {
std::env::current_exe()
.map(|mut f| {
f.pop();
f.push("../../crates/core_arch/src/aarch64/");
f.push("../../crates/core_arch/src/");
f.exists().then_some(f)
})
.ok()
Expand All @@ -147,10 +150,10 @@ fn generate_file(
out,
r#"// This code is automatically generated. DO NOT MODIFY.
//
// Instead, modify `crates/stdarch-gen2/spec/` and run the following command to re-generate this file:
// Instead, modify `crates/stdarch-gen-arm/spec/` and run the following command to re-generate this file:
//
// ```
// cargo run --bin=stdarch-gen2 -- crates/stdarch-gen2/spec
// cargo run --bin=stdarch-gen-arm -- crates/stdarch-gen-arm/spec
// ```
#![allow(improper_ctypes)]
Expand Down Expand Up @@ -183,17 +186,19 @@ pub fn format_code(
output.write_all(proc.wait_with_output()?.stdout.as_slice())
}

/// Derive an output file name from an input file and an output directory.
/// Derive an output file path from an input file path and an output directory.
///
/// The name is formed by:
/// `in_filepath` is expected to have a structure like:
/// .../<feature>/<arch>.spec.yml
///
/// - ... taking in_filepath.file_name() (dropping all directory components),
/// - ... dropping a .yml or .yaml extension (if present),
/// - ... then dropping a .spec extension (if present).
/// The resulting output path will have a structure like:
/// <out_dirpath>/<arch>/<feature>/generated.rs
///
/// Panics if the resulting name is empty, or if file_name() is not UTF-8.
fn make_output_filepath(in_filepath: &Path, out_dirpath: &Path) -> PathBuf {
make_filepath(in_filepath, out_dirpath, |name: &str| format!("{name}.rs"))
make_filepath(in_filepath, out_dirpath, |_name: &str| {
format!("generated.rs")
})
}

fn make_tests_filepath(in_filepath: &Path, out_dirpath: &Path) -> PathBuf {
Expand All @@ -207,22 +212,27 @@ fn make_filepath<F: FnOnce(&str) -> String>(
out_dirpath: &Path,
name_formatter: F,
) -> PathBuf {
let mut parts = in_filepath.iter();
let name = parts
.next_back()
.and_then(|f| f.to_str())
.expect("Inputs must have valid, UTF-8 file_name()");
let dir = parts.next_back().unwrap();
let mut parts = in_filepath.components().rev().map(|f| {
f.as_os_str()
.to_str()
.expect("Inputs must have valid, UTF-8 file_name()")
});
let yml = parts.next().expect("Not enough input path elements.");
let feature = parts.next().expect("Not enough input path elements.");

let name = name
.trim_end_matches(".yml")
.trim_end_matches(".yaml")
.trim_end_matches(".spec");
assert!(!name.is_empty());
let arch = yml
.strip_suffix(".yml")
.expect("Expected .yml file input.")
.strip_suffix(".spec")
.expect("Expected .spec.yml file input.");
if arch.is_empty() {
panic!("Extended ARCH.spec.yml file input.");
}

let mut output = out_dirpath.to_path_buf();
output.push(dir);
output.push(name_formatter(name));
output.push(arch);
output.push(feature);
output.push(name_formatter(arch));
output
}

Expand All @@ -233,47 +243,68 @@ mod tests {
#[test]
fn infer_output_file() {
macro_rules! t {
($src:expr, $outdir:expr, $dst:expr) => {
($src:expr, $outdir:expr, $dst:expr, $ldst:expr) => {
let src: PathBuf = $src.iter().collect();
let outdir: PathBuf = $outdir.iter().collect();
let dst: PathBuf = $dst.iter().collect();
let ldst: PathBuf = $ldst.iter().collect();
assert_eq!(make_output_filepath(&src, &outdir), dst);
assert_eq!(make_tests_filepath(&src, &outdir), ldst);
};
}
// Documented usage.
t!(["x", "NAME.spec.yml"], [""], ["x", "NAME.rs"]);
t!(
["x", "NAME.spec.yml"],
["a", "b"],
["a", "b", "x", "NAME.rs"]
["FEAT", "ARCH.spec.yml"],
[""],
["ARCH", "FEAT", "generated.rs"],
["ARCH", "FEAT", "ld_st_tests_ARCH.rs"]
);
t!(
["x", "y", "NAME.spec.yml"],
["x", "y", "FEAT", "ARCH.spec.yml"],
["out"],
["out", "y", "NAME.rs"]
["out", "ARCH", "FEAT", "generated.rs"],
["out", "ARCH", "FEAT", "ld_st_tests_ARCH.rs"]
);
t!(["x", "NAME.spec.yaml"], ["out"], ["out", "x", "NAME.rs"]);
t!(["x", "NAME.spec"], ["out"], ["out", "x", "NAME.rs"]);
t!(["x", "NAME.yml"], ["out"], ["out", "x", "NAME.rs"]);
t!(["x", "NAME.yaml"], ["out"], ["out", "x", "NAME.rs"]);
// Unrecognised extensions get treated as part of the stem.
t!(
["x", "NAME.spac.yml"],
["out"],
["out", "x", "NAME.spac.rs"]
["p", "q", "FEAT", "ARCH.spec.yml"],
["a", "b"],
["a", "b", "ARCH", "FEAT", "generated.rs"],
["a", "b", "ARCH", "FEAT", "ld_st_tests_ARCH.rs"]
);
t!(["x", "NAME.txt"], ["out"], ["out", "x", "NAME.txt.rs"]);
// Always take the top-level directory from the input path
// Extra extensions get treated as part of the stem.
t!(
["x", "y", "z", "NAME.spec.yml"],
["FEAT", "ARCH.variant.spec.yml"],
["out"],
["out", "z", "NAME.rs"]
["out", "ARCH.variant", "FEAT", "generated.rs"],
["out", "ARCH.variant", "FEAT", "ld_st_tests_ARCH.variant.rs"]
);
}

#[test]
#[should_panic]
fn infer_output_file_no_stem() {
make_output_filepath(Path::new(".spec.yml"), Path::new(""));
let src = PathBuf::from("FEAT/.spec.yml");
make_output_filepath(&src, Path::new(""));
}

#[test]
#[should_panic]
fn infer_output_file_no_feat() {
let src = PathBuf::from("ARCH.spec.yml");
make_output_filepath(&src, Path::new(""));
}

#[test]
#[should_panic]
fn infer_output_file_ldst_no_stem() {
let src = PathBuf::from("FEAT/.spec.yml");
make_tests_filepath(&src, Path::new(""));
}

#[test]
#[should_panic]
fn infer_output_file_ldst_no_feat() {
let src = PathBuf::from("ARCH.spec.yml");
make_tests_filepath(&src, Path::new(""));
}
}

0 comments on commit 6be8c4c

Please sign in to comment.