diff options
Diffstat (limited to 'library/stdarch/crates')
| -rw-r--r-- | library/stdarch/crates/assert-instr-macro/src/lib.rs | 28 | ||||
| -rw-r--r-- | library/stdarch/crates/coresimd/Cargo.toml | 5 | ||||
| -rw-r--r-- | library/stdarch/crates/coresimd/src/lib.rs | 6 | ||||
| -rw-r--r-- | library/stdarch/crates/stdsimd-test/Cargo.toml | 4 | ||||
| -rw-r--r-- | library/stdarch/crates/stdsimd-test/src/lib.rs | 174 | ||||
| -rw-r--r-- | library/stdarch/crates/stdsimd/Cargo.toml | 4 | ||||
| -rw-r--r-- | library/stdarch/crates/stdsimd/src/lib.rs | 1 |
7 files changed, 180 insertions, 42 deletions
diff --git a/library/stdarch/crates/assert-instr-macro/src/lib.rs b/library/stdarch/crates/assert-instr-macro/src/lib.rs index 25b5572ad8e..e5575e85a3a 100644 --- a/library/stdarch/crates/assert-instr-macro/src/lib.rs +++ b/library/stdarch/crates/assert-instr-macro/src/lib.rs @@ -38,17 +38,9 @@ pub fn assert_instr( // testing for. let disable_assert_instr = std::env::var("STDSIMD_DISABLE_ASSERT_INSTR").is_ok(); - let maybe_ignore = if cfg!(optimized) && !disable_assert_instr { - TokenStream::new() - } else { - (quote! { #[ignore] }).into() - }; use quote::ToTokens; let instr_str = instr - .clone() - .into_token_stream() - .to_string() .replace('.', "_") .replace(|c: char| c.is_whitespace(), ""); let assert_name = syn::Ident::new( @@ -124,16 +116,22 @@ pub fn assert_instr( } }; + // If instruction tests are disabled avoid emitting this shim at all, just + // return the original item without our attribute. + if !cfg!(optimized) || disable_assert_instr { + return (quote! { #item }).into(); + } + let tts: TokenStream = quote! { - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] #[allow(non_snake_case)] - #maybe_ignore fn #assert_name() { #to_test ::stdsimd_test::assert(#shim_name as usize, stringify!(#shim_name), - stringify!(#instr)); + #instr); } }.into(); // why? necessary now to get tests to work? @@ -148,13 +146,17 @@ pub fn assert_instr( } struct Invoc { - instr: syn::Expr, + instr: String, args: Vec<(syn::Ident, syn::Expr)>, } impl syn::synom::Synom for Invoc { named!(parse -> Self, do_parse!( - instr: syn!(syn::Expr) >> + instr: alt!( + map!(syn!(syn::Ident), |s| s.to_string()) + | + map!(syn!(syn::LitStr), |s| s.value()) + ) >> args: many0!(do_parse!( syn!(syn::token::Comma) >> name: syn!(syn::Ident) >> diff --git a/library/stdarch/crates/coresimd/Cargo.toml b/library/stdarch/crates/coresimd/Cargo.toml index 5bc2e5d7ef6..dac4d916da9 100644 --- a/library/stdarch/crates/coresimd/Cargo.toml +++ b/library/stdarch/crates/coresimd/Cargo.toml @@ -22,9 +22,14 @@ maintenance = { status = "experimental" } stdsimd-test = { version = "0.*", path = "../stdsimd-test" } stdsimd = { version = "0.0.3", path = "../stdsimd" } +[target.wasm32-unknown-unknown.dev-dependencies] +wasm-bindgen-test = "0.2.16" + [features] # Internal-usage only: denies all warnings. strict = [] # Internal-usage only: enables only those intrinsics supported by Intel's # Software Development Environment (SDE). intel_sde = [] +# Enables wasm simd128 intrinsics +wasm_simd128 = [] diff --git a/library/stdarch/crates/coresimd/src/lib.rs b/library/stdarch/crates/coresimd/src/lib.rs index 1c5f185a8ad..8d892e3b475 100644 --- a/library/stdarch/crates/coresimd/src/lib.rs +++ b/library/stdarch/crates/coresimd/src/lib.rs @@ -11,6 +11,7 @@ #![allow(unused_features)] #![feature( const_fn, + const_fn_union, link_llvm_intrinsics, platform_intrinsics, repr_simd, @@ -34,7 +35,7 @@ arm_target_feature, aarch64_target_feature, mips_target_feature, - powerpc_target_feature + powerpc_target_feature, )] #![cfg_attr( test, @@ -81,6 +82,9 @@ extern crate stdsimd_test; #[cfg(test)] extern crate test; +#[cfg(all(test, target_arch = "wasm32"))] +extern crate wasm_bindgen_test; + #[path = "../../../coresimd/mod.rs"] mod coresimd; diff --git a/library/stdarch/crates/stdsimd-test/Cargo.toml b/library/stdarch/crates/stdsimd-test/Cargo.toml index e2fc6e30d35..cf459b6e049 100644 --- a/library/stdarch/crates/stdsimd-test/Cargo.toml +++ b/library/stdarch/crates/stdsimd-test/Cargo.toml @@ -10,3 +10,7 @@ backtrace = "0.3" cc = "1.0" lazy_static = "1.0" rustc-demangle = "0.1.8" +wasm-bindgen = "0.2.16" + +[features] +default = [] diff --git a/library/stdarch/crates/stdsimd-test/src/lib.rs b/library/stdarch/crates/stdsimd-test/src/lib.rs index 06d1db51369..9f563638352 100644 --- a/library/stdarch/crates/stdsimd-test/src/lib.rs +++ b/library/stdarch/crates/stdsimd-test/src/lib.rs @@ -17,12 +17,16 @@ extern crate cc; extern crate lazy_static; extern crate rustc_demangle; extern crate simd_test_macro; +extern crate wasm_bindgen; use std::collections::HashMap; use std::env; +use std::path::Path; use std::process::Command; use std::str; +use wasm_bindgen::prelude::*; + pub use assert_instr_macro::*; pub use simd_test_macro::*; @@ -32,6 +36,7 @@ lazy_static! { } struct Function { + addr: Option<usize>, instrs: Vec<Instruction>, } @@ -40,6 +45,10 @@ struct Instruction { } fn disassemble_myself() -> HashMap<String, Vec<Function>> { + if cfg!(target_arch = "wasm32") { + return parse_wasm2wat(); + } + let me = env::current_exe().expect("failed to get current exe"); if cfg!(target_arch = "x86_64") @@ -145,6 +154,7 @@ fn parse_objdump(output: &str) -> HashMap<String, Vec<Function>> { ret.entry(normalize(symbol)) .or_insert_with(Vec::new) .push(Function { + addr: None, instrs: instructions, }); } @@ -189,6 +199,7 @@ fn parse_otool(output: &str) -> HashMap<String, Vec<Function>> { ret.entry(normalize(symbol)) .or_insert_with(Vec::new) .push(Function { + addr: None, instrs: instructions, }); } @@ -239,6 +250,7 @@ fn parse_dumpbin(output: &str) -> HashMap<String, Vec<Function>> { ret.entry(normalize(symbol)) .or_insert_with(Vec::new) .push(Function { + addr: None, instrs: instructions, }); } @@ -246,6 +258,100 @@ fn parse_dumpbin(output: &str) -> HashMap<String, Vec<Function>> { ret } + +#[wasm_bindgen(module = "child_process")] +extern "C" { + #[wasm_bindgen(js_name = execSync)] + fn exec_sync(cmd: &str) -> Buffer; +} + +#[wasm_bindgen(module = "buffer")] +extern "C" { + type Buffer; + #[wasm_bindgen(method, js_name = toString)] + fn to_string(this: &Buffer) -> String; +} + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = require)] + fn resolve(module: &str) -> String; + #[wasm_bindgen(js_namespace = console, js_name = log)] + fn js_console_log(s: &str); +} + +// println! doesn't work on wasm32 right now, so shadow the compiler's println! +// macro with our own shim that redirects to `console.log`. +#[cfg(target_arch = "wasm32")] +macro_rules! println { + ($($args:tt)*) => (js_console_log(&format!($($args)*))) +} + +fn parse_wasm2wat() -> HashMap<String, Vec<Function>> { + // Our wasm module in the wasm-bindgen test harness is called + // "wasm-bindgen-test_bg". When running in node this is actually a shim JS + // file. Ask node where that JS file is, and then we use that with a wasm + // extension to find the wasm file itself. + let js_shim = resolve("wasm-bindgen-test_bg"); + let js_shim = Path::new(&js_shim).with_extension("wasm"); + + // Execute `wasm2wat` synchronously, waiting for and capturing all of its + // output. + let output = + exec_sync(&format!("wasm2wat {}", js_shim.display())).to_string(); + + let mut ret: HashMap<String, Vec<Function>> = HashMap::new(); + let mut lines = output.lines().map(|s| s.trim()); + while let Some(line) = lines.next() { + // If we found the table of function pointers, fill in the known + // address for all our `Function` instances + if line.starts_with("(elem") { + for (i, name) in line.split_whitespace().skip(3).enumerate() { + let name = name.trim_right_matches(")"); + for f in ret.get_mut(name).expect("ret.get_mut(name) failed") { + f.addr = Some(i + 1); + } + } + continue; + } + + // If this isn't a function, we don't care about it. + if !line.starts_with("(func ") { + continue; + } + + let mut function = Function { + instrs: Vec::new(), + addr: None, + }; + + // Empty functions will end in `))` so there's nothing to do, otherwise + // we'll have a bunch of following lines which are instructions. + // + // Lines that have an imbalanced `)` mark the end of a function. + if !line.ends_with("))") { + while let Some(line) = lines.next() { + function.instrs.push(Instruction { + parts: line + .split_whitespace() + .map(|s| s.to_string()) + .collect(), + }); + if !line.starts_with("(") && line.ends_with(")") { + break; + } + } + } + + // The second element here split on whitespace should be the name of + // the function, skipping the type/params/results + ret.entry(line.split_whitespace().nth(1).unwrap().to_string()) + .or_insert(Vec::new()) + .push(function); + } + return ret; +} + fn normalize(symbol: &str) -> String { let symbol = rustc_demangle::demangle(symbol).to_string(); match symbol.rfind("::h") { @@ -259,27 +365,8 @@ fn normalize(symbol: &str) -> String { /// This asserts that the function at `fnptr` contains the instruction /// `expected` provided. pub fn assert(fnptr: usize, fnname: &str, expected: &str) { - // Translate this function pointer to a symbolic name that we'd have found - // in the disassembly. - let mut sym = None; - backtrace::resolve(fnptr as *mut _, |name| { - sym = name.name().and_then(|s| s.as_str()).map(normalize); - }); - - let functions = - if let Some(s) = sym.as_ref().and_then(|s| DISASSEMBLY.get(s)) { - s - } else { - if let Some(sym) = sym { - println!("assumed symbol name: `{}`", sym); - } - println!("maybe related functions"); - for f in DISASSEMBLY.keys().filter(|k| k.contains(fnname)) { - println!("\t- {}", f); - } - panic!("failed to find disassembly of {:#x} ({})", fnptr, fnname); - }; - + let mut fnname = fnname.to_string(); + let functions = get_functions(fnptr, &mut fnname); assert_eq!(functions.len(), 1); let function = &functions[0]; @@ -362,16 +449,14 @@ pub fn assert(fnptr: usize, fnname: &str, expected: &str) { // Help debug by printing out the found disassembly, and then panic as we // didn't find the instruction. - println!( - "disassembly for {}: ", - sym.as_ref().expect("symbol not found") - ); + println!("disassembly for {}: ", fnname,); for (i, instr) in instrs.iter().enumerate() { - print!("\t{:2}: ", i); + let mut s = format!("\t{:2}: ", i); for part in &instr.parts { - print!("{} ", part); + s.push_str(part); + s.push_str(" "); } - println!(); + println!("{}", s); } if !found { @@ -394,6 +479,39 @@ pub fn assert(fnptr: usize, fnname: &str, expected: &str) { } } +fn get_functions(fnptr: usize, fnname: &mut String) -> &'static [Function] { + // Translate this function pointer to a symbolic name that we'd have found + // in the disassembly. + let mut sym = None; + backtrace::resolve(fnptr as *mut _, |name| { + sym = name.name().and_then(|s| s.as_str()).map(normalize); + }); + + if let Some(sym) = &sym { + if let Some(s) = DISASSEMBLY.get(sym) { + *fnname = sym.to_string(); + return s; + } + } + + let exact_match = DISASSEMBLY + .iter() + .find(|(_, list)| list.iter().any(|f| f.addr == Some(fnptr))); + if let Some((name, list)) = exact_match { + *fnname = name.to_string(); + return list; + } + + if let Some(sym) = sym { + println!("assumed symbol name: `{}`", sym); + } + println!("maybe related functions"); + for f in DISASSEMBLY.keys().filter(|k| k.contains(&**fnname)) { + println!("\t- {}", f); + } + panic!("failed to find disassembly of {:#x} ({})", fnptr, fnname); +} + pub fn assert_skip_test_ok(name: &str) { if env::var("STDSIMD_TEST_EVERYTHING").is_err() { return; diff --git a/library/stdarch/crates/stdsimd/Cargo.toml b/library/stdarch/crates/stdsimd/Cargo.toml index 4ab553db48e..3db3ed11879 100644 --- a/library/stdarch/crates/stdsimd/Cargo.toml +++ b/library/stdarch/crates/stdsimd/Cargo.toml @@ -37,3 +37,7 @@ path = "../../examples/hex.rs" name = "wasm" crate-type = ["cdylib"] path = "../../examples/wasm.rs" + +[features] +default = [] +wasm_simd128 = ["coresimd/wasm_simd128"] \ No newline at end of file diff --git a/library/stdarch/crates/stdsimd/src/lib.rs b/library/stdarch/crates/stdsimd/src/lib.rs index 65871cc5ebe..021dc06ae3f 100644 --- a/library/stdarch/crates/stdsimd/src/lib.rs +++ b/library/stdarch/crates/stdsimd/src/lib.rs @@ -17,6 +17,7 @@ extern crate libc; extern crate std as __do_not_use_this_import; #[cfg(test)] +#[allow(unused_imports)] #[macro_use(println, print)] extern crate std; |
