about summary refs log tree commit diff
path: root/library/stdarch/crates
diff options
context:
space:
mode:
Diffstat (limited to 'library/stdarch/crates')
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/compile.rs68
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/mod.rs4
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/compile_c.rs124
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/gen_c.rs40
4 files changed, 92 insertions, 144 deletions
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/compile.rs b/library/stdarch/crates/intrinsic-test/src/arm/compile.rs
index a90caf367ca..48a8ed950e3 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/compile.rs
+++ b/library/stdarch/crates/intrinsic-test/src/arm/compile.rs
@@ -1,11 +1,8 @@
 use crate::common::cli::ProcessedCli;
-use crate::common::compile_c::CompilationCommandBuilder;
-use crate::common::gen_c::compile_c_programs;
+use crate::common::compile_c::{CompilationCommandBuilder, CppCompilation};
 
-pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) -> bool {
-    let Some(ref cpp_compiler) = config.cpp_compiler else {
-        return true;
-    };
+pub fn build_cpp_compilation(config: &ProcessedCli) -> Option<CppCompilation> {
+    let cpp_compiler = config.cpp_compiler.as_ref()?;
 
     // -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations
     let mut command = CompilationCommandBuilder::new()
@@ -21,15 +18,12 @@ pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) ->
         command = command.add_arch_flags(vec!["faminmax", "lut", "sha3"]);
     }
 
-    /*
-     * clang++ cannot link an aarch64_be object file, so we invoke
-     * aarch64_be-unknown-linux-gnu's C++ linker. This ensures that we
-     * are testing the intrinsics against LLVM.
-     *
-     * Note: setting `--sysroot=<...>` which is the obvious thing to do
-     * does not work as it gets caught up with `#include_next <stdlib.h>`
-     * not existing...
-     */
+    if !cpp_compiler.contains("clang") {
+        command = command.add_extra_flag("-flax-vector-conversions");
+    }
+
+    let mut cpp_compiler = command.into_cpp_compilation();
+
     if config.target.contains("aarch64_be") {
         let Some(ref cxx_toolchain_dir) = config.cxx_toolchain_dir else {
             panic!(
@@ -38,38 +32,20 @@ pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) ->
             )
         };
 
-        let linker = if let Some(ref linker) = config.linker {
-            linker.to_owned()
-        } else {
-            format!("{cxx_toolchain_dir}/bin/aarch64_be-none-linux-gnu-g++")
-        };
-
-        trace!("using linker: {linker}");
-
-        command = command.set_linker(linker).set_include_paths(vec![
-                "/include",
-                "/aarch64_be-none-linux-gnu/include",
-                "/aarch64_be-none-linux-gnu/include/c++/14.3.1",
-                "/aarch64_be-none-linux-gnu/include/c++/14.3.1/aarch64_be-none-linux-gnu",
-                "/aarch64_be-none-linux-gnu/include/c++/14.3.1/backward",
-                "/aarch64_be-none-linux-gnu/libc/usr/include",
+        cpp_compiler.command_mut().args([
+            &format!("--sysroot={cxx_toolchain_dir}/aarch64_be-none-linux-gnu/libc"),
+            "--include-directory",
+            &format!("{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.3.1"),
+            "--include-directory",
+            &format!("{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.3.1/aarch64_be-none-linux-gnu"),
+            "-L",
+            &format!("{cxx_toolchain_dir}/lib/gcc/aarch64_be-none-linux-gnu/14.3.1"),
+            "-L",
+            &format!("{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/libc/usr/lib"),
+            "-B",
+            &format!("{cxx_toolchain_dir}/lib/gcc/aarch64_be-none-linux-gnu/14.3.1"),
         ]);
     }
 
-    if !cpp_compiler.contains("clang") {
-        command = command.add_extra_flag("-flax-vector-conversions");
-    }
-
-    let compiler_commands = intrinsics_name_list
-        .iter()
-        .map(|intrinsic_name| {
-            command
-                .clone()
-                .set_input_name(intrinsic_name)
-                .set_output_name(intrinsic_name)
-                .make_string()
-        })
-        .collect::<Vec<_>>();
-
-    compile_c_programs(&compiler_commands)
+    Some(cpp_compiler)
 }
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs
index a2535dc6a7a..18530e7e6bd 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs
+++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs
@@ -7,6 +7,7 @@ mod types;
 use crate::common::SupportedArchitectureTest;
 use crate::common::cli::ProcessedCli;
 use crate::common::compare::compare_outputs;
