Skip to content

Commit e0a2cf1

Browse files
committed
generate arrays of type-erased function pointers
1 parent f2a0635 commit e0a2cf1

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;
@@ -188,66 +187,87 @@ pub fn generate_rust_test_loop<T: IntrinsicTypeDefinition>(
188187
w: &mut impl std::io::Write,
189188
intrinsic: &dyn IntrinsicDefinition<T>,
190189
indentation: Indentation,
191-
additional: &str,
190+
specializations: &[Vec<u8>],
192191
passes: u32,
193192
) -> std::io::Result<()> {
194-
let constraints = intrinsic.arguments().as_constraint_parameters_rust();
195-
let constraints = if !constraints.is_empty() {
196-
format!("::<{constraints}>")
197-
} else {
198-
constraints
199-
};
193+
let intrinsic_name = intrinsic.name();
194+
195+
// Each function (and each specialization) has its own type. Erase that type with a cast.
196+
let mut coerce = String::from("unsafe fn(");
197+
for _ in intrinsic.arguments().iter().filter(|a| !a.has_constraint()) {
198+
coerce += "_, ";
199+
}
200+
coerce += ") -> _";
201+
202+
match specializations {
203+
[] => {
204+
writeln!(w, " let specializations = [(\"\", {intrinsic_name})];")?;
205+
}
206+
[const_args] if const_args.is_empty() => {
207+
writeln!(w, " let specializations = [(\"\", {intrinsic_name})];")?;
208+
}
209+
_ => {
210+
writeln!(w, " let specializations = [")?;
211+
212+
for specialization in specializations {
213+
let mut specialization: Vec<_> =
214+
specialization.iter().map(|d| d.to_string()).collect();
215+
216+
let const_args = specialization.join(",");
217+
218+
// The identifier is reversed.
219+
specialization.reverse();
220+
let id = specialization.join("-");
221+
222+
writeln!(
223+
w,
224+
" (\"-{id}\", {intrinsic_name}::<{const_args}> as {coerce}),"
225+
)?;
226+
}
227+
228+
writeln!(w, " ];")?;
229+
}
230+
}
200231

201232
let return_value = format_f16_return_value(intrinsic);
202233
let indentation2 = indentation.nested();
203234
let indentation3 = indentation2.nested();
204235
writeln!(
205236
w,
206-
"{indentation}for i in 0..{passes} {{\n\
207-
{indentation2}unsafe {{\n\
208-
{loaded_args}\
209-
{indentation3}let __return_value = {intrinsic_call}{const}({args});\n\
210-
{indentation3}println!(\"Result {additional}-{{}}: {{:?}}\", i + 1, {return_value});\n\
211-
{indentation2}}}\n\
212-
{indentation}}}",
237+
"\
238+
for (id, f) in specializations {{\n\
239+
for i in 0..{passes} {{\n\
240+
unsafe {{\n\
241+
{loaded_args}\
242+
let __return_value = f({args});\n\
243+
println!(\"Result {{id}}-{{}}: {{:?}}\", i + 1, {return_value});\n\
244+
}}\n\
245+
}}\n\
246+
}}",
213247
loaded_args = intrinsic.arguments().load_values_rust(indentation3),
214-
intrinsic_call = intrinsic.name(),
215-
const = constraints,
216248
args = intrinsic.arguments().as_call_param_rust(),
217249
)
218250
}
219251

220-
fn generate_rust_constraint_blocks<'a, T: IntrinsicTypeDefinition + 'a>(
221-
w: &mut impl std::io::Write,
222-
intrinsic: &dyn IntrinsicDefinition<T>,
223-
indentation: Indentation,
224-
constraints: &mut (impl Iterator<Item = &'a Argument<T>> + Clone),
225-
name: String,
226-
) -> std::io::Result<()> {
227-
let Some(current) = constraints.next() else {
228-
return generate_rust_test_loop(w, intrinsic, indentation, &name, PASSES);
229-
};
230-
231-
let body_indentation = indentation.nested();
232-
for i in current.constraint.iter().flat_map(|c| c.to_range()) {
233-
let ty = current.ty.rust_type();
234-
235-
writeln!(w, "{indentation}{{")?;
236-
237-
writeln!(w, "{body_indentation}const {}: {ty} = {i};", current.name)?;
238-
239-
generate_rust_constraint_blocks(
240-
w,
241-
intrinsic,
242-
body_indentation,
243-
&mut constraints.clone(),
244-
format!("{name}-{i}"),
245-
)?;
246-
247-
writeln!(w, "{indentation}}}")?;
252+
/// Generate the specializations (unique sequences of const-generic arguments) for this intrinsic.
253+
fn generate_rust_specializations<'a>(
254+
constraints: &mut impl Iterator<Item = std::ops::Range<i64>>,
255+
) -> Vec<Vec<u8>> {
256+
let mut specializations = vec![vec![]];
257+
258+
for constraint in constraints {
259+
specializations = constraint
260+
.flat_map(|right| {
261+
specializations.iter().map(move |left| {
262+
let mut left = left.clone();
263+
left.push(u8::try_from(right).unwrap());
264+
left
265+
})
266+
})
267+
.collect();
248268
}
249269

250-
Ok(())
270+
specializations
251271
}
252272

253273
// Top-level function to create complete test program
@@ -265,13 +285,13 @@ pub fn create_rust_test_module<T: IntrinsicTypeDefinition>(
265285
arguments.gen_arglists_rust(w, indentation.nested(), PASSES)?;
266286

267287
// Define any const generics as `const` items, then generate the actual test loop.
268-
generate_rust_constraint_blocks(
269-
w,
270-
intrinsic,
271-
indentation.nested(),
272-
&mut arguments.iter().rev().filter(|i| i.has_constraint()),
273-
Default::default(),
274-
)?;
288+
let specializations = generate_rust_specializations(
289+
&mut arguments
290+
.iter()
291+
.filter_map(|i| i.constraint.as_ref().map(|v| v.to_range())),
292+
);
293+
294+
generate_rust_test_loop(w, intrinsic, indentation, &specializations, PASSES)?;
275295

276296
writeln!(w, "}}")?;
277297

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

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

333333
/// can be directly defined in `impl` blocks
334334
fn c_single_vector_type(&self) -> String;
335-
336-
/// can be defined in `impl` blocks
337-
fn rust_type(&self) -> String;
338335
}

0 commit comments

Comments
 (0)