From ed67655cc87dbf56c8735c6ba299aa83f6b9a1ed Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Sat, 17 Aug 2019 21:14:54 +0200 Subject: [PATCH] Verify that all intrinsics have a run-time test --- .../stdarch/crates/core_arch/src/x86/sse.rs | 4 +- .../crates/core_arch/src/x86_64/sse.rs | 2 +- .../stdarch/crates/stdarch-verify/src/lib.rs | 36 ++++- .../crates/stdarch-verify/tests/arm.rs | 150 +++++++++++++++++ .../crates/stdarch-verify/tests/mips.rs | 29 ++++ .../crates/stdarch-verify/tests/x86-intel.rs | 151 ++++++++++++++++++ 6 files changed, 366 insertions(+), 6 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/x86/sse.rs b/library/stdarch/crates/core_arch/src/x86/sse.rs index e5b1915345a6..1dcb94ef3b68 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse.rs @@ -3437,7 +3437,7 @@ mod tests { } #[simd_test(enable = "sse")] - pub unsafe fn test_mm_cvtsi32_ss() { + unsafe fn test_mm_cvtsi32_ss() { let inputs = &[ (4555i32, 4555.0f32), (322223333, 322223330.0), @@ -3455,7 +3455,7 @@ mod tests { } #[simd_test(enable = "sse")] - pub unsafe fn test_mm_cvtss_f32() { + unsafe fn test_mm_cvtss_f32() { let a = _mm_setr_ps(312.0134, 5.0, 6.0, 7.0); assert_eq!(_mm_cvtss_f32(a), 312.0134); } diff --git a/library/stdarch/crates/core_arch/src/x86_64/sse.rs b/library/stdarch/crates/core_arch/src/x86_64/sse.rs index a93215072ab1..ec09282463e2 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/sse.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/sse.rs @@ -128,7 +128,7 @@ mod tests { } #[simd_test(enable = "sse")] - pub unsafe fn test_mm_cvtsi64_ss() { + unsafe fn test_mm_cvtsi64_ss() { let inputs = &[ (4555i64, 4555.0f32), (322223333, 322223330.0), diff --git a/library/stdarch/crates/stdarch-verify/src/lib.rs b/library/stdarch/crates/stdarch-verify/src/lib.rs index cbe0530970b8..b7569fe5a2cc 100644 --- a/library/stdarch/crates/stdarch-verify/src/lib.rs +++ b/library/stdarch/crates/stdarch-verify/src/lib.rs @@ -37,14 +37,33 @@ fn functions(input: TokenStream, dirs: &[&str]) -> TokenStream { let mut functions = Vec::new(); for &mut (ref mut file, ref path) in &mut files { - for item in file.items.drain(..) { - if let syn::Item::Fn(f) = item { - functions.push((f, path)) + for mut item in file.items.drain(..) { + match item { + syn::Item::Fn(f) => functions.push((f, path)), + syn::Item::Mod(ref mut m) => { + if let Some(ref mut m) = m.content { + for i in m.1.drain(..) { + if let syn::Item::Fn(f) = i { + functions.push((f, path)) + } + } + } + } + _ => (), } } } assert!(!functions.is_empty()); + let mut tests = std::collections::HashSet::::new(); + for f in &functions { + let id = format!("{}", f.0.ident); + if id.starts_with("test_") { + tests.insert(id); + } + } + assert!(!tests.is_empty()); + functions.retain(|&(ref f, _)| { if let syn::Visibility::Public(_) = f.vis { if f.unsafety.is_some() { @@ -84,6 +103,16 @@ fn functions(input: TokenStream, dirs: &[&str]) -> TokenStream { quote! { None } }; let required_const = find_required_const(&f.attrs); + + // strip leading underscore from fn name when building a test + // _mm_foo -> mm_foo such that the test name is test_mm_foo. + let test_name_string = format!("{}", name); + let mut test_name_id = test_name_string.as_str(); + while test_name_id.starts_with('_') { + test_name_id = &test_name_id[1..]; + } + let has_test = tests.contains(&format!("test_{}", test_name_id)); + quote! { Function { name: stringify!(#name), @@ -93,6 +122,7 @@ fn functions(input: TokenStream, dirs: &[&str]) -> TokenStream { instrs: &[#(#instrs),*], file: stringify!(#path), required_const: &[#(#required_const),*], + has_test: #has_test, } } }) diff --git a/library/stdarch/crates/stdarch-verify/tests/arm.rs b/library/stdarch/crates/stdarch-verify/tests/arm.rs index 53a0ede05e0e..83ba480e07c0 100644 --- a/library/stdarch/crates/stdarch-verify/tests/arm.rs +++ b/library/stdarch/crates/stdarch-verify/tests/arm.rs @@ -18,6 +18,7 @@ struct Function { instrs: &'static [&'static str], file: &'static str, required_const: &'static [usize], + has_test: bool, } static F16: Type = Type::PrimFloat(16); @@ -197,6 +198,155 @@ fn verify_all_signatures() { let mut all_valid = true; 'outer: for rust in FUNCTIONS { + if !rust.has_test { + let skip = [ + "vaddq_s64", + "vaddq_u64", + "vrsqrte_f32", + "vtbl1_s8", + "vtbl1_u8", + "vtbl1_p8", + "vtbl2_s8", + "vtbl2_u8", + "vtbl2_p8", + "vtbl3_s8", + "vtbl3_u8", + "vtbl3_p8", + "vtbl4_s8", + "vtbl4_u8", + "vtbl4_p8", + "vtbx1_s8", + "vtbx1_u8", + "vtbx1_p8", + "vtbx2_s8", + "vtbx2_u8", + "vtbx2_p8", + "vtbx3_s8", + "vtbx3_u8", + "vtbx3_p8", + "vtbx4_s8", + "vtbx4_u8", + "vtbx4_p8", + "udf", + "_clz_u8", + "_clz_u16", + "_clz_u32", + "_rbit_u32", + "_rev_u16", + "_rev_u32", + "__breakpoint", + "vpminq_f32", + "vpminq_f64", + "vpmaxq_f32", + "vpmaxq_f64", + "vcombine_s8", + "vcombine_s16", + "vcombine_s32", + "vcombine_s64", + "vcombine_u8", + "vcombine_u16", + "vcombine_u32", + "vcombine_u64", + "vcombine_p64", + "vcombine_f32", + "vcombine_p8", + "vcombine_p16", + "vcombine_f64", + "vtbl1_s8", + "vtbl1_u8", + "vtbl1_p8", + "vtbl2_s8", + "vtbl2_u8", + "vtbl2_p8", + "vtbl3_s8", + "vtbl3_u8", + "vtbl3_p8", + "vtbl4_s8", + "vtbl4_u8", + "vtbl4_p8", + "vtbx1_s8", + "vtbx1_u8", + "vtbx1_p8", + "vtbx2_s8", + "vtbx2_u8", + "vtbx2_p8", + "vtbx3_s8", + "vtbx3_u8", + "vtbx3_p8", + "vtbx4_s8", + "vtbx4_u8", + "vtbx4_p8", + "vqtbl1_s8", + "vqtbl1q_s8", + "vqtbl1_u8", + "vqtbl1q_u8", + "vqtbl1_p8", + "vqtbl1q_p8", + "vqtbx1_s8", + "vqtbx1q_s8", + "vqtbx1_u8", + "vqtbx1q_u8", + "vqtbx1_p8", + "vqtbx1q_p8", + "vqtbl2_s8", + "vqtbl2q_s8", + "vqtbl2_u8", + "vqtbl2q_u8", + "vqtbl2_p8", + "vqtbl2q_p8", + "vqtbx2_s8", + "vqtbx2q_s8", + "vqtbx2_u8", + "vqtbx2q_u8", + "vqtbx2_p8", + "vqtbx2q_p8", + "vqtbl3_s8", + "vqtbl3q_s8", + "vqtbl3_u8", + "vqtbl3q_u8", + "vqtbl3_p8", + "vqtbl3q_p8", + "vqtbx3_s8", + "vqtbx3q_s8", + "vqtbx3_u8", + "vqtbx3q_u8", + "vqtbx3_p8", + "vqtbx3q_p8", + "vqtbl4_s8", + "vqtbl4q_s8", + "vqtbl4_u8", + "vqtbl4q_u8", + "vqtbl4_p8", + "vqtbl4q_p8", + "vqtbx4_s8", + "vqtbx4q_s8", + "vqtbx4_u8", + "vqtbx4q_u8", + "vqtbx4_p8", + "vqtbx4q_p8", + "brk", + "_rev_u64", + "_clz_u64", + "_rbit_u64", + "_cls_u32", + "_cls_u64", + ]; + if !skip.contains(&rust.name) { + println!( + "missing run-time test named `test_{}` for `{}`", + { + let mut id = rust.name; + while id.starts_with('_') { + id = &id[1..]; + } + id + }, + rust.name + ); + all_valid = false; + } + } + // Skip some intrinsics that aren't NEON and are located in different // places than the whitelists below. match rust.name { diff --git a/library/stdarch/crates/stdarch-verify/tests/mips.rs b/library/stdarch/crates/stdarch-verify/tests/mips.rs index 9dba12b95a7f..ab6637b8f200 100644 --- a/library/stdarch/crates/stdarch-verify/tests/mips.rs +++ b/library/stdarch/crates/stdarch-verify/tests/mips.rs @@ -16,6 +16,7 @@ struct Function { instrs: &'static [&'static str], file: &'static str, required_const: &'static [usize], + has_test: bool, } static F16: Type = Type::PrimFloat(16); @@ -200,6 +201,34 @@ fn verify_all_signatures() { let mut all_valid = true; for rust in FUNCTIONS { + if !rust.has_test { + let skip = [ + "__msa_ceqi_d", + "__msa_cfcmsa", + "__msa_clei_s_d", + "__msa_clti_s_d", + "__msa_ctcmsa", + "__msa_ldi_d", + "__msa_maxi_s_d", + "__msa_mini_s_d", + "break_", + ]; + if !skip.contains(&rust.name) { + println!( + "missing run-time test named `test_{}` for `{}`", + { + let mut id = rust.name; + while id.starts_with('_') { + id = &id[1..]; + } + id + }, + rust.name + ); + all_valid = false; + } + } + // Skip some intrinsics that aren't part of MSA match rust.name { "break_" => continue, diff --git a/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs b/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs index c230dac6cbae..572de603d348 100644 --- a/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs +++ b/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs @@ -27,6 +27,7 @@ struct Function { instrs: &'static [&'static str], file: &'static str, required_const: &'static [usize], + has_test: bool, } static F32: Type = Type::PrimFloat(32); @@ -140,6 +141,156 @@ fn verify_all_signatures() { let mut all_valid = true; 'outer: for rust in FUNCTIONS { + if !rust.has_test { + // FIXME: this list should be almost empty + let skip = [ + "__readeflags", + "__readeflags", + "__writeeflags", + "__writeeflags", + "_mm_comige_ss", + "_mm_cvt_ss2si", + "_mm_cvtt_ss2si", + "_mm_cvt_si2ss", + "_mm_set_ps1", + "_mm_load_ps1", + "_mm_store_ps1", + "_mm_getcsr", + "_mm_setcsr", + "_MM_GET_EXCEPTION_MASK", + "_MM_GET_EXCEPTION_STATE", + "_MM_GET_FLUSH_ZERO_MODE", + "_MM_GET_ROUNDING_MODE", + "_MM_SET_EXCEPTION_MASK", + "_MM_SET_EXCEPTION_STATE", + "_MM_SET_FLUSH_ZERO_MODE", + "_MM_SET_ROUNDING_MODE", + "_mm_prefetch", + "_mm_undefined_ps", + "_m_pmaxsw", + "_m_pmaxub", + "_m_pminsw", + "_m_pminub", + "_m_pavgb", + "_m_pavgw", + "_m_psadbw", + "_mm_cvt_pi2ps", + "_m_maskmovq", + "_m_pextrw", + "_m_pinsrw", + "_m_pmovmskb", + "_m_pshufw", + "_mm_cvtt_ps2pi", + "_mm_cvt_ps2pi", + "__cpuid_count", + "__cpuid", + "__get_cpuid_max", + "_xsave", + "_xrstor", + "_xsetbv", + "_xgetbv", + "_xsaveopt", + "_xsavec", + "_xsaves", + "_xrstors", + "_mm_bslli_si128", + "_mm_bsrli_si128", + "_mm_undefined_pd", + "_mm_undefined_si128", + "_mm_cvtps_ph", + "_mm256_cvtps_ph", + "_rdtsc", + "__rdtscp", + "_mm256_castps128_ps256", + "_mm256_castpd128_pd256", + "_mm256_castsi128_si256", + "_mm256_undefined_ps", + "_mm256_undefined_pd", + "_mm256_undefined_si256", + "_bextr2_u32", + "_mm_tzcnt_32", + "_mm512_setzero_si512", + "_mm512_setr_epi32", + "_mm512_set1_epi64", + "_m_paddb", + "_m_paddw", + "_m_paddd", + "_m_paddsb", + "_m_paddsw", + "_m_paddusb", + "_m_paddusw", + "_m_psubb", + "_m_psubw", + "_m_psubd", + "_m_psubsb", + "_m_psubsw", + "_m_psubusb", + "_m_psubusw", + "_mm_set_pi16", + "_mm_set_pi32", + "_mm_set_pi8", + "_mm_set1_pi16", + "_mm_set1_pi32", + "_mm_set1_pi8", + "_mm_setr_pi16", + "_mm_setr_pi32", + "_mm_setr_pi8", + "ud2", + "_mm_min_epi8", + "_mm_min_epi32", + "_xbegin", + "_xend", + "_rdrand16_step", + "_rdrand32_step", + "_rdseed16_step", + "_rdseed32_step", + "_fxsave", + "_fxrstor", + "_t1mskc_u64", + "_mm256_shuffle_epi32", + "_mm256_bslli_epi128", + "_mm256_bsrli_epi128", + "_mm256_unpackhi_epi8", + "_mm256_unpacklo_epi8", + "_mm256_unpackhi_epi16", + "_mm256_unpacklo_epi16", + "_mm256_unpackhi_epi32", + "_mm256_unpacklo_epi32", + "_mm256_unpackhi_epi64", + "_mm256_unpacklo_epi64", + "_xsave64", + "_xrstor64", + "_xsaveopt64", + "_xsavec64", + "_xsaves64", + "_xrstors64", + "_mm_cvtsi64x_si128", + "_mm_cvtsi128_si64x", + "_mm_cvtsi64x_sd", + "cmpxchg16b", + "_rdrand64_step", + "_rdseed64_step", + "_bextr2_u64", + "_mm_tzcnt_64", + "_fxsave64", + "_fxrstor64", + ]; + if !skip.contains(&rust.name) { + println!( + "missing run-time test named `test_{}` for `{}`", + { + let mut id = rust.name; + while id.starts_with('_') { + id = &id[1..]; + } + id + }, + rust.name + ); + all_valid = false; + } + } + match rust.name { // These aren't defined by Intel but they're defined by what appears // to be all other compilers. For more information see