+use crate::common::gen_c::compile_c_programs;
 use crate::common::gen_rust::compile_rust_programs;
 use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition};
 use crate::common::intrinsic_helpers::TypeKind;
@@ -66,7 +67,8 @@ impl SupportedArchitectureTest for ArmArchitectureTest {
             &[POLY128_OSTREAM_DEF],
         );
 
-        compile::compile_c_arm(&self.cli_options, intrinsics_name_list.as_slice())
+        let pipeline = compile::build_cpp_compilation(&self.cli_options).unwrap();
+        compile_c_programs(&pipeline, &intrinsics_name_list)
     }
 
     fn build_rust_file(&self) -> bool {
diff --git a/library/stdarch/crates/intrinsic-test/src/common/compile_c.rs b/library/stdarch/crates/intrinsic-test/src/common/compile_c.rs
index aebb7b111e2..8e2eb8e0f40 100644
--- a/library/stdarch/crates/intrinsic-test/src/common/compile_c.rs
+++ b/library/stdarch/crates/intrinsic-test/src/common/compile_c.rs
@@ -5,11 +5,7 @@ pub struct CompilationCommandBuilder {
     cxx_toolchain_dir: Option<String>,
     arch_flags: Vec<String>,
     optimization: String,
-    include_paths: Vec<String>,
     project_root: Option<String>,
-    output: String,
-    input: String,
-    linker: Option<String>,
     extra_flags: Vec<String>,
 }
 
@@ -21,11 +17,7 @@ impl CompilationCommandBuilder {
             cxx_toolchain_dir: None,
             arch_flags: Vec::new(),
             optimization: "2".to_string(),
-            include_paths: Vec::new(),
             project_root: None,
-            output: String::new(),
-            input: String::new(),
-            linker: None,
             extra_flags: Vec::new(),
         }
     }
@@ -57,37 +49,12 @@ impl CompilationCommandBuilder {
         self
     }
 
-    /// Sets a list of include paths for compilation.
-    /// The paths that are passed must be relative to the
-    /// "cxx_toolchain_dir" directory path.
-    pub fn set_include_paths(mut self, paths: Vec<&str>) -> Self {
-        self.include_paths = paths.into_iter().map(|path| path.to_string()).collect();
-        self
-    }
-
     /// Sets the root path of all the generated test files.
     pub fn set_project_root(mut self, path: &str) -> Self {
         self.project_root = Some(path.to_string());
         self
     }
 
