Skip to content

Commit ff7559f

Browse files
committed
improve cpp compiler execution
1 parent 48f6c7e commit ff7559f

File tree

4 files changed

+92
-144
lines changed

4 files changed

+92
-144
lines changed
Lines changed: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
use crate::common::cli::ProcessedCli;
2-
use crate::common::compile_c::CompilationCommandBuilder;
3-
use crate::common::gen_c::compile_c_programs;
2+
use crate::common::compile_c::{CompilationCommandBuilder, CppCompilation};
43

5-
pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) -> bool {
6-
let Some(ref cpp_compiler) = config.cpp_compiler else {
7-
return true;
8-
};
4+
pub fn build_cpp_compilation(config: &ProcessedCli) -> Option<CppCompilation> {
5+
let cpp_compiler = config.cpp_compiler.as_ref()?;
96

107
// -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations
118
let mut command = CompilationCommandBuilder::new()
@@ -21,15 +18,12 @@ pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) ->
2118
command = command.add_arch_flags(vec!["faminmax", "lut", "sha3"]);
2219
}
2320

24-
/*
25-
* clang++ cannot link an aarch64_be object file, so we invoke
26-
* aarch64_be-unknown-linux-gnu's C++ linker. This ensures that we
27-
* are testing the intrinsics against LLVM.
28-
*
29-
* Note: setting `--sysroot=<...>` which is the obvious thing to do
30-
* does not work as it gets caught up with `#include_next <stdlib.h>`
31-
* not existing...
32-
*/
21+
if !cpp_compiler.contains("clang") {
22+
command = command.add_extra_flag("-flax-vector-conversions");
23+
}
24+
25+
let mut cpp_compiler = command.into_cpp_compilation();
26+
3327
if config.target.contains("aarch64_be") {
3428
let Some(ref cxx_toolchain_dir) = config.cxx_toolchain_dir else {
3529
panic!(
@@ -38,38 +32,20 @@ pub fn compile_c_arm(config: &ProcessedCli, intrinsics_name_list: &[String]) ->
3832
)
3933
};
4034

41-
let linker = if let Some(ref linker) = config.linker {
42-
linker.to_owned()
43-
} else {
44-
format!("{cxx_toolchain_dir}/bin/aarch64_be-none-linux-gnu-g++")
45-
};
46-
47-
trace!("using linker: {linker}");
48-
49-
command = command.set_linker(linker).set_include_paths(vec![
50-
"/include",
51-
"/aarch64_be-none-linux-gnu/include",
52-
"/aarch64_be-none-linux-gnu/include/c++/14.2.1",
53-
"/aarch64_be-none-linux-gnu/include/c++/14.2.1/aarch64_be-none-linux-gnu",
54-
"/aarch64_be-none-linux-gnu/include/c++/14.2.1/backward",
55-
"/aarch64_be-none-linux-gnu/libc/usr/include",
35+
cpp_compiler.command_mut().args([
36+
&format!("--sysroot={cxx_toolchain_dir}/aarch64_be-none-linux-gnu/libc"),
37+
"--include-directory",
38+
&format!("{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1"),
39+
"--include-directory",
40+
&format!("{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1/aarch64_be-none-linux-gnu"),
41+
"-L",
42+
&format!("{cxx_toolchain_dir}/lib/gcc/aarch64_be-none-linux-gnu/14.2.1"),
43+
"-L",
44+
&format!("{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/libc/usr/lib"),
45+
"-B",
46+
&format!("{cxx_toolchain_dir}/lib/gcc/aarch64_be-none-linux-gnu/14.2.1"),
5647
]);
5748
}
5849

59-
if !cpp_compiler.contains("clang") {
60-
command = command.add_extra_flag("-flax-vector-conversions");
61-
}
62-
63-
let compiler_commands = intrinsics_name_list
64-
.iter()
65-
.map(|intrinsic_name| {
66-
command
67-
.clone()
68-
.set_input_name(intrinsic_name)
69-
.set_output_name(intrinsic_name)
70-
.make_string()
71-
})
72-
.collect::<Vec<_>>();
73-
74-
compile_c_programs(&compiler_commands)
50+
Some(cpp_compiler)
7551
}

crates/intrinsic-test/src/arm/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod types;
77
use crate::common::SupportedArchitectureTest;
88
use crate::common::cli::ProcessedCli;
99
use crate::common::compare::compare_outputs;
10+
use crate::common::gen_c::compile_c_programs;
1011
use crate::common::gen_rust::compile_rust_programs;
1112
use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition};
1213
use crate::common::intrinsic_helpers::TypeKind;
@@ -66,7 +67,8 @@ impl SupportedArchitectureTest for ArmArchitectureTest {
6667
&[POLY128_OSTREAM_DEF],
6768
);
6869

