Skip to content

Commit cbd8273

Browse files
committed
generate arrays of type-erased function pointers
i.e. don't duplicate blocks with loop logic. This compiles quite a bit faster, I think mostly because it's just less code
1 parent bb9d602 commit cbd8273

File tree

4 files changed

+73
-83
lines changed

4 files changed

+73
-83
lines changed

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

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,6 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType {
3333
}
3434
}
3535

36-
fn rust_type(&self) -> String {
37-
let rust_prefix = self.0.kind.rust_prefix();
38-
let c_prefix = self.0.kind.c_prefix();
39-
if self.0.ptr_constant {
40-
self.c_type()
41-
} else if let (Some(bit_len), simd_len, vec_len) =
42-
(self.0.bit_len, self.0.simd_len, self.0.vec_len)
43-
{
44-
match (simd_len, vec_len) {
45-
(None, None) => format!("{rust_prefix}{bit_len}"),
46-
(Some(simd), None) => format!("{c_prefix}{bit_len}x{simd}_t"),
47-
(Some(simd), Some(vec)) => format!("{c_prefix}{bit_len}x{simd}x{vec}_t"),
48-
(None, Some(_)) => todo!("{:#?}", self), // Likely an invalid case
49-
}
50-
} else {
51-
todo!("{:#?}", self)
52-
}
53-
}
54-
5536
/// Determines the load function for this type.
5637
fn get_load_function(&self, language: Language) -> String {
5738
if let IntrinsicType {

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,6 @@ where
114114
.join(", ")
115115
}
116116

117-
pub fn as_constraint_parameters_rust(&self) -> String {
118-
self.iter()
119-
.filter(|a| a.has_constraint())
120-
.map(|arg| arg.name.clone())
121-
.collect::<Vec<String>>()
122-
.join(", ")
123-
}
124-
125117
/// Creates a line for each argument that initializes an array for C from which `loads` argument
126118
/// values can be loaded as a sliding window.
127119
/// e.g `const int32x2_t a_vals = {0x3effffff, 0x3effffff, 0x3f7fffff}`, if loads=2.

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

Lines changed: 73 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use itertools::Itertools;
22
use std::process::Command;
33

4-
use super::argument::Argument;
54
use super::indentation::Indentation;
65
use super::intrinsic::{IntrinsicDefinition, format_f16_return_value};
76
use super::intrinsic_helpers::IntrinsicTypeDefinition;
@@ -156,66 +155,87 @@ pub fn generate_rust_test_loop<T: IntrinsicTypeDefinition>(
156155
w: &mut impl std::io::Write,
157156
intrinsic: &dyn IntrinsicDefinition<T>,
158157
indentation: Indentation,
159-
additional: &str,
158+
specializations: &[Vec<u8>],
160159
passes: u32,
161160
) -> std::io::Result<()> {
162-
let constraints = intrinsic.arguments().as_constraint_parameters_rust();
163-
let constraints = if !constraints.is_empty() {
164-
format!("::<{constraints}>")
165-
} else {
166-
constraints
167-
};
161+
let intrinsic_name = intrinsic.name();
162+
163+
// Each function (and each specialization) has its own type. Erase that type with a cast.
164+
let mut coerce = String::from("unsafe fn(");
165+
for _ in intrinsic.arguments().iter().filter(|a| !a.has_constraint()) {
166+
coerce += "_, ";
167+
}
168+
coerce += ") -> _";
169+
170+
match specializations {
171+
[] => {
172+
writeln!(w, " let specializations = [(\"\", {intrinsic_name})];")?;
173+
}
174+
[const_args] if const_args.is_empty() => {
175+
writeln!(w, " let specializations = [(\"\", {intrinsic_name})];")?;
176+
}
177+
_ => {
178+
writeln!(w, " let specializations = [")?;
179+
180+
for specialization in specializations {
181+
let mut specialization: Vec<_> =
182+
specialization.iter().map(|d| d.to_string()).collect();
183+
184+
let const_args = specialization.join(",");
185+
186+
// The identifier is reversed.
187+
specialization.reverse();
188+
let id = specialization.join("-");
189+
190+
writeln!(
191+
w,
192+
" (\"-{id}\", {intrinsic_name}::<{const_args}> as {coerce}),"
193+
)?;
194+
}
195+
196+
writeln!(w, " ];")?;
197+
}
198+
}
168199

169200
let return_value = format_f16_return_value(intrinsic);
170201
let indentation2 = indentation.nested();
171202
let indentation3 = indentation2.nested();
172203
writeln!(
173204
w,
174-
"{indentation}for i in 0..{passes} {{\n\
175-
{indentation2}unsafe {{\n\
176-
{loaded_args}\
177-
{indentation3}let __return_value = {intrinsic_call}{const}({args});\n\
178-
{indentation3}println!(\"Result {additional}-{{}}: {{:?}}\", i + 1, {return_value});\n\
179-
{indentation2}}}\n\
180-
{indentation}}}",
205+
"\
206+
for (id, f) in specializations {{\n\
207+
for i in 0..{passes} {{\n\
208+
unsafe {{\n\
209+
{loaded_args}\
210+
let __return_value = f({args});\n\
211+
println!(\"Result {{id}}-{{}}: {{:?}}\", i + 1, {return_value});\n\
212+
}}\n\
213+
}}\n\
214+
}}",
181215
loaded_args = intrinsic.arguments().load_values_rust(indentation3),
182-
intrinsic_call = intrinsic.name(),
183-
const = constraints,
184216
args = intrinsic.arguments().as_call_param_rust(),
185217
)
186218
}
187219

188-
fn generate_rust_constraint_blocks<'a, T: IntrinsicTypeDefinition + 'a>(
189-
w: &mut impl std::io::Write,
190-
intrinsic: &dyn IntrinsicDefinition<T>,
191-
indentation: Indentation,
192-
constraints: &mut (impl Iterator<Item = &'a Argument<T>> + Clone),
193-
name: String,
194-
) -> std::io::Result<()> {
195-
let Some(current) = constraints.next() else {
196-
return generate_rust_test_loop(w, intrinsic, indentation, &name, PASSES);
197-
};
198-
199-
let body_indentation = indentation.nested();
200-
for i in current.constraint.iter().flat_map(|c| c.to_range()) {
201-
let ty = current.ty.rust_type();
202-
203-
writeln!(w, "{indentation}{{")?;
204-
205-
writeln!(w, "{body_indentation}const {}: {ty} = {i};", current.name)?;
206-
207-
generate_rust_constraint_blocks(
208-
w,
209-
intrinsic,
210-
body_indentation,
211-
&mut constraints.clone(),
212-
format!("{name}-{i}"),
213-
)?;
214-
215-
writeln!(w, "{indentation}}}")?;
220+
/// Generate the specializations (unique sequences of const-generic arguments) for this intrinsic.
221+
fn generate_rust_specializations<'a>(
222+
constraints: &mut impl Iterator<Item = std::ops::Range<i64>>,
223+
) -> Vec<Vec<u8>> {
224+
let mut specializations = vec![vec![]];
225+
226+
for constraint in constraints {
227+
specializations = constraint
228+
.flat_map(|right| {
229+
specializations.iter().map(move |left| {
230+
let mut left = left.clone();
231+
left.push(u8::try_from(right).unwrap());
232+
left
233+
})
234+
})
235+
.collect();
216236
}
217237

218-
Ok(())
238+
specializations
219239
}
220240

221241
// Top-level function to create complete test program
@@ -233,13 +253,13 @@ pub fn create_rust_test_module<T: IntrinsicTypeDefinition>(
233253
arguments.gen_arglists_rust(w, indentation.nested(), PASSES)?;
234254

235255
// Define any const generics as `const` items, then generate the actual test loop.
236-
generate_rust_constraint_blocks(
237-
w,
238-
intrinsic,
239-
indentation.nested(),
240-
&mut arguments.iter().rev().filter(|i| i.has_constraint()),
241-
Default::default(),
242-
)?;
256+
let specializations = generate_rust_specializations(
257+
&mut arguments
258+
.iter()
259+
.filter_map(|i| i.constraint.as_ref().map(|v| v.to_range())),
260+
);
261+
262+
generate_rust_test_loop(w, intrinsic, indentation, &specializations, PASSES)?;
243263

244264
writeln!(w, "}}")?;
245265

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,4 @@ pub trait IntrinsicTypeDefinition: Deref<Target = IntrinsicType> {
290290

291291
/// can be directly defined in `impl` blocks
292292
fn c_single_vector_type(&self) -> String;
293-
294-
/// can be defined in `impl` blocks
295-
fn rust_type(&self) -> String;
296293
}

0 commit comments

Comments
 (0)