about summary refs log tree commit diff
path: root/library/stdarch/crates
diff options
context:
space:
mode:
Diffstat (limited to 'library/stdarch/crates')
-rw-r--r--library/stdarch/crates/assert-instr-macro/src/lib.rs28
-rw-r--r--library/stdarch/crates/coresimd/Cargo.toml5
-rw-r--r--library/stdarch/crates/coresimd/src/lib.rs6
-rw-r--r--library/stdarch/crates/stdsimd-test/Cargo.toml4
-rw-r--r--library/stdarch/crates/stdsimd-test/src/lib.rs174
-rw-r--r--library/stdarch/crates/stdsimd/Cargo.toml4
-rw-r--r--library/stdarch/crates/stdsimd/src/lib.rs1
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;