Skip to content

Commit 6277e35

Browse files
authored
Merge pull request #2126 from davidtwco/intrinsic-test-values
intrinsic-test: refactor `populate_random` and related code
2 parents f51bf86 + a5d092c commit 6277e35

5 files changed

Lines changed: 328 additions & 268 deletions

File tree

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

Lines changed: 4 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use itertools::Itertools;
22

33
use crate::common::intrinsic_helpers::TypeKind;
4+
use crate::common::values::test_values_array_name;
45

6+
use super::PASSES;
57
use super::constraint::Constraint;
6-
use super::gen_rust::PASSES;
78
use super::intrinsic_helpers::IntrinsicTypeDefinition;
89

910
/// An argument for the intrinsic.
@@ -52,17 +53,6 @@ where
5253
self.constraint.is_some()
5354
}
5455

55-
/// Returns a string with the name of the static variable containing test values for intrinsic
56-
/// arguments of this type.
57-
pub(crate) fn rust_vals_array_name(&self) -> impl std::fmt::Display {
58-
let loads = crate::common::gen_rust::PASSES;
59-
format!(
60-
"{ty}_{load_size}",
61-
ty = self.ty.rust_scalar_type().to_uppercase(),
62-
load_size = self.ty.num_lanes() * self.ty.num_vectors() + loads - 1,
63-
)
64-
}
65-
6656
/// Should this argument be passed by reference in C wrapper function declarations?
6757
///
6858
/// SIMD types and `f16` are currently passed by reference.
@@ -165,41 +155,6 @@ where
165155
.join("")
166156
}
167157

168-
/// Returns a string defining a static variable with test values used for all intrinsics with
169-
/// arguments of `arg`'s type.
170-
///
171-
/// e.g.
172-
/// ```rust,ignore
173-
/// static U8_20: [u8; 20] = [
174-
/// 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xf0,
175-
/// 0x80, 0x3b, 0xff,
176-
/// ];
177-
/// ```
178-
///
179-
/// `num_lanes * num_vectors + loads - 1` elements are present in the array, which is sufficient
180-
/// for a `loads` number of `num_lanes * num_vectors` windows into the array to be loaded:
181-
///
182-
/// ```text
183-
/// [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xf0, 0x80, 0x3b, 0xff]
184-
/// ^^^^^^^^^^^^^^^^^^^ first window of `num_lanes * num_vectors` elements (e.g. four elements)
185-
/// ^^^^^^^^^^^^^^^^^^ second window
186-
/// `loads`th window ^^^^^^^^^^^^^^^^^^^^^^
187-
/// ```
188-
pub fn gen_arg_rust(
189-
arg: &Argument<T>,
190-
w: &mut impl std::io::Write,
191-
loads: u32,
192-
) -> std::io::Result<()> {
193-
writeln!(
194-
w,
195-
"static {name}: [{ty}; {load_size}] = {values};\n",
196-
name = arg.rust_vals_array_name(),
197-
ty = arg.ty.rust_scalar_type(),
198-
load_size = arg.ty.num_lanes() * arg.ty.num_vectors() + loads - 1,
199-
values = arg.ty.populate_random(loads)
200-
)
201-
}
202-
203158
/// Returns a string defining a local variable for each argument and loading a value into each
204159
/// using a load intrinsic.
205160
///
@@ -226,14 +181,14 @@ where
226181
format!(
227182
"let {name} = {load}({vals_name}.as_ptr().add((i+{idx}) % {PASSES}) as _);\n",
228183
name = arg.generate_name(),
229-
vals_name = arg.rust_vals_array_name(),
184+
vals_name = test_values_array_name(&arg.ty),
230185
load = arg.ty.get_load_function(),
231186
)
232187
} else {
233188
format!(
234189
"let {name} = {vals_name}[(i+{idx}) % {PASSES}];\n",
235190
name = arg.generate_name(),
236-
vals_name = arg.rust_vals_array_name(),
191+
vals_name = test_values_array_name(&arg.ty),
237192
)
238193
}
239194
})

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

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,11 @@ use std::process::Command;
33
use itertools::Itertools;
44

55
use super::intrinsic_helpers::IntrinsicTypeDefinition;
6-
use crate::common::argument::ArgumentList;
6+
use crate::common::PASSES;
77
use crate::common::cli::{CcArgStyle, ProcessedCli};
88
use crate::common::intrinsic::Intrinsic;
99
use crate::common::intrinsic_helpers::TypeKind;
10-
11-
// The number of times each intrinsic will be called - influences the generation of the
12-
// test arrays to minimise repeated testing of the same test values.
13-
pub(crate) const PASSES: u32 = 20;
10+
use crate::common::values::{test_values_array_name, test_values_array_static};
1411

