Skip to content

Commit 97bda68

Browse files
Jmc18134Amanieu
authored andcommitted
Use load intrinsic and loop for intrinsic-test programs. Add --release flag back to intrinsic-test programs.
1 parent 9eb3150 commit 97bda68

File tree

6 files changed

+184
-109
lines changed

6 files changed

+184
-109
lines changed

crates/intrinsic-test/missing_aarch64.txt

-14
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,6 @@ vrnd64xq_f64
6767
vrnd64z_f64
6868
vrnd64zq_f64
6969

70-
# Takes too long to compile tests
71-
vcopyq_laneq_u8
72-
vcopyq_laneq_s8
73-
vcopyq_laneq_p8
74-
vcopyq_lane_u8
75-
vcopyq_lane_s8
76-
vcopyq_lane_p8
77-
vcopy_laneq_u8
78-
vcopy_laneq_s8
79-
vcopy_laneq_p8
80-
vcopy_lane_u8
81-
vcopy_lane_s8
82-
vcopy_lane_p8
83-
8470
# QEMU 6.0 doesn't support these instructions
8571
vmmlaq_s32
8672
vmmlaq_u32

crates/intrinsic-test/src/argument.rs

+83-24
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::ops::Range;
22

3-
use crate::types::IntrinsicType;
3+
use crate::types::{IntrinsicType, TypeKind};
44
use crate::Language;
55

66
/// An argument for the intrinsic.
@@ -90,49 +90,108 @@ impl ArgumentList {
9090
.join(", ")
9191
}
9292

