Skip to content

Commit 9f07931

Browse files
committed
intrinsic-test: combine C files for more efficient compilation
1 parent 92e8033 commit 9f07931

File tree

6 files changed

+264
-234
lines changed

6 files changed

+264
-234
lines changed

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

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ mod intrinsic;
44
mod json_parser;
55
mod types;
66

7+
use std::fs::File;
8+
9+
use rayon::prelude::*;
10+
11+
use crate::arm::config::POLY128_OSTREAM_DEF;
712
use crate::common::SupportedArchitectureTest;
813
use crate::common::cli::ProcessedCli;
914
use crate::common::compare::compare_outputs;
10-
use crate::common::gen_c::compile_c_programs;
15+
use crate::common::gen_c::{write_main_cpp, write_mod_cpp};
1116
use crate::common::gen_rust::compile_rust_programs;
1217
use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition};
1318
use crate::common::intrinsic_helpers::TypeKind;
14-
use crate::common::write_file::{write_c_testfiles, write_rust_testfiles};
15-
use config::{AARCH_CONFIGURATIONS, F16_FORMATTING_DEF, POLY128_OSTREAM_DEF, build_notices};
19+
use crate::common::write_file::write_rust_testfiles;
20+
use config::{AARCH_CONFIGURATIONS, F16_FORMATTING_DEF, build_notices};
1621
use intrinsic::ArmIntrinsicType;
1722
use json_parser::get_neon_intrinsics;
1823

@@ -51,24 +56,57 @@ impl SupportedArchitectureTest for ArmArchitectureTest {
5156
}
5257

5358
fn build_c_file(&self) -> bool {
54-
let target = &self.cli_options.target;
5559
let c_target = "aarch64";
60+
let platform_headers = &["arm_neon.h", "arm_acle.h", "arm_fp16.h"];
5661

57-
let intrinsics_name_list = write_c_testfiles(
58-
&self
59-
.intrinsics
60-
.iter()
61-
.map(|i| i as &dyn IntrinsicDefinition<_>)
62-
.collect::<Vec<_>>(),
63-
target,
64-
c_target,
65-
&["arm_neon.h", "arm_acle.h", "arm_fp16.h"],
66-
&build_notices("// "),
67-
&[POLY128_OSTREAM_DEF],
68-
);
62+
let available_parallelism = std::thread::available_parallelism().unwrap().get();
63+
let chunk_size = self.intrinsics.len().div_ceil(available_parallelism);
6964

7065
let pipeline = compile::build_cpp_compilation(&self.cli_options).unwrap();
71-
compile_c_programs(&pipeline, &intrinsics_name_list)
66+
67+
let notice = &build_notices("// ");
68+
self.intrinsics
69+
.par_chunks(chunk_size)
70+
.enumerate()
71+
.map(|(i, chunk)| {
72+
let c_filename = format!("c_programs/mod_{i}.cpp");
73+
let mut file = File::create(&c_filename).unwrap();
74+
write_mod_cpp(&mut file, notice, c_target, platform_headers, chunk).unwrap();
75+
76+
// compile this cpp file into a .o file
77+
let output = pipeline.run(&[], &[format!("mod_{i}.cpp")], &format!("mod_{i}.o"))?;
78+
assert!(output.status.success());
79+
80+
Ok(())
81+
})
82+
.collect::<Result<(), std::io::Error>>()
83+
.unwrap();
84+
85+
let mut file = File::create("c_programs/main.cpp").unwrap();
86+
write_main_cpp(
87+
&mut file,
88+
c_target,
89+
POLY128_OSTREAM_DEF,
90+
self.intrinsics.iter().map(|i| i.name.as_str()),
91+
)
92+
.unwrap();
93+
94+
// Files to include in the final link step.
95+
let mut includes = vec![];
96+
for i in 0..Ord::min(available_parallelism, self.intrinsics.len()) {
97+
includes.push(format!("mod_{i}.o"));
98+
}
99+
100+
let output = pipeline
101+
.run(
102+
&includes,
103+
&["main.cpp".to_string()],
104+
"intrinsic-test-programs",
105+
)
106+
.unwrap();
107+
assert!(output.status.success());
108+
109+
true
72110
}
73111