1512
/// Rust definitions that are included verbatim in the generated source. In particular, defines
1613
/// a wrapper around float types that defines `NaN`s to be equal reflexively to enable
@@ -135,10 +132,10 @@ pub fn write_lib_rs<T: IntrinsicTypeDefinition>(
135132
for intrinsic in intrinsics {
136133
for arg in &intrinsic.arguments.args {
137134
if !arg.has_constraint() {
138-
let name = arg.rust_vals_array_name().to_string();
135+
let name = test_values_array_name(&arg.ty);
139136

140137
if seen.insert(name) {
141-
ArgumentList::gen_arg_rust(arg, w, PASSES)?;
138+
test_values_array_static(w, &arg.ty)?;
142139
}
143140
}
144141
}
@@ -163,7 +160,6 @@ pub fn write_lib_rs<T: IntrinsicTypeDefinition>(
163160
fn generate_rust_test_loop<T: IntrinsicTypeDefinition>(
164161
w: &mut impl std::io::Write,
165162
intrinsic: &Intrinsic<T>,
166-
passes: u32,
167163
) -> std::io::Result<()> {
168164
let intrinsic_name = &intrinsic.name;
169165

@@ -247,7 +243,7 @@ fn generate_rust_test_loop<T: IntrinsicTypeDefinition>(
247243
loaded_args = intrinsic.arguments.load_values_rust(),
248244
rust_args = intrinsic.arguments.as_call_param_rust(),
249245
c_args = intrinsic.arguments.as_c_call_param_rust(),
250-
passes = passes,
246+
passes = PASSES,
251247
cast_prefix = cast_prefix,
252248
cast_suffix = cast_suffix,
253249
)
@@ -267,7 +263,7 @@ fn create_rust_test<T: IntrinsicTypeDefinition>(
267263
intrinsic_name = intrinsic.name,
268264
)?;
269265

270-
generate_rust_test_loop(w, intrinsic, PASSES)?;
266+
generate_rust_test_loop(w, intrinsic)?;
271267

272268
writeln!(w, "}}")?;
273269

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

Lines changed: 0 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ use std::fmt;
33
use std::ops::Deref;
44
use std::str::FromStr;
55

6-
use itertools::Itertools as _;
7-
8-
use super::values::value_for_array;
9-
106
#[derive(Debug, PartialEq, Copy, Clone)]
117
pub enum Sign {
128
Signed,
@@ -197,92 +193,6 @@ impl IntrinsicType {
197193
pub fn is_ptr(&self) -> bool {
198194
self.ptr
199195
}
200-
201-
/// Returns the elements used in the test value arrays in `gen_arg_rust`. Uses the same
202-
/// `num_lanes * num_vectors + loads - 1` arithmetic to produce the number of values that
203-
/// `ArgumentList::gen_arg_rust` expects and `ArgumentList::load_values_rust` needs.
204-
///
205-
/// Each value in the array starts as a bit pattern from `common::values::value_from_array`
206-
/// which is then printed as a hex value in the generated code (and if identified as a negative
207-
/// value, with the appropriate minus and corrected hex pattern). Calls to `fN::from_bits` are
208-
/// generated for floats.
209-
pub fn populate_random(&self, loads: u32) -> String {
210-
match self {
211-
IntrinsicType {
212-
bit_len: Some(bit_len @ (1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 16 | 32 | 64)),
213-
kind:
214-
kind @ (TypeKind::Int(_) | TypeKind::Poly | TypeKind::Char(_) | TypeKind::Mask),
215-
vec_len,
216-
..
217-
} => {
218-
format!(
219-
"[\n{body}\n]",
220-
body = (0..(self.num_lanes() * vec_len.unwrap_or(1) + loads - 1)).format_with(
221-
",\n",
222-
|i, fmt| {
223-
let src = value_for_array(*bit_len, i);
224-
assert!(src == 0 || src.ilog2() < *bit_len);
225-
if *kind == TypeKind::Int(Sign::Signed) && (src >> (*bit_len - 1)) != 0
226-
{
227-
// `src` is a two's complement representation of a negative value.
228-
let mask = !0u64 >> (64 - *bit_len);
229-
let ones_compl = src ^ mask;
230-
let twos_compl = ones_compl + 1;
231-
fmt(&format_args!("-{twos_compl:#x}"))
232-
} else {
233-
fmt(&format_args!("{src:#x}"))
234-
}
235-
}
236-
)
237-
)
238-
}
239-
IntrinsicType {
240-
kind: TypeKind::Float,
241-
bit_len: Some(bit_len @ (16 | 32 | 64)),
242-
vec_len,
243-
..
244-
} => {
245-
format!(
246-
"[\n{body}\n]",
247-
body = (0..(self.num_lanes() * vec_len.unwrap_or(1) + loads - 1)).format_with(
248-
",\n",
249-
|i, fmt| fmt(&format_args!(
250-
"f{bit_len}::from_bits({src:#x})",
251-
src = value_for_array(*bit_len, i)
252-
))
253-
)
254-
)
255-
}
256-
IntrinsicType {
257-
kind: TypeKind::Vector,
258-
bit_len: Some(128 | 256 | 512),
259-
vec_len,
260-
..
261-
} => {
262-
let effective_bit_len = 32;
263-
format!(
264-
"[\n{body}\n]",
265-
body = (0..(vec_len.unwrap_or(1) * self.num_lanes() + loads - 1)).format_with(
266-
",\n",
267-
|i, fmt| {
268-
let src = value_for_array(effective_bit_len, i);
269-
assert!(src == 0 || src.ilog2() < effective_bit_len);
270-
if (src >> (effective_bit_len - 1)) != 0 {
271-
// `src` is a two's complement representation of a negative value.
272-
let mask = !0u64 >> (64 - effective_bit_len);
273-
let ones_compl = src ^ mask;
274-
let twos_compl = ones_compl + 1;
275-
fmt(&format_args!("-{twos_compl:#x}"))
276-
} else {
277-
fmt(&format_args!("{src:#x}"))
278-
}
279-
}
280-
)
281-
)
282-
}
283-
_ => unimplemented!("populate random: {self:#?}"),
284-
}
285-
}
286196
}
287197

288198
pub trait IntrinsicTypeDefinition: Deref<Target = IntrinsicType> {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ mod gen_c;
2323
mod gen_rust;
2424
mod values;
2525

26+
// The number of times each intrinsic will be called - influences the generation of the
27+
// test arrays to minimise repeated testing of the same test values.
28+
pub(crate) const PASSES: u32 = 20;
29+
2630
/// Architectures must support this trait
2731
/// to be successfully tested.
2832
pub trait SupportedArchitectureTest {

0 commit comments

Comments
 (0)