69-
compile::compile_c_arm(&self.cli_options, intrinsics_name_list.as_slice())
70+
let pipeline = compile::build_cpp_compilation(&self.cli_options).unwrap();
71+
compile_c_programs(&pipeline, &intrinsics_name_list)
7072
}
7173

7274
fn build_rust_file(&self) -> bool {

crates/intrinsic-test/src/common/compile_c.rs

Lines changed: 46 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,7 @@ pub struct CompilationCommandBuilder {
55
cxx_toolchain_dir: Option<String>,
66
arch_flags: Vec<String>,
77
optimization: String,
8-
include_paths: Vec<String>,
98
project_root: Option<String>,
10-
output: String,
11-
input: String,
12-
linker: Option<String>,
139
extra_flags: Vec<String>,
1410
}
1511

@@ -21,11 +17,7 @@ impl CompilationCommandBuilder {
2117
cxx_toolchain_dir: None,
2218
arch_flags: Vec::new(),
2319
optimization: "2".to_string(),
24-
include_paths: Vec::new(),
2520
project_root: None,
26-
output: String::new(),
27-
input: String::new(),
28-
linker: None,
2921
extra_flags: Vec::new(),
3022
}
3123
}
@@ -57,37 +49,12 @@ impl CompilationCommandBuilder {
5749
self
5850
}
5951

60-
/// Sets a list of include paths for compilation.
61-
/// The paths that are passed must be relative to the
62-
/// "cxx_toolchain_dir" directory path.
63-
pub fn set_include_paths(mut self, paths: Vec<&str>) -> Self {
64-
self.include_paths = paths.into_iter().map(|path| path.to_string()).collect();
65-
self
66-
}
67-
6852
/// Sets the root path of all the generated test files.
6953
pub fn set_project_root(mut self, path: &str) -> Self {
7054
self.project_root = Some(path.to_string());
7155
self
7256
}
7357