74112
fn build_rust_file(&self) -> bool {

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

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -125,19 +125,23 @@ where
125125
/// Creates a line for each argument that initializes an array for C from which `loads` argument
126126
/// values can be loaded as a sliding window.
127127
/// e.g `const int32x2_t a_vals = {0x3effffff, 0x3effffff, 0x3f7fffff}`, if loads=2.
128-
pub fn gen_arglists_c(&self, indentation: Indentation, loads: u32) -> String {
129-
self.iter()
130-
.filter(|&arg| !arg.has_constraint())
131-
.map(|arg| {
132-
format!(
133-
"{indentation}const {ty} {name}_vals[] = {values};",
134-
ty = arg.ty.c_scalar_type(),
135-
name = arg.name,
136-
values = arg.ty.populate_random(indentation, loads, &Language::C)
137-
)
138-
})
139-
.collect::<Vec<_>>()
140-
.join("\n")
128+
pub fn gen_arglists_c(
129+
&self,
130+
w: &mut impl std::io::Write,
131+
indentation: Indentation,
132+
loads: u32,
133+
) -> std::io::Result<()> {
134+
for arg in self.iter().filter(|&arg| !arg.has_constraint()) {
135+
writeln!(
136+
w,
137+
"{indentation}const {ty} {name}_vals[] = {values};",
138+
ty = arg.ty.c_scalar_type(),
139+
name = arg.name,
140+
values = arg.ty.populate_random(indentation, loads, &Language::C)
141+
)?
142+
}
143+
144+
Ok(())
141145
}
142146

143147
/// Creates a line for each argument that initializes an array for Rust from which `loads` argument

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub fn compare_outputs(
1313
.filter_map(|intrinsic_name| {
1414
let c = Command::new("sh")
1515
.arg("-c")
16-
.arg(format!("{runner} ./c_programs/{intrinsic_name}"))
16+
.arg(format!("{runner} ./c_programs/intrinsic-test-programs {intrinsic_name}"))
1717
.output();
1818

1919
let rust = Command::new("sh")

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

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,35 @@ fn clone_command(command: &std::process::Command) -> std::process::Command {
144144
}
145145

146146
impl CppCompilation {
147-
pub fn run(&self, inputs: &[String], output: &str) -> std::io::Result<std::process::Output> {
148-
match self {
149-
CppCompilation::Simple(command) => {
150-
let mut cmd = clone_command(command);
151-
cmd.args(inputs);
152-
cmd.args(["-o", output]);
147+
fn compile_cpp(
148+
command: &std::process::Command,
149+
includes: &[String],
150+
inputs: &[String],
151+
output: &str,
152+
) -> std::io::Result<std::process::Output> {
153+
let mut cmd = clone_command(command);
154+
cmd.args(includes);
155+
cmd.args(inputs);
156+
cmd.args(["-o", output]);
157+
158+
if output.ends_with(".o") {
159+
cmd.arg("-c");
160+
}
153161

154-
cmd.output()
162+
cmd.output()
163+
}
164+
165+
pub fn run(
166+
&self,
167+
includes: &[String],
168+
inputs: &[String],
169+
output: &str,
170+
) -> std::io::Result<std::process::Output> {
171+
match self {
172+
CppCompilation::Simple(command) => Self::compile_cpp(command, includes, inputs, output),
173+
CppCompilation::CustomLinker { cpp_compiler, .. } if output.ends_with(".o") => {
174+
// No need to invoke that custom linker if we're creating an object file.
175+
Self::compile_cpp(cpp_compiler, includes, inputs, output)
155176
}
156177
CppCompilation::CustomLinker {
157178
cpp_compiler,
@@ -174,6 +195,7 @@ impl CppCompilation {
174195

175196
// Use the custom linker to turn the object file into an executable.
176197
let mut cmd = std::process::Command::new(linker);
198+
cmd.args(includes);
177199
cmd.args([object_file, "-o", output]);
178200

179201
if let Some(current_dir) = cpp_compiler.get_current_dir() {

0 commit comments

Comments
 (0)