]>
git.proxmox.com Git - rustc.git/blob - library/stdarch/crates/intrinsic-test/src/main.rs
2 extern crate lazy_static
;
8 use std
::process
::Command
;
11 use intrinsic
::Intrinsic
;
12 use rayon
::prelude
::*;
20 #[derive(Debug, PartialEq)]
26 fn generate_c_program(header_files
: &[&str], intrinsic
: &Intrinsic
) -> String
{
33 template<typename T1, typename T2> T1 cast(T2 x) {{
34 static_assert(sizeof(T1) == sizeof(T2), "sizeof T1 and T2 must be the same");
36 memcpy(&ret, &x, sizeof(T1));
39 std::ostream& operator<<(std::ostream& os, poly128_t value) {{
40 std::stringstream temp;
45 }} while (value != 0);
46 std::string tempstr(temp.str());
47 std::string res(tempstr.rbegin(), tempstr.rend());
51 int main(int argc, char **argv) {{
55 header_files
= header_files
57 .map(|header
| format
!("#include <{}>", header
))
61 .map(|idx
| intrinsic
.generate_pass_c(idx
))
67 fn generate_rust_program(intrinsic
: &Intrinsic
) -> String
{
69 r
#"#![feature(simd_ffi)]
70 #![feature(link_llvm_intrinsics)]
72 #![allow(overflowing_literals)]
73 use core_arch::arch::aarch64::*;
80 .map(|idx
| intrinsic
.generate_pass_rust(idx
))
86 fn compile_c(c_filename
: &str, intrinsic
: &Intrinsic
, compiler
: &str) -> bool
{
87 let flags
= std
::env
::var("CPPFLAGS").unwrap_or("".into());
89 let output
= Command
::new("sh")
92 "{cpp} {cppflags} {arch_flags} -Wno-narrowing -O2 -target {target} -o c_programs/{intrinsic} {filename}",
93 target
= "aarch64-unknown-linux-gnu",
94 arch_flags
= "-march=armv8-a+crypto+crc",
95 filename
= c_filename
,
96 intrinsic
= intrinsic
.name
,
101 if let Ok(output
) = output
{
102 if output
.status
.success() {
105 let stderr
= std
::str::from_utf8(&output
.stderr
).unwrap_or("");
106 if stderr
.contains("error: use of undeclared identifier") {
107 warn
!("Skipping intrinsic due to no support: {}", intrinsic
.name
);
111 "Failed to compile code for intrinsic: {}\n\nstdout:\n{}\n\nstderr:\n{}",
113 std
::str::from_utf8(&output
.stdout
).unwrap_or(""),
114 std
::str::from_utf8(&output
.stderr
).unwrap_or("")
120 error
!("Command failed: {:#?}", output
);
125 fn build_c(intrinsics
: &Vec
<Intrinsic
>, compiler
: &str) -> bool
{
126 let _
= std
::fs
::create_dir("c_programs");
130 let c_filename
= format
!(r
#"c_programs/{}.cpp"#, i.name);
131 let mut file
= File
::create(&c_filename
).unwrap();
133 let c_code
= generate_c_program(&["arm_neon.h", "arm_acle.h"], &i
);
134 file
.write_all(c_code
.into_bytes().as_slice()).unwrap();
135 compile_c(&c_filename
, &i
, compiler
)
141 fn build_rust(intrinsics
: &Vec
<Intrinsic
>, toolchain
: &str) -> bool
{
142 intrinsics
.iter().for_each(|i
| {
143 let rust_dir
= format
!(r
#"rust_programs/{}"#, i.name);
144 let _
= std
::fs
::create_dir_all(&rust_dir
);
145 let rust_filename
= format
!(r
#"{}/main.rs"#, rust_dir);
146 let mut file
= File
::create(&rust_filename
).unwrap();
148 let c_code
= generate_rust_program(&i
);
149 file
.write_all(c_code
.into_bytes().as_slice()).unwrap();
152 let mut cargo
= File
::create("rust_programs/Cargo.toml").unwrap();
157 name = "intrinsic-test"
158 version = "{version}"
159 authors = ["{authors}"]
163 core_arch = {{ path = "../crates/core_arch" }}
165 version
= env
!("CARGO_PKG_VERSION"),
166 authors
= env
!("CARGO_PKG_AUTHORS"),
167 binaries
= intrinsics
173 path = "{intrinsic}/main.rs""#,
185 let output
= Command
::new("sh")
186 .current_dir("rust_programs")
189 "cargo {toolchain} build --release --target {target}",
190 toolchain
= toolchain
,
191 target
= "aarch64-unknown-linux-gnu",
194 if let Ok(output
) = output
{
195 if output
.status
.success() {
199 "Failed to compile code for intrinsics\n\nstdout:\n{}\n\nstderr:\n{}",
200 std
::str::from_utf8(&output
.stdout
).unwrap_or(""),
201 std
::str::from_utf8(&output
.stderr
).unwrap_or("")
206 error
!("Command failed: {:#?}", output
);
212 pretty_env_logger
::init();
214 let matches
= App
::new("Intrinsic test tool")
215 .about("Generates Rust and C programs for intrinsics and compares the output")
217 Arg
::with_name("INPUT")
218 .help("The input file containing the intrinsics")
223 Arg
::with_name("TOOLCHAIN")
226 .help("The rust toolchain to use for building the rust code"),
229 Arg
::with_name("CPPCOMPILER")
231 .default_value("clang++")
233 .help("The C++ compiler to use for compiling the c++ code"),
236 Arg
::with_name("RUNNER")
239 .help("Run the C programs under emulation with this command"),
243 let filename
= matches
.value_of("INPUT").unwrap();
244 let toolchain
= matches
245 .value_of("TOOLCHAIN")
246 .map_or("".into(), |t
| format
!("+{}", t
));
248 let cpp_compiler
= matches
.value_of("CPPCOMPILER").unwrap();
249 let c_runner
= matches
.value_of("RUNNER").unwrap_or("");
250 let mut csv_reader
= csv
::Reader
::from_reader(std
::fs
::File
::open(filename
).unwrap());
252 let mut intrinsics
= csv_reader
254 .filter_map(|x
| -> Option
<Intrinsic
> {
255 debug
!("Processing {:#?}", x
);
264 // Only perform the test for intrinsics that are enabled...
265 .filter(|i
| i
.enabled
)
266 // Not sure how we would compare intrinsic that returns void.
267 .filter(|i
| i
.results
.kind() != TypeKind
::Void
)
268 .filter(|i
| i
.results
.kind() != TypeKind
::BFloat
)
269 .filter(|i
| !(i
.results
.kind() == TypeKind
::Float
&& i
.results
.inner_size() == 16))
273 .find(|a
| a
.ty
.kind() == TypeKind
::BFloat
)
279 .find(|a
| a
.ty
.kind() == TypeKind
::Float
&& a
.ty
.inner_size() == 16)
282 // Skip pointers for now, we would probably need to look at the return
283 // type to work out how many elements we need to point to.
284 .filter(|i
| i
.arguments
.iter().find(|a
| a
.is_ptr()).is_none())
285 // intrinsics with a lane parameter have constraints, deal with them later.
289 .find(|a
| a
.name
.starts_with("lane"))
292 .filter(|i
| i
.arguments
.iter().find(|a
| a
.name
== "n").is_none())
293 // clang-12 fails to compile this intrinsic due to an error.
294 // fatal error: error in backend: Cannot select: 0x2b99c30: i64 = AArch64ISD::VSHL Constant:i64<1>, Constant:i32<1>
295 // 0x2b9a520: i64 = Constant<1>
296 // 0x2b9a248: i32 = Constant<1>
297 .filter(|i
| !["vshld_s64", "vshld_u64"].contains(&i
.name
.as_str()))
298 .collect
::<Vec
<_
>>();
301 if !build_c(&intrinsics
, cpp_compiler
) {
302 std
::process
::exit(2);
305 if !build_rust(&intrinsics
, &toolchain
) {
306 std
::process
::exit(3);
309 if !compare_outputs(&intrinsics
, &toolchain
, &c_runner
) {
310 std
::process
::exit(1)
317 Difference(String
, String
, String
),
320 fn compare_outputs(intrinsics
: &Vec
<Intrinsic
>, toolchain
: &str, runner
: &str) -> bool
{
321 let intrinsics
= intrinsics
323 .filter_map(|intrinsic
| {
324 let c
= Command
::new("sh")
327 "{runner} ./c_programs/{intrinsic}",
329 intrinsic
= intrinsic
.name
,
332 let rust
= Command
::new("sh")
333 .current_dir("rust_programs")
336 "cargo {toolchain} run --release --target {target} --bin {intrinsic}",
337 intrinsic
= intrinsic
.name
,
338 toolchain
= toolchain
,
339 target
= "aarch64-unknown-linux-gnu",
343 let (c
, rust
) = match (c
, rust
) {
344 (Ok(c
), Ok(rust
)) => (c
, rust
),
345 a
=> panic
!("{:#?}", a
),
348 if !c
.status
.success() {
349 error
!("Failed to run C program for intrinsic {}", intrinsic
.name
);
350 return Some(FailureReason
::RunC(intrinsic
.name
.clone()));
353 if !rust
.status
.success() {
355 "Failed to run rust program for intrinsic {}",
358 return Some(FailureReason
::RunRust(intrinsic
.name
.clone()));
361 info
!("Comparing intrinsic: {}", intrinsic
.name
);
363 let c
= std
::str::from_utf8(&c
.stdout
)
366 .replace("-nan", "nan");
367 let rust
= std
::str::from_utf8(&rust
.stdout
)
370 .replace("-nan", "nan");
375 Some(FailureReason
::Difference(intrinsic
.name
.clone(), c
, rust
))
378 .collect
::<Vec
<_
>>();
380 intrinsics
.iter().for_each(|reason
| match reason
{
381 FailureReason
::Difference(intrinsic
, c
, rust
) => {
382 println
!("Difference for intrinsic: {}", intrinsic
);
383 let diff
= diff
::lines(c
, rust
);
384 diff
.iter().for_each(|diff
| match diff
{
385 diff
::Result
::Left(c
) => println
!("C: {}", c
),
386 diff
::Result
::Right(rust
) => println
!("Rust: {}", rust
),
387 diff
::Result
::Both(_
, _
) => (),
389 println
!("****************************************************************");
391 FailureReason
::RunC(intrinsic
) => {
392 println
!("Failed to run C program for intrinsic {}", intrinsic
)
394 FailureReason
::RunRust(intrinsic
) => {
395 println
!("Failed to run rust program for intrinsic {}", intrinsic
)
398 println
!("{} differences found", intrinsics
.len());
399 intrinsics
.is_empty()