about summary refs log tree commit diff
path: root/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/stdarch/crates/intrinsic-test/src/common/gen_c.rs')
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/gen_c.rs323
1 files changed, 162 insertions, 161 deletions
diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs
index 1cfb66c39b9..905efb6d890 100644
--- a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs
+++ b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs
@@ -1,8 +1,3 @@
-use itertools::Itertools;
-use rayon::prelude::*;
-use std::collections::BTreeMap;
-use std::process::Command;
-
 use super::argument::Argument;
 use super::indentation::Indentation;
 use super::intrinsic::IntrinsicDefinition;
@@ -11,104 +6,16 @@ use super::intrinsic_helpers::IntrinsicTypeDefinition;
 // The number of times each intrinsic will be called.
 const PASSES: u32 = 20;
 
-// Formats the main C program template with placeholders
-pub fn format_c_main_template(
-    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.join("\n"),
-    )
-}
-
-pub fn compile_c_programs(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()
-}
-
-// Creates directory structure and file path mappings
-pub fn setup_c_file_paths(identifiers: &Vec<String>) -> BTreeMap<&String, String> {
-    let _ = std::fs::create_dir("c_programs");
-    identifiers
-        .par_iter()
-        .map(|identifier| {
-            let c_filename = format!(r#"c_programs/{identifier}.cpp"#);
-
-            (identifier, c_filename)
-        })
-        .collect::<BTreeMap<&String, String>>()
-}
-
 pub fn generate_c_test_loop<T: IntrinsicTypeDefinition + Sized>(
+    w: &mut impl std::io::Write,
     intrinsic: &dyn IntrinsicDefinition<T>,
     indentation: Indentation,
     additional: &str,
     passes: u32,
-    _target: &str,
-) -> String {
+) -> std::io::Result<()> {
     let body_indentation = indentation.nested();
-    format!(
+    writeln!(
+        w,
         "{indentation}for (int i=0; i<{passes}; i++) {{\n\
             {loaded_args}\
             {body_indentation}auto __return_value = {intrinsic_call}({args});\n\
@@ -121,78 +28,172 @@ pub fn generate_c_test_loop<T: IntrinsicTypeDefinition + Sized>(
     )
 }
 
-pub fn generate_c_constraint_blocks<T: IntrinsicTypeDefinition>(
+pub fn generate_c_constraint_blocks<'a, T: IntrinsicTypeDefinition + 'a>(
+    w: &mut impl std::io::Write,
     intrinsic: &dyn IntrinsicDefinition<T>,
     indentation: Indentation,
-    constraints: &[&Argument<T>],
+    constraints: &mut (impl Iterator<Item = &'a Argument<T>> + Clone),
     name: String,
-    target: &str,
-) -> 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}{ty} {name} = {val};\n\
-                        {pass}\n\
-                    {indentation}}}",
-                    name = current.name,
-                    ty = current.ty.c_type(),
-                    val = i,
-                    pass = generate_c_constraint_blocks(
-                        intrinsic,
-                        body_indentation,
-                        constraints,
-                        format!("{name}-{i}"),
-                        target,
-                    )
-                )
-            })
-            .join("\n")
-    } else {
-        generate_c_test_loop(intrinsic, indentation, &name, PASSES, target)
+) -> std::io::Result<()> {
+    let Some(current) = constraints.next() else {
+        return generate_c_test_loop(w, intrinsic, indentation, &name, PASSES);
+    };
+
+    let body_indentation = indentation.nested();
+    for i in current.constraint.iter().flat_map(|c| c.to_range()) {
+        let ty = current.ty.c_type();
+
+        writeln!(w, "{indentation}{{")?;
+        writeln!(w, "{body_indentation}{ty} {} = {i};", current.name)?;
+
+        generate_c_constraint_blocks(
+            w,
+            intrinsic,
+            body_indentation,
+            &mut constraints.clone(),
+            format!("{name}-{i}"),
+        )?;
+
+        writeln!(w, "{indentation}}}")?;
     }
+
+    Ok(())
 }
 
 // Compiles C test programs using specified compiler