74-
/// The name of the output executable, without any suffixes
75-
pub fn set_output_name(mut self, path: &str) -> Self {
76-
self.output = path.to_string();
77-
self
78-
}
79-
80-
/// The name of the input C file, without any suffixes
81-
pub fn set_input_name(mut self, path: &str) -> Self {
82-
self.input = path.to_string();
83-
self
84-
}
85-
86-
pub fn set_linker(mut self, linker: String) -> Self {
87-
self.linker = Some(linker);
88-
self
89-
}
90-
9158
pub fn add_extra_flags(mut self, flags: Vec<&str>) -> Self {
9259
let mut flags: Vec<String> = flags.into_iter().map(|f| f.to_string()).collect();
9360
self.extra_flags.append(&mut flags);
@@ -100,55 +67,56 @@ impl CompilationCommandBuilder {
10067
}
10168

10269
impl CompilationCommandBuilder {
103-
pub fn make_string(self) -> String {
104-
let arch_flags = self.arch_flags.join("+");
70+
pub fn into_cpp_compilation(self) -> CppCompilation {
71+
let mut cpp_compiler = std::process::Command::new(self.compiler);
72+
73+
if let Some(project_root) = self.project_root {
74+
cpp_compiler.current_dir(project_root);
75+
}
76+
10577
let flags = std::env::var("CPPFLAGS").unwrap_or("".into());
106-
let project_root = self.project_root.unwrap_or_default();
107-
let project_root_str = project_root.as_str();
108-
let mut output = self.output.clone();
109-
if self.linker.is_some() {
110-
output += ".o"
111-
};
112-
let mut command = format!(
113-
"{} {flags} -march={arch_flags} \
114-
-O{} \
115-
-o {project_root}/{} \
116-
{project_root}/{}.cpp",
117-
self.compiler, self.optimization, output, self.input,
118-
);
119-
120-
command = command + " " + self.extra_flags.join(" ").as_str();
78+
cpp_compiler.args(flags.split_whitespace());
79+
80+
cpp_compiler.arg(format!("-march={}", self.arch_flags.join("+")));
81+
82+
cpp_compiler.arg(format!("-O{}", self.optimization));
83+
84+
cpp_compiler.args(self.extra_flags);
12185

12286
if let Some(target) = &self.target {
123-
command = command + " --target=" + target;
87+
cpp_compiler.arg(format!("--target={target}"));
12488
}
12589

126-
if let (Some(linker), Some(cxx_toolchain_dir)) = (&self.linker, &self.cxx_toolchain_dir) {
127-
let include_args = self
128-
.include_paths
129-
.iter()
130-
.map(|path| "--include-directory=".to_string() + cxx_toolchain_dir + path)
131-
.collect::<Vec<_>>()
132-
.join(" ");
133-
134-
command = command
135-
+ " -c "
136-
+ include_args.as_str()
137-
+ " && "
138-
+ linker
139-
+ " "
140-
+ project_root_str
141-
+ "/"
142-
+ &output
143-
+ " -o "
144-
+ project_root_str
145-
+ "/"
146-
+ &self.output
147-
+ " && rm "
148-
+ project_root_str
149-
+ "/"
150-
+ &output;
151-
}
152-
command
90+
CppCompilation(cpp_compiler)
91+
}
92+
}
93+
94+
pub struct CppCompilation(std::process::Command);
95+
96+
fn clone_command(command: &std::process::Command) -> std::process::Command {
97+
let mut cmd = std::process::Command::new(command.get_program());
98+
if let Some(current_dir) = command.get_current_dir() {
99+
cmd.current_dir(current_dir);
100+
}
101+
cmd.args(command.get_args());
102+
103+
for (key, val) in command.get_envs() {
104+
cmd.env(key, val.unwrap_or_default());
105+
}
106+
107+
cmd
108+
}
109+
110+
impl CppCompilation {
111+
pub fn command_mut(&mut self) -> &mut std::process::Command {
112+
&mut self.0
113+
}
114+
115+
pub fn run(&self, inputs: &[String], output: &str) -> std::io::Result<std::process::Output> {
116+
let mut cmd = clone_command(&self.0);
117+
cmd.args(inputs);
118+
cmd.args(["-o", output]);
119+
120+
cmd.output()
153121
}
154122
}

crates/intrinsic-test/src/common/gen_c.rs

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use itertools::Itertools;
22
use rayon::prelude::*;
33
use std::collections::BTreeMap;
4-
use std::process::Command;
4+
5+
use crate::common::compile_c::CppCompilation;
56

67
use super::argument::Argument;
78
use super::indentation::Indentation;
@@ -62,29 +63,30 @@ int main(int argc, char **argv) {{
6263
)
6364
}
6465

65-
pub fn compile_c_programs(compiler_commands: &[String]) -> bool {
66-
compiler_commands
66+
pub fn compile_c_programs(pipeline: &CppCompilation, intrinsics: &[String]) -> bool {
67+
intrinsics
6768
.par_iter()
68-
.map(|compiler_command| {
69-
let output = Command::new("sh").arg("-c").arg(compiler_command).output();
70-
if let Ok(output) = output {
71-
if output.status.success() {
72-
true
73-
} else {
74-
error!(
75-
"Failed to compile code for intrinsics: \n\nstdout:\n{}\n\nstderr:\n{}",
69+
.map(
70+
|intrinsic| match pipeline.run(&[format!("{intrinsic}.cpp")], intrinsic) {
71+
Ok(output) if output.status.success() => Ok(()),
72+
Ok(output) => {
73+
let msg = format!(
74+
"Failed to compile code for intrinsic `{intrinsic}`: \n\nstdout:\n{}\n\nstderr:\n{}",
7675
std::str::from_utf8(&output.stdout).unwrap_or(""),
7776
std::str::from_utf8(&output.stderr).unwrap_or("")
7877
);
79-
false
78+
error!("{msg}");
79+
80+
Err(msg)
8081
}
81-
} else {
82-
error!("Command failed: {output:#?}");
83-
false
84-
}
85-
})
86-
.find_any(|x| !x)
87-
.is_none()
82+
Err(e) => {
83+
error!("command for `{intrinsic}` failed with IO error: {e:?}");
84+
Err(e.to_string())
85+
}
86+
},
87+
)
88+
.collect::<Result<(), String>>()
89+
.is_ok()
8890
}
8991

9092
// Creates directory structure and file path mappings

0 commit comments

Comments
 (0)