mod compile; mod config; mod intrinsic; mod json_parser; mod types; use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; use crate::common::compare::compare_outputs; use crate::common::gen_rust::compile_rust_programs; use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; use crate::common::intrinsic_helpers::TypeKind; use crate::common::write_file::{write_c_testfiles, write_rust_testfiles}; use compile::compile_c_arm; use config::{AARCH_CONFIGURATIONS, F16_FORMATTING_DEF, POLY128_OSTREAM_DEF, build_notices}; use intrinsic::ArmIntrinsicType; use json_parser::get_neon_intrinsics; pub struct ArmArchitectureTest { intrinsics: Vec>, cli_options: ProcessedCli, } impl SupportedArchitectureTest for ArmArchitectureTest { fn create(cli_options: ProcessedCli) -> Box { let a32 = cli_options.target.contains("v7"); let mut intrinsics = get_neon_intrinsics(&cli_options.filename, &cli_options.target) .expect("Error parsing input file"); intrinsics.sort_by(|a, b| a.name.cmp(&b.name)); let mut intrinsics = intrinsics .into_iter() // Not sure how we would compare intrinsic that returns void. .filter(|i| i.results.kind() != TypeKind::Void) .filter(|i| i.results.kind() != TypeKind::BFloat) .filter(|i| !i.arguments.iter().any(|a| a.ty.kind() == TypeKind::BFloat)) // Skip pointers for now, we would probably need to look at the return // type to work out how many elements we need to point to. .filter(|i| !i.arguments.iter().any(|a| a.is_ptr())) .filter(|i| !i.arguments.iter().any(|a| a.ty.inner_size() == 128)) .filter(|i| !cli_options.skip.contains(&i.name)) .filter(|i| !(a32 && i.arch_tags == vec!["A64".to_string()])) .collect::>(); intrinsics.dedup(); Box::new(Self { intrinsics, cli_options, }) } fn build_c_file(&self) -> bool { let compiler = self.cli_options.cpp_compiler.as_deref(); let target = &self.cli_options.target; let cxx_toolchain_dir = self.cli_options.cxx_toolchain_dir.as_deref(); let c_target = "aarch64"; let intrinsics_name_list = write_c_testfiles( &self .intrinsics .iter() .map(|i| i as &dyn IntrinsicDefinition<_>) .collect::>(), target, c_target, &["arm_neon.h", "arm_acle.h", "arm_fp16.h"], &build_notices("// "), &[POLY128_OSTREAM_DEF], ); match compiler { None => true, Some(compiler) => compile_c_arm( intrinsics_name_list.as_slice(), compiler, target, cxx_toolchain_dir, ), } } fn build_rust_file(&self) -> bool { let rust_target = if self.cli_options.target.contains("v7") { "arm" } else { "aarch64" }; let target = &self.cli_options.target; let toolchain = self.cli_options.toolchain.as_deref(); let linker = self.cli_options.linker.as_deref(); let intrinsics_name_list = write_rust_testfiles( self.intrinsics .iter() .map(|i| i as &dyn IntrinsicDefinition<_>) .collect::>(), rust_target, &build_notices("// "), F16_FORMATTING_DEF, AARCH_CONFIGURATIONS, ); compile_rust_programs(intrinsics_name_list, toolchain, target, linker) } fn compare_outputs(&self) -> bool { if self.cli_options.toolchain.is_some() { let intrinsics_name_list = self .intrinsics .iter() .map(|i| i.name.clone()) .collect::>(); compare_outputs( &intrinsics_name_list, &self.cli_options.runner, &self.cli_options.target, ) } else { true } } }