-    /// The name of the output executable, without any suffixes
-    pub fn set_output_name(mut self, path: &str) -> Self {
-        self.output = path.to_string();
-        self
-    }
-
-    /// The name of the input C file, without any suffixes
-    pub fn set_input_name(mut self, path: &str) -> Self {
-        self.input = path.to_string();
-        self
-    }
-
-    pub fn set_linker(mut self, linker: String) -> Self {
-        self.linker = Some(linker);
-        self
-    }
-
     pub fn add_extra_flags(mut self, flags: Vec<&str>) -> Self {
         let mut flags: Vec<String> = flags.into_iter().map(|f| f.to_string()).collect();
         self.extra_flags.append(&mut flags);
@@ -100,55 +67,56 @@ impl CompilationCommandBuilder {
 }
 
 impl CompilationCommandBuilder {
-    pub fn make_string(self) -> String {
-        let arch_flags = self.arch_flags.join("+");
+    pub fn into_cpp_compilation(self) -> CppCompilation {
+        let mut cpp_compiler = std::process::Command::new(self.compiler);
+
+        if let Some(project_root) = self.project_root {
+            cpp_compiler.current_dir(project_root);
+        }
+
         let flags = std::env::var("CPPFLAGS").unwrap_or("".into());
-        let project_root = self.project_root.unwrap_or_default();
-        let project_root_str = project_root.as_str();
-        let mut output = self.output.clone();
-        if self.linker.is_some() {
-            output += ".o"
-        };
-        let mut command = format!(
-            "{} {flags} -march={arch_flags} \
-            -O{} \
-            -o {project_root}/{} \
-            {project_root}/{}.cpp",
-            self.compiler, self.optimization, output, self.input,
-        );
-
-        command = command + " " + self.extra_flags.join(" ").as_str();
+        cpp_compiler.args(flags.split_whitespace());
+
+        cpp_compiler.arg(format!("-march={}", self.arch_flags.join("+")));
+
+        cpp_compiler.arg(format!("-O{}", self.optimization));
+
+        cpp_compiler.args(self.extra_flags);
 
         if let Some(target) = &self.target {
-            command = command + " --target=" + target;
+            cpp_compiler.arg(format!("--target={target}"));
         }
 
-        if let (Some(linker), Some(cxx_toolchain_dir)) = (&self.linker, &self.cxx_toolchain_dir) {
-            let include_args = self
-                .include_paths
-                .iter()
-                .map(|path| "--include-directory=".to_string() + cxx_toolchain_dir + path)
-                .collect::<Vec<_>>()
-                .join(" ");
-
-            command = command
-                + " -c "
-                + include_args.as_str()
-                + " && "
-                + linker
-                + " "
-                + project_root_str
-                + "/"
-                + &output
-                + " -o "
-                + project_root_str
-                + "/"
-                + &self.output
-                + " && rm "
-                + project_root_str
-                + "/"
-                + &output;
-        }
-        command
+        CppCompilation(cpp_compiler)
+    }
+}
+
+pub struct CppCompilation(std::process::Command);
+
+fn clone_command(command: &std::process::Command) -> std::process::Command {
+    let mut cmd = std::process::Command::new(command.get_program());
+    if let Some(current_dir) = command.get_current_dir() {
+        cmd.current_dir(current_dir);
+    }
+    cmd.args(command.get_args());
+
+    for (key, val) in command.get_envs() {
+        cmd.env(key, val.unwrap_or_default());
+    }
+
+    cmd
+}
+
+impl CppCompilation {
+    pub fn command_mut(&mut self) -> &mut std::process::Command {
+        &mut self.0
+    }
+
+    pub fn run(&self, inputs: &[String], output: &str) -> std::io::Result<std::process::Output> {
+        let mut cmd = clone_command(&self.0);
+        cmd.args(inputs);
+        cmd.args(["-o", output]);
+
+        cmd.output()
     }
 }
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..84167f2f4ae 100644
--- a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs
+++ b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs
@@ -1,7 +1,8 @@
 use itertools::Itertools;
 use rayon::prelude::*;
 use std::collections::BTreeMap;
-use std::process::Command;
+
+use crate::common::compile_c::CppCompilation;
 
 use super::argument::Argument;
 use super::indentation::Indentation;
@@ -62,29 +63,30 @@ int main(int argc, char **argv) {{
     )
 }
 
-pub fn compile_c_programs(compiler_commands: &[String]) -> bool {
-    compiler_commands
+pub fn compile_c_programs(pipeline: &CppCompilation, intrinsics: &[String]) -> bool {
+    intrinsics
         .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{}",
+        .map(
+            |intrinsic| match pipeline.run(&[format!("{intrinsic}.cpp")], intrinsic) {
+                Ok(output) if output.status.success() => Ok(()),
+                Ok(output) => {
+                    let msg = format!(
+                        "Failed to compile code for intrinsic `{intrinsic}`: \n\nstdout:\n{}\n\nstderr:\n{}",
                         std::str::from_utf8(&output.stdout).unwrap_or(""),
                         std::str::from_utf8(&output.stderr).unwrap_or("")
                     );
-                    false
+                    error!("{msg}");
+
+                    Err(msg)
                 }
-            } else {
-                error!("Command failed: {output:#?}");
-                false
-            }
-        })
-        .find_any(|x| !x)
-        .is_none()
+                Err(e) => {
+                    error!("command for `{intrinsic}` failed with IO error: {e:?}");
+                    Err(e.to_string())
+                }
+            },
+        )
+        .collect::<Result<(), String>>()
+        .is_ok()
 }
 
 // Creates directory structure and file path mappings