diff --git a/library/stdarch/crates/intrinsic-test/src/argument.rs b/library/stdarch/crates/intrinsic-test/src/argument.rs index 7dbbb5a2a531..e80760ca3aa4 100644 --- a/library/stdarch/crates/intrinsic-test/src/argument.rs +++ b/library/stdarch/crates/intrinsic-test/src/argument.rs @@ -1,5 +1,6 @@ use std::ops::Range; +use crate::format::Indentation; use crate::json_parser::ArgPrep; use crate::types::{IntrinsicType, TypeKind}; use crate::Language; @@ -169,15 +170,15 @@ impl ArgumentList { /// 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. - pub fn gen_arglists_c(&self, loads: u32) -> String { + pub fn gen_arglists_c(&self, indentation: Indentation, loads: u32) -> String { self.iter() .filter_map(|arg| { (!arg.has_constraint()).then(|| { format!( - "const {ty} {name}_vals[] = {values};", + "{indentation}const {ty} {name}_vals[] = {values};", ty = arg.ty.c_scalar_type(), name = arg.name, - values = arg.ty.populate_random(loads, &Language::C) + values = arg.ty.populate_random(indentation, loads, &Language::C) ) }) }) @@ -187,17 +188,17 @@ impl ArgumentList { /// 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, loads: u32) -> String { + pub fn gen_arglists_rust(&self, indentation: Indentation, loads: u32) -> String { self.iter() .filter_map(|arg| { (!arg.has_constraint()).then(|| { format!( - "{bind} {name}: [{ty}; {load_size}] = {values};", + "{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(loads, &Language::Rust) + values = arg.ty.populate_random(indentation, loads, &Language::Rust) ) }) }) @@ -208,7 +209,7 @@ impl ArgumentList { /// Creates a line for each argument that initializes the argument from an array `[arg]_vals` at /// an offset `i` using a load intrinsic, in C. /// e.g `uint8x8_t a = vld1_u8(&a_vals[i]);` - pub fn load_values_c(&self, p64_armv7_workaround: bool) -> String { + pub fn load_values_c(&self, indentation: Indentation, p64_armv7_workaround: bool) -> String { self.iter() .filter_map(|arg| { // The ACLE doesn't support 64-bit polynomial loads on Armv7 @@ -221,7 +222,7 @@ impl ArgumentList { (!arg.has_constraint()).then(|| { format!( - "{ty} {name} = {open_cast}{load}(&{name}_vals[i]){close_cast};", + "{indentation}{ty} {name} = {open_cast}{load}(&{name}_vals[i]){close_cast};\n", ty = arg.to_c_type(), name = arg.name, load = if arg.is_simd() { @@ -242,19 +243,18 @@ impl ArgumentList { ) }) }) - .collect::>() - .join("\n ") + .collect() } /// Creates a line for each argument that initializes the argument from array `[ARG]_VALS` at /// an offset `i` using a load intrinsic, in Rust. /// e.g `let a = vld1_u8(A_VALS.as_ptr().offset(i));` - pub fn load_values_rust(&self) -> String { + pub fn load_values_rust(&self, indentation: Indentation) -> String { self.iter() .filter_map(|arg| { (!arg.has_constraint()).then(|| { format!( - "let {name} = {load}({vals_name}.as_ptr().offset(i));", + "{indentation}let {name} = {load}({vals_name}.as_ptr().offset(i));\n", name = arg.name, vals_name = arg.rust_vals_array_name(), load = if arg.is_simd() { @@ -265,8 +265,7 @@ impl ArgumentList { ) }) }) - .collect::>() - .join("\n ") + .collect() } pub fn iter(&self) -> std::slice::Iter<'_, Argument> { diff --git a/library/stdarch/crates/intrinsic-test/src/format.rs b/library/stdarch/crates/intrinsic-test/src/format.rs new file mode 100644 index 000000000000..fd185fb74852 --- /dev/null +++ b/library/stdarch/crates/intrinsic-test/src/format.rs @@ -0,0 +1,28 @@ +//! Basic code formatting tools. +//! +//! We don't need perfect formatting for the generated tests, but simple indentation can make +//! debugging a lot easier. + +#[derive(Copy, Clone, Debug)] +pub struct Indentation(u32); + +impl std::default::Default for Indentation { + fn default() -> Self { + Self(0) + } +} + +impl Indentation { + pub fn nested(self) -> Self { + Self(self.0 + 1) + } +} + +impl std::fmt::Display for Indentation { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + for _ in 0..self.0 { + write!(f, " ")?; + } + Ok(()) + } +} diff --git a/library/stdarch/crates/intrinsic-test/src/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/intrinsic.rs index fb4eb4cb717f..b83c371ea497 100644 --- a/library/stdarch/crates/intrinsic-test/src/intrinsic.rs +++ b/library/stdarch/crates/intrinsic-test/src/intrinsic.rs @@ -1,3 +1,4 @@ +use crate::format::Indentation; use crate::types::{IntrinsicType, TypeKind}; use super::argument::ArgumentList; @@ -22,7 +23,7 @@ impl Intrinsic { /// Generates a std::cout for the intrinsics results that will match the /// rust debug output format for the return type. The generated line assumes /// there is an int i in scope which is the current pass number. - pub fn print_result_c(&self, additional: &str) -> String { + pub fn print_result_c(&self, indentation: Indentation, additional: &str) -> String { let lanes = if self.results.num_vectors() > 1 { (0..self.results.num_vectors()) .map(|vector| { @@ -73,7 +74,7 @@ impl Intrinsic { }; format!( - r#"std::cout << "Result {additional}-" << i+1 << ": {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#, + r#"{indentation}std::cout << "Result {additional}-" << i+1 << ": {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#, ty = if self.results.is_simd() { format!("{}(", self.results.c_type()) } else { @@ -87,26 +88,33 @@ impl Intrinsic { pub fn generate_loop_c( &self, + indentation: Indentation, additional: &str, passes: u32, p64_armv7_workaround: bool, ) -> String { + let body_indentation = indentation.nested(); format!( - r#" {{ - for (int i=0; i<{passes}; i++) {{ - {loaded_args} - auto __return_value = {intrinsic_call}({args}); - {print_result} - }} - }}"#, - loaded_args = self.arguments.load_values_c(p64_armv7_workaround), + "{indentation}for (int i=0; i<{passes}; i++) {{\n\ + {loaded_args}\ + {body_indentation}auto __return_value = {intrinsic_call}({args});\n\ + {print_result}\n\ + {indentation}}}", + loaded_args = self + .arguments + .load_values_c(body_indentation, p64_armv7_workaround), intrinsic_call = self.name, args = self.arguments.as_call_param_c(), - print_result = self.print_result_c(additional) + print_result = self.print_result_c(body_indentation, additional) ) } - pub fn generate_loop_rust(&self, additional: &str, passes: u32) -> String { + pub fn generate_loop_rust( + &self, + indentation: Indentation, + additional: &str, + passes: u32, + ) -> String { let constraints = self.arguments.as_constraint_parameters_rust(); let constraints = if !constraints.is_empty() { format!("::<{constraints}>") @@ -114,17 +122,17 @@ impl Intrinsic { constraints }; + let indentation2 = indentation.nested(); + let indentation3 = indentation2.nested(); format!( - r#" {{ - for i in 0..{passes} {{ - unsafe {{ - {loaded_args} - let __return_value = {intrinsic_call}{const}({args}); - println!("Result {additional}-{{}}: {{:.150?}}", i+1, __return_value); - }} - }} - }}"#, - loaded_args = self.arguments.load_values_rust(), + "{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}-{{}}: {{:.150?}}\", i + 1, __return_value);\n\ + {indentation2}}}\n\ + {indentation}}}", + loaded_args = self.arguments.load_values_rust(indentation3), intrinsic_call = self.name, const = constraints, args = self.arguments.as_call_param_rust(), diff --git a/library/stdarch/crates/intrinsic-test/src/main.rs b/library/stdarch/crates/intrinsic-test/src/main.rs index 4890bf5aab3c..2f567c981e08 100644 --- a/library/stdarch/crates/intrinsic-test/src/main.rs +++ b/library/stdarch/crates/intrinsic-test/src/main.rs @@ -13,9 +13,11 @@ use rayon::prelude::*; use types::TypeKind; use crate::argument::Argument; +use crate::format::Indentation; use crate::json_parser::get_neon_intrinsics; mod argument; +mod format; mod intrinsic; mod json_parser; mod types; @@ -31,6 +33,7 @@ pub enum Language { } fn gen_code_c( + indentation: Indentation, intrinsic: &Intrinsic, constraints: &[&Argument], name: String, @@ -43,17 +46,19 @@ fn gen_code_c( .map(|c| c.to_range()) .flat_map(|r| r.into_iter()); + let body_indentation = indentation.nested(); range .map(|i| { format!( - r#" {{ - {ty} {name} = {val}; -{pass} - }}"#, + "{indentation}{{\n\ + {body_indentation}{ty} {name} = {val};\n\ + {pass}\n\ + {indentation}}}", name = current.name, ty = current.ty.c_type(), val = i, pass = gen_code_c( + body_indentation, intrinsic, constraints, format!("{name}-{i}"), @@ -61,9 +66,9 @@ fn gen_code_c( ) ) }) - .collect() + .join("\n") } else { - intrinsic.generate_loop_c(&name, PASSES, p64_armv7_workaround) + intrinsic.generate_loop_c(indentation, &name, PASSES, p64_armv7_workaround) } } @@ -79,6 +84,7 @@ fn generate_c_program( .filter(|i| i.has_constraint()) .collect_vec(); + let indentation = Indentation::default(); format!( r#"{notices}{header_files} #include @@ -119,8 +125,9 @@ int main(int argc, char **argv) {{ .map(|header| format!("#include <{header}>")) .collect::>() .join("\n"), - arglists = intrinsic.arguments.gen_arglists_c(PASSES), + arglists = intrinsic.arguments.gen_arglists_c(indentation, PASSES), passes = gen_code_c( + indentation.nested(), intrinsic, constraints.as_slice(), Default::default(), @@ -129,7 +136,12 @@ int main(int argc, char **argv) {{ ) } -fn gen_code_rust(intrinsic: &Intrinsic, constraints: &[&Argument], name: String) -> String { +fn gen_code_rust( + indentation: Indentation, + intrinsic: &Intrinsic, + constraints: &[&Argument], + name: String, +) -> String { if let Some((current, constraints)) = constraints.split_last() { let range = current .constraints @@ -137,22 +149,28 @@ fn gen_code_rust(intrinsic: &Intrinsic, constraints: &[&Argument], name: String) .map(|c| c.to_range()) .flat_map(|r| r.into_iter()); + let body_indentation = indentation.nested(); range .map(|i| { format!( - r#" {{ - const {name}: {ty} = {val}; -{pass} - }}"#, + "{indentation}{{\n\ + {body_indentation}const {name}: {ty} = {val};\n\ + {pass}\n\ + {indentation}}}", name = current.name, ty = current.ty.rust_type(), val = i, - pass = gen_code_rust(intrinsic, constraints, format!("{name}-{i}")) + pass = gen_code_rust( + body_indentation, + intrinsic, + constraints, + format!("{name}-{i}") + ) ) }) - .collect() + .join("\n") } else { - intrinsic.generate_loop_rust(&name, PASSES) + intrinsic.generate_loop_rust(indentation, &name, PASSES) } } @@ -163,6 +181,7 @@ fn generate_rust_program(notices: &str, intrinsic: &Intrinsic, a32: bool) -> Str .filter(|i| i.has_constraint()) .collect_vec(); + let indentation = Indentation::default(); format!( r#"{notices}#![feature(simd_ffi)] #![feature(link_llvm_intrinsics)] @@ -183,8 +202,15 @@ fn main() {{ }} "#, target_arch = if a32 { "arm" } else { "aarch64" }, - arglists = intrinsic.arguments.gen_arglists_rust(PASSES), - passes = gen_code_rust(intrinsic, &constraints, Default::default()) + arglists = intrinsic + .arguments + .gen_arglists_rust(indentation.nested(), PASSES), + passes = gen_code_rust( + indentation.nested(), + intrinsic, + &constraints, + Default::default() + ) ) } diff --git a/library/stdarch/crates/intrinsic-test/src/types.rs b/library/stdarch/crates/intrinsic-test/src/types.rs index 47178a578f40..a3db342ae2ae 100644 --- a/library/stdarch/crates/intrinsic-test/src/types.rs +++ b/library/stdarch/crates/intrinsic-test/src/types.rs @@ -3,6 +3,7 @@ use std::str::FromStr; use itertools::Itertools as _; +use crate::format::Indentation; use crate::values::value_for_array; use crate::Language; @@ -301,9 +302,14 @@ impl IntrinsicType { /// Returns a string such as /// * `{0x1, 0x7F, 0xFF}` if `language` is `Language::C` /// * `[0x1 as _, 0x7F as _, 0xFF as _]` if `language` is `Language::Rust` - pub fn populate_random(&self, loads: u32, language: &Language) -> String { + pub fn populate_random( + &self, + indentation: Indentation, + loads: u32, + language: &Language, + ) -> String { match self { - IntrinsicType::Ptr { child, .. } => child.populate_random(loads, language), + IntrinsicType::Ptr { child, .. } => child.populate_random(indentation, loads, language), IntrinsicType::Type { bit_len: Some(bit_len @ (8 | 16 | 32 | 64)), kind: kind @ (TypeKind::Int | TypeKind::UInt | TypeKind::Poly), @@ -315,10 +321,11 @@ impl IntrinsicType { &Language::Rust => ("[", "]"), &Language::C => ("{", "}"), }; + let body_indentation = indentation.nested(); format!( - "{prefix}{body}{suffix}", + "{prefix}\n{body}\n{indentation}{suffix}", body = (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1)) - .format_with(", ", |i, fmt| { + .format_with(",\n", |i, fmt| { let src = value_for_array(*bit_len, i); assert!(src == 0 || src.ilog2() < *bit_len); if *kind == TypeKind::Int && (src >> (*bit_len - 1)) != 0 { @@ -329,12 +336,12 @@ impl IntrinsicType { if (twos_compl == src) && (language == &Language::C) { // `src` is INT*_MIN. C requires `-0x7fffffff - 1` to avoid // undefined literal overflow behaviour. - fmt(&format_args!("-{ones_compl:#x} - 1")) + fmt(&format_args!("{body_indentation}-{ones_compl:#x} - 1")) } else { - fmt(&format_args!("-{twos_compl:#x}")) + fmt(&format_args!("{body_indentation}-{twos_compl:#x}")) } } else { - fmt(&format_args!("{src:#x}")) + fmt(&format_args!("{body_indentation}{src:#x}")) } }) ) @@ -354,10 +361,11 @@ impl IntrinsicType { _ => unreachable!(), }; format!( - "{prefix}{body}{suffix}", + "{prefix}\n{body}\n{indentation}{suffix}", body = (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1)) - .format_with(", ", |i, fmt| fmt(&format_args!( - "{cast_prefix}{src:#x}{cast_suffix}", + .format_with(",\n", |i, fmt| fmt(&format_args!( + "{indentation}{cast_prefix}{src:#x}{cast_suffix}", + indentation = indentation.nested(), src = value_for_array(*bit_len, i) ))) )