Skip to content

Commit c45dc7d

Browse files
committed
wire up writer for C file writes
1 parent 65598e9 commit c45dc7d

File tree

3 files changed

+110
-133
lines changed

3 files changed

+110
-133
lines changed

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
Lines changed: 90 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use itertools::Itertools;
21
use rayon::prelude::*;
32
use std::process::Command;
43

@@ -10,57 +9,6 @@ use super::intrinsic_helpers::IntrinsicTypeDefinition;
109
// The number of times each intrinsic will be called.
1110
const PASSES: u32 = 20;
1211

13-
// Formats the main C program template with placeholders
14-
pub fn format_c_main_template(
15-
notices: &str,
16-
header_files: &[&str],
17-
arch_identifier: &str,
18-
arch_specific_definitions: &[&str],
19-
arglists: &str,
20-
passes: &str,
21-
) -> String {
22-
format!(
23-
r#"{notices}{header_files}
24-
#include <iostream>
25-
#include <cstring>
26-
#include <iomanip>
27-
#include <sstream>
28-
29-
template<typename T1, typename T2> T1 cast(T2 x) {{
30-
static_assert(sizeof(T1) == sizeof(T2), "sizeof T1 and T2 must be the same");
31-
T1 ret{{}};
32-
memcpy(&ret, &x, sizeof(T1));
33-
return ret;
34-
}}
35-
36-
std::ostream& operator<<(std::ostream& os, float16_t value) {{
37-
uint16_t temp = 0;
38-
memcpy(&temp, &value, sizeof(float16_t));
39-
std::stringstream ss;
40-
ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << temp;
41-
os << ss.str();
42-
return os;
43-
}}
44-
45-
#ifdef __{arch_identifier}__
46-
{arch_specific_definitions}
47-
#endif
48-
49-
{arglists}
50-
51-
int main(int argc, char **argv) {{
52-
{passes}
53-
return 0;
54-
}}"#,
55-
header_files = header_files
56-
.iter()
57-
.map(|header| format!("#include <{header}>"))
58-
.collect::<Vec<_>>()
59-
.join("\n"),
60-
arch_specific_definitions = arch_specific_definitions.join("\n"),
61-
)
62-
}
63-
6412
pub fn compile_c_programs(compiler_commands: &[String]) -> bool {
6513
compiler_commands
6614
.par_iter()
@@ -87,14 +35,15 @@ pub fn compile_c_programs(compiler_commands: &[String]) -> bool {
8735
}
8836

8937
pub fn generate_c_test_loop<T: IntrinsicTypeDefinition + Sized>(
38+
w: &mut impl std::io::Write,
9039
intrinsic: &dyn IntrinsicDefinition<T>,
9140
indentation: Indentation,
9241
additional: &str,
9342
passes: u32,
94-
_target: &str,
95-
) -> String {
43+
) -> std::io::Result<()> {
9644
let body_indentation = indentation.nested();
97-
format!(
45+
write!(
46+
w,
9847
"{indentation}for (int i=0; i<{passes}; i++) {{\n\
9948
{loaded_args}\
10049
{body_indentation}auto __return_value = {intrinsic_call}({args});\n\
@@ -107,78 +56,105 @@ pub fn generate_c_test_loop<T: IntrinsicTypeDefinition + Sized>(
10756
)
10857
}
10958

110-
pub fn generate_c_constraint_blocks<T: IntrinsicTypeDefinition>(
59+
pub fn generate_c_constraint_blocks<'a, T: IntrinsicTypeDefinition + 'a>(
60+
w: &mut impl std::io::Write,
11161
intrinsic: &dyn IntrinsicDefinition<T>,
11262
indentation: Indentation,
113-
constraints: &[&Argument<T>],
63+
constraints: &mut (impl Iterator<Item = &'a Argument<T>> + Clone),
11464
name: String,
115-
target: &str,
116-
) -> String {
117-
if let Some((current, constraints)) = constraints.split_last() {
118-
let range = current
119-
.constraint
120-
.iter()
121-
.map(|c| c.to_range())
122-
.flat_map(|r| r.into_iter());
123-
124-
let body_indentation = indentation.nested();
125-
range
126-
.map(|i| {
127-
format!(
128-
"{indentation}{{\n\
129-
{body_indentation}{ty} {name} = {val};\n\
130-
{pass}\n\
131-
{indentation}}}",
132-
name = current.name,
133-
ty = current.ty.c_type(),
134-
val = i,
135-
pass = generate_c_constraint_blocks(
136-
intrinsic,
137-
body_indentation,
138-
constraints,
139-
format!("{name}-{i}"),
140-
target,
141-
)
142-
)
143-
})
144-
.join("\n")
145-
} else {
146-
generate_c_test_loop(intrinsic, indentation, &name, PASSES, target)
65+
) -> std::io::Result<()> {
66+
let Some(current) = constraints.next() else {
67+
return generate_c_test_loop(w, intrinsic, indentation, &name, PASSES);
68+
};
69+
70+
let body_indentation = indentation.nested();
71+
for i in current.constraint.iter().flat_map(|c| c.to_range()) {
72+
let ty = current.ty.c_type();
73+
74+
writeln!(w, "{indentation}{{")?;
75+
writeln!(w, "{body_indentation}{ty} {} = {i};", current.name)?;
76+
77+
generate_c_constraint_blocks(
78+
w,
79+
intrinsic,
80+
body_indentation,
81+
&mut constraints.clone(),
82+
format!("{name}-{i}"),
83+
)?;
84+
85+
writeln!(w, "{indentation}}}")?;
14786
}
87+
88+
Ok(())
14889
}
14990

15091
// Compiles C test programs using specified compiler
15192
pub fn create_c_test_program<T: IntrinsicTypeDefinition>(
93+
w: &mut impl std::io::Write,
15294
intrinsic: &dyn IntrinsicDefinition<T>,
15395
header_files: &[&str],
154-
target: &str,
96+
_target: &str,
15597
c_target: &str,
15698
notices: &str,
15799
arch_specific_definitions: &[&str],
158-
) -> String {
100+
) -> std::io::Result<()> {
101+
let indentation = Indentation::default();
102+
103+
write!(w, "{notices}")?;
104+
105+
for header in header_files {
106+
writeln!(w, "#include <{header}>")?;
107+
}
108+
109+
writeln!(
110+
w,
111+
r#"
112+
#include <iostream>
113+
#include <cstring>
114+
#include <iomanip>
115+
#include <sstream>
116+
117+
template<typename T1, typename T2> T1 cast(T2 x) {{
118+
static_assert(sizeof(T1) == sizeof(T2), "sizeof T1 and T2 must be the same");
119+
T1 ret{{}};
120+
memcpy(&ret, &x, sizeof(T1));
121+
return ret;
122+
}}
123+
124+
std::ostream& operator<<(std::ostream& os, float16_t value) {{
125+
uint16_t temp = 0;
126+
memcpy(&temp, &value, sizeof(float16_t));
127+
std::stringstream ss;
128+
ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << temp;
129+
os << ss.str();
130+
return os;
131+
}}
132+
"#
133+
)?;
134+
135+
let arch_identifier = c_target;
136+
writeln!(w, "#ifdef __{arch_identifier}__")?;
137+
for def in arch_specific_definitions {
138+
writeln!(w, "{def}")?;
139+
}
140+
writeln!(w, "#endif")?;
141+
142+
// Define the arrays of arguments.
159143
let arguments = intrinsic.arguments();
160-
let constraints = arguments
161-
.iter()
162-
.filter(|&i| i.has_constraint())
163-
.collect_vec();
144+
arguments.gen_arglists_c(w, indentation, PASSES)?;
164145

165-
let indentation = Indentation::default();
166-
format_c_main_template(
167-
notices,
168-
header_files,
169-
c_target,
170-
arch_specific_definitions,
171-
intrinsic
172-
.arguments()
173-
.gen_arglists_c(indentation, PASSES)
174-
.as_str(),
175-
generate_c_constraint_blocks(
176-
intrinsic,
177-
indentation.nested(),
178-
constraints.as_slice(),
179-
Default::default(),
180-
target,
181-
)
182-
.as_str(),
183-
)
146+
writeln!(w, "int main(int argc, char **argv) {{")?;
147+
148+
generate_c_constraint_blocks(
149+
w,
150+
intrinsic,
151+
indentation.nested(),
152+
&mut arguments.iter().rev().filter(|&i| i.has_constraint()),
153+
Default::default(),
154+
)?;
155+
156+
writeln!(w, " return 0;")?;
157+
writeln!(w, "}}")?;
158+
159+
Ok(())
184160
}

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::fs::File;
2-
use std::io::Write;
32

43
use super::gen_rust::create_rust_test_program;
54
use super::intrinsic::IntrinsicDefinition;
@@ -24,17 +23,15 @@ where
2423
let identifier = intrinsic.name().to_owned();
2524
let mut file = File::create(format!("c_programs/{identifier}.cpp")).unwrap();
2625

27-
// write_c_test_program(&mut file, intrinsic)?;
28-
let c_code = crate::common::gen_c::create_c_test_program(
26+
crate::common::gen_c::create_c_test_program(
27+
&mut file,
2928
intrinsic,
3029
headers,
3130
target,
3231
c_target,
3332
notice,
3433
arch_specific_definitions,
35-
);
36-
37-
file.write_all(c_code.as_bytes())?;
34+
)?;
3835

3936
Ok(identifier)
4037
})

0 commit comments

Comments
 (0)