93-
/// Creates a line that initializes this argument for C code.
94-
/// e.g. `int32x2_t a = { 0x1, 0x2 };`
95-
pub fn init_random_values_c(&self, pass: usize) -> String {
93+
/// Creates a line for each argument that initializes an array for C from which `loads` argument
94+
/// values can be loaded as a sliding window.
95+
/// e.g `const int32x2_t a_vals = {0x3effffff, 0x3effffff, 0x3f7fffff}`, if loads=2.
96+
pub fn gen_arglists_c(&self, loads: u32) -> String {
9697
self.iter()
9798
.filter_map(|arg| {
9899
(!arg.has_constraint()).then(|| {
99100
format!(
100-
"{ty} {name} = {{ {values} }};",
101-
ty = arg.to_c_type(),
101+
"const {ty} {name}_vals[] = {{ {values} }};",
102+
ty = arg.ty.c_scalar_type(),
102103
name = arg.name,
103-
values = arg.ty.populate_random(pass, &Language::C)
104+
values = arg.ty.populate_random(loads, &Language::C)
104105
)
105106
})
106107
})
107108
.collect::<Vec<_>>()
108-
.join("\n ")
109+
.join("\n")
109110
}
110111

111-
/// Creates a line that initializes this argument for Rust code.
112-
/// e.g. `let a = transmute([0x1, 0x2]);`
113-
pub fn init_random_values_rust(&self, pass: usize) -> String {
112+
/// Creates a line for each argument that initializes an array for Rust from which `loads` argument
113+
/// values can be loaded as a sliding window, e.g `const A_VALS: [u32; 20] = [...];`
114+
pub fn gen_arglists_rust(&self, loads: u32) -> String {
114115
self.iter()
115116
.filter_map(|arg| {
116117
(!arg.has_constraint()).then(|| {
117-
if arg.is_simd() {
118-
format!(
119-
"let {name} = ::std::mem::transmute([{values}]);",
120-
name = arg.name,
121-
values = arg.ty.populate_random(pass, &Language::Rust),
122-
)
123-
} else {
124-
format!(
125-
"let {name} = {value};",
126-
name = arg.name,
127-
value = arg.ty.populate_random(pass, &Language::Rust)
128-
)
129-
}
118+
format!(
119+
"const {upper_name}_VALS: [{ty}; {load_size}] = unsafe{{ [{values}] }};",
120+
upper_name = arg.name.to_uppercase(),
121+
ty = arg.ty.rust_scalar_type(),
122+
load_size = arg.ty.num_lanes() * arg.ty.num_vectors() + loads - 1,
123+
values = arg.ty.populate_random(loads, &Language::Rust)
124+
)
125+
})
126+
})
127+
.collect::<Vec<_>>()
128+
.join("\n")
129+
}
130+
131+
/// Creates a line for each argument that initalizes the argument from an array [arg]_vals at
132+
/// an offset i using a load intrinsic, in C.
133+
/// e.g `uint8x8_t a = vld1_u8(&a_vals[i]);`
134+
pub fn load_values_c(&self, p64_armv7_workaround: bool) -> String {
135+
self.iter()
136+
.filter_map(|arg| {
137+
// The ACLE doesn't support 64-bit polynomial loads on Armv7
138+
// This and the cast are a workaround for this
139+
let armv7_p64 = if let TypeKind::Poly = arg.ty.kind() {
140+
p64_armv7_workaround
141+
} else {
142+
false
143+
};
144+
145+
(!arg.has_constraint()).then(|| {
146+
format!(
147+
"{ty} {name} = {open_cast}{load}(&{name}_vals[i]){close_cast};",
148+
ty = arg.to_c_type(),
149+
name = arg.name,
150+
load = if arg.is_simd() {
151+
arg.ty.get_load_function(p64_armv7_workaround)
152+
} else {
153+
"*".to_string()
154+
},
155+
open_cast = if armv7_p64 {
156+
format!("cast<{}>(", arg.to_c_type())
157+
} else {
158+
"".to_string()
159+
},
160+
close_cast = if armv7_p64 {
161+
")".to_string()
162+
} else {
163+
"".to_string()
164+
}
165+
)
130166
})
131167
})
132168
.collect::<Vec<_>>()
133169
.join("\n ")
134170
}
135171

172+
/// Creates a line for each argument that initalizes the argument from array [ARG]_VALS at
173+
/// an offset i using a load intrinsic, in Rust.
174+
/// e.g `let a = vld1_u8(A_VALS.as_ptr().offset(i));`
175+
pub fn load_values_rust(&self) -> String {
176+
self.iter()
177+
.filter_map(|arg| {
178+
(!arg.has_constraint()).then(|| {
179+
format!(
180+
"let {name} = {load}({upper_name}_VALS.as_ptr().offset(i));",
181+
name = arg.name,
182+
upper_name = arg.name.to_uppercase(),
183+
load = if arg.is_simd() {
184+
arg.ty.get_load_function(false)
185+
} else {
186+
"*".to_string()
187+
},
188+
)
189+
})
190+
})
191+
.collect::<Vec<_>>()
192+
.join("\n ")
193+
}
194+
136195
pub fn iter(&self) -> std::slice::Iter<'_, Argument> {
137196
self.args.iter()
138197
}

crates/intrinsic-test/src/intrinsic.rs

+37-28
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ pub struct Intrinsic {
2020

2121
impl Intrinsic {
2222
/// Generates a std::cout for the intrinsics results that will match the
23-
/// rust debug output format for the return type.
24-
pub fn print_result_c(&self, index: usize, additional: &str) -> String {
23+
/// rust debug output format for the return type. The generated line assumes
24+
/// there is an int i in scope which is the current pass number.
25+
pub fn print_result_c(&self, additional: &str) -> String {
2526
let lanes = if self.results.num_vectors() > 1 {
2627
(0..self.results.num_vectors())
2728
.map(|vector| {
@@ -72,7 +73,7 @@ impl Intrinsic {
7273
};
7374

7475
format!(
75-
r#"std::cout << "Result {additional}-{idx}: {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#,
76+
r#"std::cout << "Result {additional}-" << i+1 << ": {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#,
7677
ty = if self.results.is_simd() {
7778
format!("{}(", self.results.c_type())
7879
} else {
@@ -81,45 +82,53 @@ impl Intrinsic {
8182
close = if self.results.is_simd() { ")" } else { "" },
8283
lanes = lanes,
8384
additional = additional,
84-
idx = index,
8585
)
8686
}
8787

88-
pub fn generate_pass_rust(&self, index: usize, additional: &str) -> String {
88+
pub fn generate_loop_c(
89+
&self,
90+
additional: &str,
91+
passes: u32,
92+
p64_armv7_workaround: bool,
93+
) -> String {
94+
format!(
95+
r#" {{
96+
for (int i=0; i<{passes}; i++) {{
97+
{loaded_args}
98+
auto __return_value = {intrinsic_call}({args});
99+
{print_result}
100+
}}
101+
}}"#,
102+
loaded_args = self.arguments.load_values_c(p64_armv7_workaround),
103+
intrinsic_call = self.name,
104+
args = self.arguments.as_call_param_c(),
105+
print_result = self.print_result_c(additional)
106+
)
107+
}
108+
109+
pub fn generate_loop_rust(&self, additional: &str, passes: u32) -> String {
89110
let constraints = self.arguments.as_constraint_parameters_rust();
90111
let constraints = if !constraints.is_empty() {
91112
format!("::<{}>", constraints)
92113
} else {
93114
constraints
94115
};
95116

96-
format!(
97-
r#"
98-
unsafe {{
99-
{initialized_args}
100-
let res = {intrinsic_call}{const}({args});
101-
println!("Result {additional}-{idx}: {{:.150?}}", res);
102-
}}"#,
103-
initialized_args = self.arguments.init_random_values_rust(index),
104-
intrinsic_call = self.name,
105-
args = self.arguments.as_call_param_rust(),
106-
additional = additional,
107-
idx = index,
108-
const = constraints,
109-
)
110-
}
111-
112-
pub fn generate_pass_c(&self, index: usize, additional: &str) -> String {
113117
format!(
114118
r#" {{
115-
{initialized_args}
116-
auto __return_value = {intrinsic_call}({args});
117-
{print_result}
119+
for i in 0..{passes} {{
120+
unsafe {{
121+
{loaded_args}
122+
let __return_value = {intrinsic_call}{const}({args});
123+
println!("Result {additional}-{{}}: {{:.150?}}", i+1, __return_value);
124+
}}
125+
}}
118126
}}"#,
119-
initialized_args = self.arguments.init_random_values_c(index),
127+
loaded_args = self.arguments.load_values_rust(),
120128
intrinsic_call = self.name,
121-
args = self.arguments.as_call_param_c(),
122-
print_result = self.print_result_c(index, additional)
129+
const = constraints,
130+
args = self.arguments.as_call_param_rust(),
131+
additional = additional,
123132
)
124133
}
125134
}

0 commit comments

Comments
 (0)