Skip to content

Commit 447d570

Browse files
moved the C compilation commands into a struct for easier handling
1 parent d395e9c commit 447d570

File tree

3 files changed

+167
-49
lines changed

3 files changed

+167
-49
lines changed

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

Lines changed: 30 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::config::{AARCH_CONFIGURATIONS, POLY128_OSTREAM_DEF, build_notices};
22
use super::intrinsic::ArmIntrinsicType;
33
use crate::arm::constraint::Constraint;
44
use crate::common::argument::Argument;
5+
use crate::common::compile_c::CompilationCommandBuilder;
56
use crate::common::format::Indentation;
67
use crate::common::gen_c::{compile_c, create_c_filenames, generate_c_program};
78
use crate::common::gen_rust::{compile_rust, create_rust_filenames, generate_rust_program};
@@ -161,70 +162,50 @@ fn generate_rust_program_arm(
161162

162163
fn compile_c_arm(
163164
intrinsics_name_list: &Vec<String>,
164-
filename_mapping: BTreeMap<&String, String>,
165+
_filename_mapping: BTreeMap<&String, String>,
165166
compiler: &str,
166167
target: &str,
167168
cxx_toolchain_dir: Option<&str>,
168169
) -> bool {
169170
let compiler_commands = intrinsics_name_list.iter().map(|intrinsic_name| {
170-
let c_filename = filename_mapping.get(intrinsic_name).unwrap();
171-
let flags = std::env::var("CPPFLAGS").unwrap_or("".into());
172-
let arch_flags = if target.contains("v7") {
173-
"-march=armv8.6-a+crypto+crc+dotprod+fp16"
171+
let mut command = CompilationCommandBuilder::new();
172+
if target.contains("v7") {
173+
command.set_arch_flags(vec!["armv8.6-a", "crypto", "crc", "dotprod", "fp16"])
174174
} else {
175-
"-march=armv8.6-a+crypto+sha3+crc+dotprod+fp16+faminmax+lut"
175+
command.set_arch_flags(vec!["armv8.6-a", "crypto", "crc", "dotprod", "fp16", "sha3", "faminmax", "lut"])
176176
};
177177

178-
let compiler_command = if target == "aarch64_be-unknown-linux-gnu" {
179-
let Some(cxx_toolchain_dir) = cxx_toolchain_dir else {
180-
panic!(
181-
"When setting `--target aarch64_be-unknown-linux-gnu` the C++ compilers toolchain directory must be set with `--cxx-toolchain-dir <dest>`"
182-
);
183-
};
178+
command = command
179+
.set_compiler(compiler)
180+
.set_output_name(intrinsic_name)
181+
.set_target(target)
182+
.set_opt_level("2")
183+
.set_cxx_toolchain_dir(cxx_toolchain_dir)
184+
.set_project_root("c_programs")
185+
.set_input_name(intrinsic_name)
186+
.add_extra_flags(vec!["-ffp-contract=off", "-Wno-narrowing"]);
184187

185-
/* clang++ cannot link an aarch64_be object file, so we invoke
186-
* aarch64_be-unknown-linux-gnu's C++ linker. This ensures that we
187-
* are testing the intrinsics against LLVM.
188-
*
189-
* Note: setting `--sysroot=<...>` which is the obvious thing to do
190-
* does not work as it gets caught up with `#include_next <stdlib.h>`
191-
* not existing... */
192-
format!(
193-
"{compiler} {flags} {arch_flags} \
194-
-ffp-contract=off \
195-
-Wno-narrowing \
196-
-O2 \
197-
--target=aarch64_be-unknown-linux-gnu \
198-
-I{cxx_toolchain_dir}/include \
199-
-I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include \
200-
-I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1 \
201-
-I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1/aarch64_be-none-linux-gnu \
202-
-I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/include/c++/14.2.1/backward \
203-
-I{cxx_toolchain_dir}/aarch64_be-none-linux-gnu/libc/usr/include \
204-
-c {c_filename} \
205-
-o c_programs/{intrinsic_name}.o && \
206-
{cxx_toolchain_dir}/bin/aarch64_be-none-linux-gnu-g++ c_programs/{intrinsic_name}.o -o c_programs/{intrinsic_name} && \
207-
rm c_programs/{intrinsic_name}.o",
208-
)
188+
command = if target == "aarch64_be-unknown-linux-gnu" {
189+
command
190+
.set_linker(cxx_toolchain_dir.unwrap_or("").to_string() + "/bin/aarch64_be-none-linux-gnu-g++")
191+
.set_include_paths(vec![
192+
"/include",
193+
"/aarch64_be-none-linux-gnu/include",
194+
"/aarch64_be-none-linux-gnu/include/c++/14.2.1",
195+
"/aarch64_be-none-linux-gnu/include/c++/14.2.1/aarch64_be-none-linux-gnu",
196+
"/aarch64_be-none-linux-gnu/include/c++/14.2.1/backward",
197+
"/aarch64_be-none-linux-gnu/libc/usr/include"
198+
])
209199
} else {
210-
// -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations
211-
let base_compiler_command = format!(
212-
"{compiler} {flags} {arch_flags} -o c_programs/{intrinsic_name} {c_filename} -ffp-contract=off -Wno-narrowing -O2"
213-
);
214-
215-
/* `-target` can be passed to some c++ compilers, however if we want to
216-
* use a c++ compiler does not support this flag we do not want to pass
217-
* the flag. */
218200
if compiler.contains("clang") {
219-
format!("{base_compiler_command} -target {target}")
201+
command.add_extra_flag(format!("-target {target}").as_str())
220202
} else {
221-
format!("{base_compiler_command} -flax-vector-conversions")
203+
command.add_extra_flag("-flax-vector-conversions")
222204
}
223205
};
224206

225-
compiler_command
226-
})
227-
.collect::<Vec<_>>();
207+
command.as_str()
208+
}).collect::<Vec<_>>();
228209

229210
compile_c(&compiler_commands)
230211
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
pub struct CompilationCommandBuilder {
2+
compiler: String,
3+
target: Option<String>,
4+
cxx_toolchain_dir: Option<String>,
5+
arch_flags: Vec<String>,
6+
optimization: String,
7+
include_paths: Vec<String>,
8+
project_root: Option<String>,
9+
output: String,
10+
input: String,
11+
linker: Option<String>,
12+
extra_flags: Vec<String>,
13+
}
14+
15+
impl CompilationCommandBuilder {
16+
pub fn new() -> Self {
17+
Self {
18+
compiler: String::new(),
19+
target: None,
20+
cxx_toolchain_dir: None,
21+
arch_flags: Vec::new(),
22+
optimization: "2".to_string(),
23+
include_paths: Vec::new(),
24+
project_root: None,
25+
output: String::new(),
26+
input: String::new(),
27+
linker: None,
28+
extra_flags: Vec::new(),
29+
}
30+
}
31+
32+
pub fn set_compiler(mut self, compiler: &str) -> Self {
33+
self.compiler = compiler.to_string();
34+
self
35+
}
36+
37+
pub fn set_target(mut self, target: &str) -> Self {
38+
self.target = Some(target.to_string());
39+
self
40+
}
41+
42+
pub fn set_cxx_toolchain_dir(mut self, path: Option<&str>) -> Self {
43+
self.cxx_toolchain_dir = path.map(|p| p.to_string());
44+
self
45+
}
46+
47+
pub fn set_arch_flags(&mut self, flags: Vec<&str>) {
48+
self.arch_flags = flags.iter().map(|v| v.to_string()).collect();
49+
}
50+
51+
pub fn set_opt_level(mut self, optimization: &str) -> Self {
52+
self.optimization = optimization.to_string();
53+
self
54+
}
55+
56+
pub fn set_include_paths(mut self, paths: Vec<&str>) -> Self {
57+
self.include_paths = paths
58+
.into_iter()
59+
.map(|path| path.to_string())
60+
.collect();
61+
self
62+
}
63+
64+
pub fn set_project_root(mut self, path: &str) -> Self {
65+
self.project_root = Some(path.to_string());
66+
self
67+
}
68+
69+
pub fn set_output_name(mut self, path: &str) -> Self {
70+
self.output = path.to_string();
71+
self
72+
}
73+
74+
pub fn set_input_name(mut self, path: &str) -> Self {
75+
self.input = path.to_string();
76+
self
77+
}
78+
79+
pub fn set_linker(mut self, linker: String) -> Self {
80+
self.linker = Some(linker);
81+
self.output += ".o";
82+
self
83+
}
84+
85+
pub fn add_extra_flags(mut self, flags: Vec<&str>) -> Self {
86+
let mut flags: Vec<String> = flags.into_iter().map(|f| f.to_string()).collect();
87+
self.extra_flags.append(&mut flags);
88+
self
89+
}
90+
91+
pub fn add_extra_flag(self, flag: &str) -> Self {
92+
self.add_extra_flags(vec![flag])
93+
}
94+
}
95+
96+
impl CompilationCommandBuilder {
97+
pub fn as_str(self) -> String {
98+
let arch_flags = self.arch_flags.join("+");
99+
let flags = std::env::var("CPPFLAGS").unwrap_or("".into());
100+
let project_root = self.project_root.unwrap_or(String::new());
101+
let project_root_str = project_root.as_str();
102+
let mut command = format!(
103+
"{} {flags} -march={arch_flags} \
104+
-O{} \
105+
-o {project_root}/{} \
106+
{project_root}/{}.cpp",
107+
self.compiler,
108+
self.optimization,
109+
self.output,
110+
self.input,
111+
);
112+
113+
command = command
114+
+ " " + self.extra_flags.join(" ").as_str();
115+
116+
if let (Some(linker), Some(cxx_toolchain_dir)) = (&self.linker, &self.cxx_toolchain_dir) {
117+
if let Some(target) = &self.target {
118+
command = command + " --target=" + target;
119+
}
120+
121+
let include_args = self.include_paths
122+
.iter()
123+
.map(|path| "--include-directory=".to_string() + cxx_toolchain_dir + path)
124+
.collect::<Vec<_>>()
125+
.join(" ");
126+
127+
command = command + " -c "
128+
+ " " + include_args.as_str()
129+
+ "&& " + linker + project_root_str + "/" + self.output.as_str()
130+
+ " -o " + project_root_str + "/" + self.output.strip_suffix(".o").unwrap()
131+
+ " && " + "rm " + project_root_str + "/" + self.output.as_str();
132+
}
133+
134+
command
135+
}
136+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::io::Write;
44

55
pub mod argument;
66
pub mod compare;
7+
pub mod compile_c;
78
pub mod format;
89
pub mod gen_c;
910
pub mod gen_rust;

0 commit comments

Comments
 (0)