-pub fn create_c_test_program<T: IntrinsicTypeDefinition>(
+pub fn create_c_test_function<T: IntrinsicTypeDefinition>(
+    w: &mut impl std::io::Write,
     intrinsic: &dyn IntrinsicDefinition<T>,
-    header_files: &[&str],
-    target: &str,
-    c_target: &str,
-    notices: &str,
-    arch_specific_definitions: &[&str],
-) -> String {
+) -> std::io::Result<()> {
+    let indentation = Indentation::default();
+
+    writeln!(w, "int 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_c(w, indentation.nested(), PASSES)?;
 
-    let indentation = Indentation::default();
-    format_c_main_template(
-        notices,
-        header_files,
-        c_target,
-        arch_specific_definitions,
-        intrinsic
-            .arguments()
-            .gen_arglists_c(indentation, PASSES)
-            .as_str(),
-        generate_c_constraint_blocks(
-            intrinsic,
-            indentation.nested(),
-            constraints.as_slice(),
-            Default::default(),
-            target,
-        )
-        .as_str(),
-    )
+    generate_c_constraint_blocks(
+        w,
+        intrinsic,
+        indentation.nested(),
+        &mut arguments.iter().rev().filter(|&i| i.has_constraint()),
+        Default::default(),
+    )?;
+
+    writeln!(w, "    return 0;")?;
+    writeln!(w, "}}")?;
+
+    Ok(())
+}
+
+pub fn write_mod_cpp<T: IntrinsicTypeDefinition>(
+    w: &mut impl std::io::Write,
+    notice: &str,
+    architecture: &str,
+    platform_headers: &[&str],
+    intrinsics: &[impl IntrinsicDefinition<T>],
+) -> std::io::Result<()> {
+    write!(w, "{notice}")?;
+
+    for header in platform_headers {
+        writeln!(w, "#include <{header}>")?;
+    }
+
+    writeln!(
+        w,
+        r#"
+#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);
+
+
+
+"#
+    )?;
+
+    writeln!(w, "#ifdef __{architecture}__")?;
+    writeln!(
+        w,
+        "std::ostream& operator<<(std::ostream& os, poly128_t value);"
+    )?;
+    writeln!(w, "#endif")?;
+
+    for intrinsic in intrinsics {
+        create_c_test_function(w, intrinsic)?;
+    }
+
+    Ok(())
+}
+
+pub fn write_main_cpp<'a>(
+    w: &mut impl std::io::Write,
+    architecture: &str,
+    arch_specific_definitions: &str,
+    intrinsics: impl Iterator<Item = &'a str> + Clone,
+) -> std::io::Result<()> {
+    writeln!(w, "#include <iostream>")?;
+    writeln!(w, "#include <string>")?;
+
+    for header in ["arm_neon.h", "arm_acle.h", "arm_fp16.h"] {
+        writeln!(w, "#include <{header}>")?;
+    }
+
+    writeln!(
+        w,
+        r#"
+#include <cstring>
+#include <iomanip>
+#include <sstream>
+
+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;
+}}
+"#
+    )?;
+
+    writeln!(w, "#ifdef __{architecture}__")?;
+    writeln!(w, "{arch_specific_definitions }")?;
+    writeln!(w, "#endif")?;
+
+    for intrinsic in intrinsics.clone() {
+        writeln!(w, "extern int run_{intrinsic}(void);")?;
+    }
+
+    writeln!(w, "int main(int argc, char **argv) {{")?;
+    writeln!(w, "    std::string intrinsic_name = argv[1];")?;
+
+    writeln!(w, "    if (false) {{")?;
+
+    for intrinsic in intrinsics {
+        writeln!(w, "    }} else if (intrinsic_name == \"{intrinsic}\") {{")?;
+        writeln!(w, "        return run_{intrinsic}();")?;
+    }
+
+    writeln!(w, "    }} else {{")?;
+    writeln!(
+        w,
+        "        std::cerr << \"Unknown command: \" << intrinsic_name << \"\\n\";"
+    )?;
+    writeln!(w, "        return -1;")?;
+    writeln!(w, "    }}")?;
+
+    writeln!(w, "}}")?;
+
+    Ok(())
 }