From a4f156e3be7674ed053c022c0aa191e3f392a73e Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Wed, 6 Mar 2019 09:31:28 -0800
Subject: [PATCH 1/4] Remove stray wasm file

---
 crates/core_arch/foo.wasm | Bin 252 -> 0 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100755 crates/core_arch/foo.wasm

diff --git a/crates/core_arch/foo.wasm b/crates/core_arch/foo.wasm
deleted file mode 100755
index 34e1133664981b6e34f11488c7c983052ca8d5fc..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 252
zcmY+9y-veG5QJxM?F3>8g$5}F?|?yZXeca!=<)zGoAvpuShCNNZT>1BZ^olx=xAo7
z(P;DybZ7|xotXnoH~=OgcK(g4t^+t?B8p-<kufn7){6~Kl!x$*WWs-6KF5pJwO#*d
zuo0<!S@+J4QoVXR)}5D8i^dTWk)zX-6goJjl}M?hit{BKF0_X^UlMYfIaXI}kX#`D
z3L#)UOF%Lwc#OQZjvgZXa?+*9`+P*KHjUV^>xaK3zLuB$-CRgN(%n(FwoGrU`z*`!
JrrK?vegG4HJ^%m!


From 40e6d36b8513f39829f80aa067ca7435e2f81d64 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Wed, 10 Apr 2019 16:17:39 -0700
Subject: [PATCH 2/4] Hook tests up to node.js

We can even test some of the functions!
---
 ci/docker/wasm32-unknown-unknown/Dockerfile   | 27 +++++--
 .../wasm32-unknown-unknown/wasm-entrypoint.sh | 15 ++++
 ci/run.sh                                     | 14 +++-
 crates/core_arch/Cargo.toml                   |  4 +-
 crates/core_arch/src/wasm32/simd128.rs        | 75 +++++++++++++++----
 crates/stdsimd-test/Cargo.toml                |  3 +-
 crates/stdsimd-test/src/wasm.rs               | 19 +++--
 7 files changed, 122 insertions(+), 35 deletions(-)
 create mode 100755 ci/docker/wasm32-unknown-unknown/wasm-entrypoint.sh

diff --git a/ci/docker/wasm32-unknown-unknown/Dockerfile b/ci/docker/wasm32-unknown-unknown/Dockerfile
index e385541f9c..4e84b05728 100644
--- a/ci/docker/wasm32-unknown-unknown/Dockerfile
+++ b/ci/docker/wasm32-unknown-unknown/Dockerfile
@@ -1,3 +1,18 @@
+FROM ubuntu:18.04 as node
+
+RUN apt-get update -y && apt-get install -y \
+  g++ \
+  git \
+  make \
+  python
+
+
+# Install `node`
+RUN git clone https://github.com/nodejs/node --depth 1
+WORKDIR node
+RUN ./configure --prefix=/node-install
+RUN make -j$(nproc) install
+
 FROM ubuntu:18.04
 
 RUN apt-get update -y && apt-get install -y --no-install-recommends \
@@ -16,12 +31,8 @@ RUN git clone --recursive https://github.com/WebAssembly/wabt
 RUN make -C wabt -j$(nproc)
 ENV PATH=$PATH:/wabt/bin
 
-# Install `wasm-bindgen-test-runner`
-RUN curl -L https://github.com/rustwasm/wasm-bindgen/releases/download/0.2.19/wasm-bindgen-0.2.19-x86_64-unknown-linux-musl.tar.gz \
-  | tar xzf -
-ENV PATH=$PATH:/wasm-bindgen-0.2.19-x86_64-unknown-linux-musl
-ENV CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=wasm-bindgen-test-runner
+COPY --from=node /node-install /
+ENV PATH=$PATH:/node-install/bin
 
-# Install `node`
-RUN curl https://nodejs.org/dist/v10.8.0/node-v10.8.0-linux-x64.tar.xz | tar xJf -
-ENV PATH=$PATH:/node-v10.8.0-linux-x64/bin
+COPY docker/wasm32-unknown-unknown/wasm-entrypoint.sh /wasm-entrypoint.sh
+ENTRYPOINT ["/wasm-entrypoint.sh"]
diff --git a/ci/docker/wasm32-unknown-unknown/wasm-entrypoint.sh b/ci/docker/wasm32-unknown-unknown/wasm-entrypoint.sh
new file mode 100755
index 0000000000..d2e4d42bcd
--- /dev/null
+++ b/ci/docker/wasm32-unknown-unknown/wasm-entrypoint.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+set -e
+
+# Download an appropriate version of wasm-bindgen based off of what's being used
+# in the lock file. Ideally we'd use `wasm-pack` at some point for this!
+version=$(grep -A 1 'name = "wasm-bindgen"' Cargo.lock | grep version)
+version=$(echo $version | awk '{print $3}' | sed 's/"//g')
+curl -L https://github.com/rustwasm/wasm-bindgen/releases/download/$version/wasm-bindgen-$version-x86_64-unknown-linux-musl.tar.gz \
+   | tar xzf - -C target
+export PATH=$PATH:`pwd`/target/wasm-bindgen-$version-x86_64-unknown-linux-musl
+export CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=wasm-bindgen-test-runner
+export NODE_ARGS=--experimental-wasm-simd
+
+exec "$@"
diff --git a/ci/run.sh b/ci/run.sh
index ebcbdb1ad1..529d72ac37 100755
--- a/ci/run.sh
+++ b/ci/run.sh
@@ -51,6 +51,7 @@ STD_DETECT="--manifest-path=crates/std_detect/Cargo.toml"
 STDSIMD_EXAMPLES="--manifest-path=examples/Cargo.toml"
 cargo_test "${CORE_ARCH}"
 cargo_test "${CORE_ARCH} --release"
+
 if [ "$NOSTD" != "1" ]; then
     cargo_test "${STD_DETECT}"
     cargo_test "${STD_DETECT} --release"
@@ -72,10 +73,15 @@ case ${TARGET} in
         cargo_test "--release"
         ;;
     wasm32-unknown-unknown*)
-        # There's no node or other runtime which supports the most recent SIMD
-        # proposal, but hopefully that's coming soon! For now just test that we
-        # can codegen with no LLVM faults, and we'll remove `--no-run` at a
-        # later date.
+        # Attempt to actually run some SIMD tests in node.js. Unfortunately
+        # though node.js (transitively through v8) doesn't have support for the
+        # full SIMD spec yet, only some functions. As a result only pass in
+        # some target features and a special `--cfg`
+        export RUSTFLAGS="${RUSTFLAGS} -C target-feature=+simd128 --cfg only_node_compatible_functions"
+        cargo_test "--release"
+
+        # After that passes make sure that all intrinsics compile, passing in
+        # the extra feature to compile in non-node-compatible SIMD.
         export RUSTFLAGS="${RUSTFLAGS} -C target-feature=+simd128,+unimplemented-simd128"
         cargo_test "--release --no-run"
         ;;
diff --git a/crates/core_arch/Cargo.toml b/crates/core_arch/Cargo.toml
index a1ac0ed8f1..34385520ec 100644
--- a/crates/core_arch/Cargo.toml
+++ b/crates/core_arch/Cargo.toml
@@ -29,7 +29,7 @@ stdsimd-test = { version = "0.*", path = "../stdsimd-test" }
 std_detect = { version = "0.*", path = "../std_detect" }
 
 [target.wasm32-unknown-unknown.dev-dependencies]
-wasm-bindgen-test = "=0.2.19"
+wasm-bindgen-test = "0.2.39"
 
 [package.metadata.docs.rs]
-rustdoc-args = [ "--cfg", "dox" ]
\ No newline at end of file
+rustdoc-args = [ "--cfg", "dox" ]
diff --git a/crates/core_arch/src/wasm32/simd128.rs b/crates/core_arch/src/wasm32/simd128.rs
index e853fdd599..824b70562a 100644
--- a/crates/core_arch/src/wasm32/simd128.rs
+++ b/crates/core_arch/src/wasm32/simd128.rs
@@ -164,6 +164,7 @@ pub unsafe fn v128_store(m: *mut v128, a: v128) {
 /// The `v128.const` instruction is encoded with 16 immediate bytes
 /// `imm` which provide the bits of the vector directly.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[rustc_args_required_const(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)]
 #[cfg_attr(test, assert_instr(
     v128.const,
@@ -243,6 +244,7 @@ pub unsafe fn i8x16_extract_lane(a: v128, imm: usize) -> i8 {
         unsafe { i8x16_extract_lane(a, 0) as i32 }
     }
     #[cfg(test)]
+    #[cfg(not(only_node_compatible_functions))]
     #[assert_instr(i8x16.extract_lane_u)]
     fn extract_lane_u(a: v128) -> u32 {
         unsafe { i8x16_extract_lane(a, 0) as u32 }
@@ -270,7 +272,7 @@ pub unsafe fn i8x16_replace_lane(a: v128, imm: usize, val: i8) -> v128 {
 ///
 /// Construct a vector with `x` replicated to all 8 lanes.
 #[inline]
-#[cfg_attr(test, assert_instr(i8x16.splat))]
+#[cfg_attr(test, assert_instr(i16x8.splat))]
 pub fn i16x8_splat(a: i16) -> v128 {
     unsafe { transmute(i16x8::splat(a)) }
 }
@@ -293,6 +295,7 @@ pub unsafe fn i16x8_extract_lane(a: v128, imm: usize) -> i16 {
         unsafe { i16x8_extract_lane(a, 0) as i32 }
     }
     #[cfg(test)]
+    #[cfg(not(only_node_compatible_functions))]
     #[assert_instr(i16x8.extract_lane_u)]
     fn extract_lane_u(a: v128) -> u32 {
         unsafe { i16x8_extract_lane(a, 0) as u32 }
@@ -320,7 +323,7 @@ pub unsafe fn i16x8_replace_lane(a: v128, imm: usize, val: i16) -> v128 {
 ///
 /// Constructs a vector with `x` replicated to all 4 lanes.
 #[inline]
-#[cfg_attr(test, assert_instr(i8x16.splat))]
+#[cfg_attr(test, assert_instr(i32x4.splat))]
 pub fn i32x4_splat(a: i32) -> v128 {
     unsafe { transmute(i32x4::splat(a)) }
 }
@@ -335,7 +338,7 @@ pub fn i32x4_splat(a: i32) -> v128 {
 /// This function has undefined behavior if `imm` is greater than or equal to
 /// 4.
 #[inline]
-#[cfg_attr(test, assert_instr(i32x4.extract_lane_s, imm = 0))]
+#[cfg_attr(test, assert_instr(i32x4.extract_lane, imm = 0))]
 #[rustc_args_required_const(1)]
 pub unsafe fn i32x4_extract_lane(a: v128, imm: usize) -> i32 {
     simd_extract(a.as_i32x4(), imm as u32)
@@ -361,6 +364,7 @@ pub unsafe fn i32x4_replace_lane(a: v128, imm: usize, val: i32) -> v128 {
 ///
 /// Construct a vector with `x` replicated to all 2 lanes.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i8x16.splat))]
 pub fn i64x2_splat(a: i64) -> v128 {
     unsafe { transmute(i64x2::splat(a)) }
@@ -376,6 +380,7 @@ pub fn i64x2_splat(a: i64) -> v128 {
 /// This function has undefined behavior if `imm` is greater than or equal to
 /// 2.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i64x2.extract_lane_s, imm = 0))]
 #[rustc_args_required_const(1)]
 pub unsafe fn i64x2_extract_lane(a: v128, imm: usize) -> i64 {
@@ -392,6 +397,7 @@ pub unsafe fn i64x2_extract_lane(a: v128, imm: usize) -> i64 {
 /// This function has undefined behavior if `imm` is greater than or equal to
 /// 2.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i64x2.replace_lane, imm = 0))]
 #[rustc_args_required_const(1)]
 pub unsafe fn i64x2_replace_lane(a: v128, imm: usize, val: i64) -> v128 {
@@ -402,7 +408,7 @@ pub unsafe fn i64x2_replace_lane(a: v128, imm: usize, val: i64) -> v128 {
 ///
 /// Constructs a vector with `x` replicated to all 4 lanes.
 #[inline]
-#[cfg_attr(test, assert_instr(i8x16.splat))]
+#[cfg_attr(test, assert_instr(f32x4.splat))]
 pub fn f32x4_splat(a: f32) -> v128 {
     unsafe { transmute(f32x4::splat(a)) }
 }
@@ -417,7 +423,7 @@ pub fn f32x4_splat(a: f32) -> v128 {
 /// This function has undefined behavior if `imm` is greater than or equal to
 /// 4.
 #[inline]
-#[cfg_attr(test, assert_instr(f32x4.extract_lane_s, imm = 0))]
+#[cfg_attr(test, assert_instr(f32x4.extract_lane, imm = 0))]
 #[rustc_args_required_const(1)]
 pub unsafe fn f32x4_extract_lane(a: v128, imm: usize) -> f32 {
     simd_extract(a.as_f32x4(), imm as u32)
@@ -443,7 +449,8 @@ pub unsafe fn f32x4_replace_lane(a: v128, imm: usize, val: f32) -> v128 {
 ///
 /// Constructs a vector with `x` replicated to all 2 lanes.
 #[inline]
-#[cfg_attr(test, assert_instr(i8x16.splat))]
+#[cfg(not(only_node_compatible_functions))]
+#[cfg_attr(test, assert_instr(f64x2.splat))]
 pub fn f64x2_splat(a: f64) -> v128 {
     unsafe { transmute(f64x2::splat(a)) }
 }
@@ -458,6 +465,7 @@ pub fn f64x2_splat(a: f64) -> v128 {
 /// This function has undefined behavior if `imm` is greater than or equal to
 /// 2.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.extract_lane_s, imm = 0))]
 #[rustc_args_required_const(1)]
 pub unsafe fn f64x2_extract_lane(a: v128, imm: usize) -> f64 {
@@ -474,6 +482,7 @@ pub unsafe fn f64x2_extract_lane(a: v128, imm: usize) -> f64 {
 /// This function has undefined behavior if `imm` is greater than or equal to
 /// 2.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.replace_lane, imm = 0))]
 #[rustc_args_required_const(1)]
 pub unsafe fn f64x2_replace_lane(a: v128, imm: usize, val: f64) -> v128 {
@@ -882,6 +891,7 @@ pub fn f32x4_ge(a: v128, b: v128) -> v128 {
 /// Returns a new vector where each lane is all ones if the pairwise elements
 /// were equal, or all zeros if the elements were not equal.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.eq))]
 pub fn f64x2_eq(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_eq::<_, i64x2>(a.as_f64x2(), b.as_f64x2())) }
@@ -893,6 +903,7 @@ pub fn f64x2_eq(a: v128, b: v128) -> v128 {
 /// Returns a new vector where each lane is all ones if the pairwise elements
 /// were not equal, or all zeros if the elements were equal.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.ne))]
 pub fn f64x2_ne(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_ne::<_, i64x2>(a.as_f64x2(), b.as_f64x2())) }
@@ -904,6 +915,7 @@ pub fn f64x2_ne(a: v128, b: v128) -> v128 {
 /// Returns a new vector where each lane is all ones if the pairwise left
 /// element is less than the pairwise right element, or all zeros otherwise.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.lt))]
 pub fn f64x2_lt(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_lt::<_, i64x2>(a.as_f64x2(), b.as_f64x2())) }
@@ -915,6 +927,7 @@ pub fn f64x2_lt(a: v128, b: v128) -> v128 {
 /// Returns a new vector where each lane is all ones if the pairwise left
 /// element is greater than the pairwise right element, or all zeros otherwise.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.gt))]
 pub fn f64x2_gt(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_gt::<_, i64x2>(a.as_f64x2(), b.as_f64x2())) }
@@ -926,6 +939,7 @@ pub fn f64x2_gt(a: v128, b: v128) -> v128 {
 /// Returns a new vector where each lane is all ones if the pairwise left
 /// element is less than the pairwise right element, or all zeros otherwise.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.le))]
 pub fn f64x2_le(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_le::<_, i64x2>(a.as_f64x2(), b.as_f64x2())) }
@@ -937,6 +951,7 @@ pub fn f64x2_le(a: v128, b: v128) -> v128 {
 /// Returns a new vector where each lane is all ones if the pairwise left
 /// element is greater than the pairwise right element, or all zeros otherwise.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.ge))]
 pub fn f64x2_ge(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_ge::<_, i64x2>(a.as_f64x2(), b.as_f64x2())) }
@@ -1006,6 +1021,7 @@ pub fn i8x16_all_true(a: v128) -> i32 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i8x16.shl))]
 pub fn i8x16_shl(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shl(a.as_i8x16(), i8x16::splat(amt as i8))) }
@@ -1017,6 +1033,7 @@ pub fn i8x16_shl(a: v128, amt: u32) -> v128 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i8x16.shl))]
 pub fn i8x16_shr_s(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shr(a.as_i8x16(), i8x16::splat(amt as i8))) }
@@ -1028,6 +1045,7 @@ pub fn i8x16_shr_s(a: v128, amt: u32) -> v128 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i8x16.shl))]
 pub fn i8x16_shr_u(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shr(a.as_u8x16(), u8x16::splat(amt as u8))) }
@@ -1113,6 +1131,7 @@ pub fn i16x8_all_true(a: v128) -> i32 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i16x8.shl))]
 pub fn i16x8_shl(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shl(a.as_i16x8(), i16x8::splat(amt as i16))) }
@@ -1124,6 +1143,7 @@ pub fn i16x8_shl(a: v128, amt: u32) -> v128 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i16x8.shl))]
 pub fn i16x8_shr_s(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shr(a.as_i16x8(), i16x8::splat(amt as i16))) }
@@ -1135,6 +1155,7 @@ pub fn i16x8_shr_s(a: v128, amt: u32) -> v128 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i16x8.shl))]
 pub fn i16x8_shr_u(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shr(a.as_u16x8(), u16x8::splat(amt as u16))) }
@@ -1220,6 +1241,7 @@ pub fn i32x4_all_true(a: v128) -> i32 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i32x4.shl))]
 pub fn i32x4_shl(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shl(a.as_i32x4(), i32x4::splat(amt as i32))) }
@@ -1231,6 +1253,7 @@ pub fn i32x4_shl(a: v128, amt: u32) -> v128 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i32x4.shl))]
 pub fn i32x4_shr_s(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shr(a.as_i32x4(), i32x4::splat(amt as i32))) }
@@ -1242,6 +1265,7 @@ pub fn i32x4_shr_s(a: v128, amt: u32) -> v128 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i32x4.shl))]
 pub fn i32x4_shr_u(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shr(a.as_u32x4(), u32x4::splat(amt as u32))) }
@@ -1271,6 +1295,7 @@ pub fn i32x4_mul(a: v128, b: v128) -> v128 {
 
 /// Negates a 128-bit vectors intepreted as two 64-bit signed integers
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i32x4.neg))]
 pub fn i64x2_neg(a: v128) -> v128 {
     unsafe { transmute(simd_mul(a.as_i64x2(), i64x2::splat(-1))) }
@@ -1278,6 +1303,7 @@ pub fn i64x2_neg(a: v128) -> v128 {
 
 /// Returns 1 if any lane is nonzero or 0 if all lanes are zero.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i64x2.any_true))]
 pub fn i64x2_any_true(a: v128) -> i32 {
     unsafe { llvm_i64x2_any_true(a.as_i64x2()) }
@@ -1285,6 +1311,7 @@ pub fn i64x2_any_true(a: v128) -> i32 {
 
 /// Returns 1 if all lanes are nonzero or 0 if any lane is nonzero.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i64x2.all_true))]
 pub fn i64x2_all_true(a: v128) -> i32 {
     unsafe { llvm_i64x2_all_true(a.as_i64x2()) }
@@ -1295,6 +1322,7 @@ pub fn i64x2_all_true(a: v128) -> i32 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i64x2.shl))]
 pub fn i64x2_shl(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shl(a.as_i64x2(), i64x2::splat(amt as i64))) }
@@ -1306,6 +1334,7 @@ pub fn i64x2_shl(a: v128, amt: u32) -> v128 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i64x2.shl))]
 pub fn i64x2_shr_s(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shr(a.as_i64x2(), i64x2::splat(amt as i64))) }
@@ -1317,6 +1346,7 @@ pub fn i64x2_shr_s(a: v128, amt: u32) -> v128 {
 /// Only the low bits of the shift amount are used if the shift amount is
 /// greater than the lane width.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i64x2.shl))]
 pub fn i64x2_shr_u(a: v128, amt: u32) -> v128 {
     unsafe { transmute(simd_shr(a.as_u64x2(), u64x2::splat(amt as u64))) }
@@ -1324,6 +1354,7 @@ pub fn i64x2_shr_u(a: v128, amt: u32) -> v128 {
 
 /// Adds two 128-bit vectors as if they were two packed two 64-bit integers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i64x2.add))]
 pub fn i64x2_add(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_add(a.as_i64x2(), b.as_i64x2())) }
@@ -1331,6 +1362,7 @@ pub fn i64x2_add(a: v128, b: v128) -> v128 {
 
 /// Subtracts two 128-bit vectors as if they were two packed two 64-bit integers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(i64x2.sub))]
 pub fn i64x2_sub(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_sub(a.as_i64x2(), b.as_i64x2())) }
@@ -1347,7 +1379,7 @@ pub fn f32x4_abs(a: v128) -> v128 {
 /// Negates each lane of a 128-bit vector interpreted as four 32-bit floating
 /// point numbers.
 #[inline]
-#[cfg_attr(test, assert_instr(f32x4.abs))]
+#[cfg_attr(test, assert_instr(f32x4.neg))]
 pub fn f32x4_neg(a: v128) -> v128 {
     unsafe { f32x4_mul(a, transmute(f32x4(-1.0, -1.0, -1.0, -1.0))) }
 }
@@ -1355,6 +1387,7 @@ pub fn f32x4_neg(a: v128) -> v128 {
 /// Calculates the square root of each lane of a 128-bit vector interpreted as
 /// four 32-bit floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f32x4.sqrt))]
 pub fn f32x4_sqrt(a: v128) -> v128 {
     unsafe { transmute(llvm_f32x4_sqrt(a.as_f32x4())) }
@@ -1387,6 +1420,7 @@ pub fn f32x4_mul(a: v128, b: v128) -> v128 {
 /// Divides pairwise lanes of two 128-bit vectors interpreted as four 32-bit
 /// floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f32x4.div))]
 pub fn f32x4_div(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_div(a.as_f32x4(), b.as_f32x4())) }
@@ -1411,6 +1445,7 @@ pub fn f32x4_max(a: v128, b: v128) -> v128 {
 /// Calculates the absolute value of each lane of a 128-bit vector interpreted
 /// as two 64-bit floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.abs))]
 pub fn f64x2_abs(a: v128) -> v128 {
     unsafe { transmute(llvm_f64x2_abs(a.as_f64x2())) }
@@ -1419,6 +1454,7 @@ pub fn f64x2_abs(a: v128) -> v128 {
 /// Negates each lane of a 128-bit vector interpreted as two 64-bit floating
 /// point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.abs))]
 pub fn f64x2_neg(a: v128) -> v128 {
     unsafe { f64x2_mul(a, transmute(f64x2(-1.0, -1.0))) }
@@ -1427,6 +1463,7 @@ pub fn f64x2_neg(a: v128) -> v128 {
 /// Calculates the square root of each lane of a 128-bit vector interpreted as
 /// two 64-bit floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.sqrt))]
 pub fn f64x2_sqrt(a: v128) -> v128 {
     unsafe { transmute(llvm_f64x2_sqrt(a.as_f64x2())) }
@@ -1435,6 +1472,7 @@ pub fn f64x2_sqrt(a: v128) -> v128 {
 /// Adds pairwise lanes of two 128-bit vectors interpreted as two 64-bit
 /// floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.add))]
 pub fn f64x2_add(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_add(a.as_f64x2(), b.as_f64x2())) }
@@ -1443,6 +1481,7 @@ pub fn f64x2_add(a: v128, b: v128) -> v128 {
 /// Subtracts pairwise lanes of two 128-bit vectors interpreted as two 64-bit
 /// floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.sub))]
 pub fn f64x2_sub(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_sub(a.as_f64x2(), b.as_f64x2())) }
@@ -1451,6 +1490,7 @@ pub fn f64x2_sub(a: v128, b: v128) -> v128 {
 /// Multiplies pairwise lanes of two 128-bit vectors interpreted as two 64-bit
 /// floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.mul))]
 pub fn f64x2_mul(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_mul(a.as_f64x2(), b.as_f64x2())) }
@@ -1459,6 +1499,7 @@ pub fn f64x2_mul(a: v128, b: v128) -> v128 {
 /// Divides pairwise lanes of two 128-bit vectors interpreted as two 64-bit
 /// floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.div))]
 pub fn f64x2_div(a: v128, b: v128) -> v128 {
     unsafe { transmute(simd_div(a.as_f64x2(), b.as_f64x2())) }
@@ -1467,6 +1508,7 @@ pub fn f64x2_div(a: v128, b: v128) -> v128 {
 /// Calculates the minimum of pairwise lanes of two 128-bit vectors interpreted
 /// as two 64-bit floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.min))]
 pub fn f64x2_min(a: v128, b: v128) -> v128 {
     unsafe { transmute(llvm_f64x2_min(a.as_f64x2(), b.as_f64x2())) }
@@ -1475,6 +1517,7 @@ pub fn f64x2_min(a: v128, b: v128) -> v128 {
 /// Calculates the maximum of pairwise lanes of two 128-bit vectors interpreted
 /// as two 64-bit floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr(f64x2.max))]
 pub fn f64x2_max(a: v128, b: v128) -> v128 {
     unsafe { transmute(llvm_f64x2_max(a.as_f64x2(), b.as_f64x2())) }
@@ -1486,7 +1529,7 @@ pub fn f64x2_max(a: v128, b: v128) -> v128 {
 /// NaN is converted to 0 and if it's out of bounds it becomes the nearest
 /// representable intger.
 #[inline]
-#[cfg_attr(test, assert_instr("i32x4.trunc_s/f32x4:sat"))]
+#[cfg_attr(test, assert_instr("i32x4.trunc_sat_f32x4_s"))]
 pub fn i32x4_trunc_s_f32x4_sat(a: v128) -> v128 {
     unsafe { transmute(simd_cast::<_, i32x4>(a.as_f32x4())) }
 }
@@ -1497,7 +1540,7 @@ pub fn i32x4_trunc_s_f32x4_sat(a: v128) -> v128 {
 /// NaN is converted to 0 and if it's out of bounds it becomes the nearest
 /// representable intger.
 #[inline]
-#[cfg_attr(test, assert_instr("i32x4.trunc_u/f32x4:sat"))]
+#[cfg_attr(test, assert_instr("i32x4.trunc_sat_f32x4_u"))]
 pub fn i32x4_trunc_u_f32x4_sat(a: v128) -> v128 {
     unsafe { transmute(simd_cast::<_, u32x4>(a.as_f32x4())) }
 }
@@ -1508,7 +1551,8 @@ pub fn i32x4_trunc_u_f32x4_sat(a: v128) -> v128 {
 /// NaN is converted to 0 and if it's out of bounds it becomes the nearest
 /// representable intger.
 #[inline]
-#[cfg_attr(test, assert_instr("i32x4.trunc_s/f32x4:sat"))]
+#[cfg(not(only_node_compatible_functions))]
+#[cfg_attr(test, assert_instr("i64x2.trunc_s/f64x2:sat"))]
 pub fn i64x2_trunc_s_f64x2_sat(a: v128) -> v128 {
     unsafe { transmute(simd_cast::<_, i64x2>(a.as_f64x2())) }
 }
@@ -1519,6 +1563,7 @@ pub fn i64x2_trunc_s_f64x2_sat(a: v128) -> v128 {
 /// NaN is converted to 0 and if it's out of bounds it becomes the nearest
 /// representable intger.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr("i64x2.trunc_u/f64x2:sat"))]
 pub fn i64x2_trunc_u_f64x2_sat(a: v128) -> v128 {
     unsafe { transmute(simd_cast::<_, u64x2>(a.as_f64x2())) }
@@ -1527,22 +1572,23 @@ pub fn i64x2_trunc_u_f64x2_sat(a: v128) -> v128 {
 /// Converts a 128-bit vector interpreted as four 32-bit signed integers into a
 /// 128-bit vector of four 32-bit floating point numbers.
 #[inline]
-#[cfg_attr(test, assert_instr("f32x4.convert_s/i32x4"))]
-pub fn f32x4_convert_s_i32x4(a: v128) -> v128 {
+#[cfg_attr(test, assert_instr("f32x4.convert_i32x4_s"))]
+pub fn f32x4_convert_i32x4_s(a: v128) -> v128 {
     unsafe { transmute(simd_cast::<_, f32x4>(a.as_i32x4())) }
 }
 
 /// Converts a 128-bit vector interpreted as four 32-bit unsigned integers into a
 /// 128-bit vector of four 32-bit floating point numbers.
 #[inline]
-#[cfg_attr(test, assert_instr("f32x4.convert_u/i32x4"))]
-pub fn f32x4_convert_u_i32x4(a: v128) -> v128 {
+#[cfg_attr(test, assert_instr("f32x4.convert_i32x4_u"))]
+pub fn f32x4_convert_i32x4_u(a: v128) -> v128 {
     unsafe { transmute(simd_cast::<_, f32x4>(a.as_u32x4())) }
 }
 
 /// Converts a 128-bit vector interpreted as two 64-bit signed integers into a
 /// 128-bit vector of two 64-bit floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr("f64x2.convert_s/i64x2"))]
 pub fn f64x2_convert_s_i64x2(a: v128) -> v128 {
     unsafe { transmute(simd_cast::<_, f64x2>(a.as_i64x2())) }
@@ -1551,6 +1597,7 @@ pub fn f64x2_convert_s_i64x2(a: v128) -> v128 {
 /// Converts a 128-bit vector interpreted as two 64-bit unsigned integers into a
 /// 128-bit vector of two 64-bit floating point numbers.
 #[inline]
+#[cfg(not(only_node_compatible_functions))]
 #[cfg_attr(test, assert_instr("f64x2.convert_u/i64x2"))]
 pub fn f64x2_convert_u_i64x2(a: v128) -> v128 {
     unsafe { transmute(simd_cast::<_, f64x2>(a.as_u64x2())) }
diff --git a/crates/stdsimd-test/Cargo.toml b/crates/stdsimd-test/Cargo.toml
index 60b0b72ef8..df7ee0f7f0 100644
--- a/crates/stdsimd-test/Cargo.toml
+++ b/crates/stdsimd-test/Cargo.toml
@@ -13,7 +13,8 @@ rustc-demangle = "0.1.8"
 cfg-if = "0.1"
 
 [target.wasm32-unknown-unknown.dependencies]
-wasm-bindgen = "=0.2.19"
+wasm-bindgen = "0.2.39"
+js-sys = "0.3"
 console_error_panic_hook = "0.1"
 
 [features]
diff --git a/crates/stdsimd-test/src/wasm.rs b/crates/stdsimd-test/src/wasm.rs
index 5d12484956..16d775b2d5 100644
--- a/crates/stdsimd-test/src/wasm.rs
+++ b/crates/stdsimd-test/src/wasm.rs
@@ -1,12 +1,13 @@
 //! Disassembly calling function for `wasm32` targets.
 use wasm_bindgen::prelude::*;
 
-use ::*;
+use crate::{Function, Instruction};
+use std::collections::HashMap;
 
 #[wasm_bindgen(module = "child_process")]
 extern "C" {
-    #[wasm_bindgen(js_name = execSync)]
-    fn exec_sync(cmd: &str) -> Buffer;
+    #[wasm_bindgen(js_name = execFileSync)]
+    fn exec_file_sync(cmd: &str, args: &js_sys::Array, opts: &js_sys::Object) -> Buffer;
 }
 
 #[wasm_bindgen(module = "buffer")]
@@ -35,9 +36,15 @@ pub(crate) fn disassemble_myself() -> HashMap<String, Vec<Function>> {
     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();
+    // output. Note that we pass in a custom `maxBuffer` parameter because we're
+    // generating a ton of output that needs to be buffered.
+    let args = js_sys::Array::new();
+    args.push(&js_shim.display().to_string().into());
+    args.push(&"--enable-simd".into());
+    let opts = js_sys::Object::new();
+    js_sys::Reflect::set(&opts, &"maxBuffer".into(), &(200 * 1024 * 1024).into())
+        .unwrap();
+    let output = exec_file_sync("wasm2wat", &args, &opts).to_string();
 
     let mut ret: HashMap<String, Vec<Function>> = HashMap::new();
     let mut lines = output.lines().map(|s| s.trim());

From 404ebf1270bc0d94fd64e87051ff4ed566d71bcd Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Thu, 11 Apr 2019 12:11:14 -0700
Subject: [PATCH 3/4] Enabling a bunch of tests

---
 crates/core_arch/src/wasm32/simd128.rs | 1318 +++++++++++++-----------
 1 file changed, 729 insertions(+), 589 deletions(-)

diff --git a/crates/core_arch/src/wasm32/simd128.rs b/crates/core_arch/src/wasm32/simd128.rs
index 824b70562a..7bf579f38e 100644
--- a/crates/core_arch/src/wasm32/simd128.rs
+++ b/crates/core_arch/src/wasm32/simd128.rs
@@ -1603,592 +1603,732 @@ pub fn f64x2_convert_u_i64x2(a: v128) -> v128 {
     unsafe { transmute(simd_cast::<_, f64x2>(a.as_u64x2())) }
 }
 
-// #[cfg(test)]
-// pub mod tests {
-//     use super::*;
-//     use std;
-//     use std::mem;
-//     use std::prelude::v1::*;
-//     use wasm_bindgen_test::*;
-//
-//     fn compare_bytes(a: v128, b: v128) {
-//         let a: [u8; 16] = unsafe { transmute(a) };
-//         let b: [u8; 16] = unsafe { transmute(b) };
-//         assert_eq!(a, b);
-//     }
-//
-//     #[wasm_bindgen_test]
-//     fn v128_const() {
-//         const A: v128 = unsafe {
-//             v128::const_([
-//                 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
-//             ])
-//         };
-//         compare_bytes(A, A);
-//     }
-//
-//     macro_rules! test_splat {
-//         ($test_id:ident: $id:ident($val:expr) => $($vals:expr),*) => {
-//             #[wasm_bindgen_test]
-//             fn $test_id() {
-//                 const A: v128 = unsafe {
-//                     $id::splat($val)
-//                 };
-//                 const B: v128 = unsafe {
-//                     v128::const_([$($vals),*])
-//                 };
-//                 compare_bytes(A, B);
-//             }
-//         }
-//     }
-//
-//     test_splat!(i8x16_splat: i8x16(42) => 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42);
-//     test_splat!(i16x8_splat: i16x8(42) => 42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0);
-//     test_splat!(i32x4_splat: i32x4(42) => 42, 0, 0, 0, 42, 0, 0, 0, 42, 0, 0, 0, 42, 0, 0, 0);
-//     test_splat!(i64x2_splat: i64x2(42) => 42, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0);
-//     test_splat!(f32x4_splat: f32x4(42.) => 0, 0, 40, 66, 0, 0, 40, 66, 0, 0, 40, 66, 0, 0, 40, 66);
-//     test_splat!(f64x2_splat: f64x2(42.) => 0, 0, 0, 0, 0, 0, 69, 64, 0, 0, 0, 0, 0, 0, 69, 64);
-//
-//     // tests extract and replace lanes
-//     macro_rules! test_extract {
-//         ($test_id:ident: $id:ident[$ety:ident] => $extract_fn:ident | [$val:expr; $count:expr]
-//          | [$($vals:expr),*] => ($other:expr)
-//          | $($ids:expr),*) => {
-//             #[wasm_bindgen_test]
-//             fn $test_id() {
-//                 unsafe {
-//                     // splat vector and check that all indices contain the same value
-//                     // splatted:
-//                     const A: v128 = unsafe {
-//                         $id::splat($val)
-//                     };
-//                     $(
-//                         assert_eq!($id::$extract_fn(A, $ids) as $ety, $val);
-//                     )*;
-//
-//                     // create a vector from array and check that the indices contain
-//                     // the same values as in the array:
-//                     let arr: [$ety; $count] = [$($vals),*];
-//                     let mut vec: v128 = transmute(arr);
-//                     $(
-//                         assert_eq!($id::$extract_fn(vec, $ids) as $ety, arr[$ids]);
-//                     )*;
-//
-//                     // replace lane 0 with another value
-//                     vec = $id::replace_lane(vec, 0, $other);
-//                     assert_ne!($id::$extract_fn(vec, 0) as $ety, arr[0]);
-//                     assert_eq!($id::$extract_fn(vec, 0) as $ety, $other);
-//                 }
-//             }
-//         }
-//     }
-//
-//     test_extract!(i8x16_extract_u: i8x16[u8] => extract_lane_u | [255; 16]
-//                   | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] => (42)
-//                   | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
-//     );
-//     test_extract!(i8x16_extract_s: i8x16[i8] => extract_lane_s | [-122; 16]
-//                   | [0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12, -13, 14, -15] => (-42)
-//                   | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
-//     );
-//
-//     test_extract!(i16x8_extract_u: i16x8[u16] => extract_lane_u | [255; 8]
-//                   | [0, 1, 2, 3, 4, 5, 6, 7]  => (42) | 0, 1, 2, 3, 4, 5, 6, 7
-//     );
-//     test_extract!(i16x8_extract_s: i16x8[i16] => extract_lane_s | [-122; 8]
-//                   | [0, -1, 2, -3, 4, -5, 6, -7]  => (-42) | 0, 1, 2, 3, 4, 5, 6, 7
-//     );
-//     test_extract!(i32x4_extract: i32x4[i32] => extract_lane | [-122; 4]
-//                   | [0, -1, 2, -3]  => (42) | 0, 1, 2, 3
-//     );
-//     test_extract!(i64x2_extract: i64x2[i64] => extract_lane | [-122; 2]
-//                   | [0, -1]  => (42) | 0, 1
-//     );
-//     test_extract!(f32x4_extract: f32x4[f32] => extract_lane | [-122.; 4]
-//                   | [0., -1., 2., -3.]  => (42.) | 0, 1, 2, 3
-//     );
-//     test_extract!(f64x2_extract: f64x2[f64] => extract_lane | [-122.; 2]
-//                   | [0., -1.]  => (42.) | 0, 1
-//     );
-//
-//     #[wasm_bindgen_test]
-//     fn v8x16_shuffle() {
-//         unsafe {
-//             let a = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
-//             let b = [
-//                 16_u8, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
-//                 31,
-//             ];
-//
-//             let vec_a: v128 = transmute(a);
-//             let vec_b: v128 = transmute(b);
-//
-//             let vec_r = v8x16_shuffle!(
-//                 vec_a,
-//                 vec_b,
-//                 [0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30]
-//             );
-//
-//             let e =
-//                 [0_u8, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30];
-//             let vec_e: v128 = transmute(e);
-//             compare_bytes(vec_r, vec_e);
-//         }
-//     }
-//
-//     macro_rules! floating_point {
-//         (f32) => {
-//             true
-//         };
-//         (f64) => {
-//             true
-//         };
-//         ($id:ident) => {
-//             false
-//         };
-//     }
-//
-//     trait IsNan: Sized {
-//         fn is_nan(self) -> bool {
-//             false
-//         }
-//     }
-//     impl IsNan for i8 {}
-//     impl IsNan for i16 {}
-//     impl IsNan for i32 {}
-//     impl IsNan for i64 {}
-//
-//     macro_rules! test_bop {
-//         ($id:ident[$ety:ident; $ecount:expr] |
-//          $binary_op:ident [$op_test_id:ident] :
-//          ([$($in_a:expr),*], [$($in_b:expr),*]) => [$($out:expr),*]) => {
-//             test_bop!(
-//                 $id[$ety; $ecount] => $ety | $binary_op [ $op_test_id ]:
-//                 ([$($in_a),*], [$($in_b),*]) => [$($out),*]
-//             );
-//
-//         };
-//         ($id:ident[$ety:ident; $ecount:expr] => $oty:ident |
-//          $binary_op:ident [$op_test_id:ident] :
-//          ([$($in_a:expr),*], [$($in_b:expr),*]) => [$($out:expr),*]) => {
-//             #[wasm_bindgen_test]
-//             fn $op_test_id() {
-//                 unsafe {
-//                     let a_input: [$ety; $ecount] = [$($in_a),*];
-//                     let b_input: [$ety; $ecount] = [$($in_b),*];
-//                     let output: [$oty; $ecount] = [$($out),*];
-//
-//                     let a_vec_in: v128 = transmute(a_input);
-//                     let b_vec_in: v128 = transmute(b_input);
-//                     let vec_res: v128 = $id::$binary_op(a_vec_in, b_vec_in);
-//
-//                     let res: [$oty; $ecount] = transmute(vec_res);
-//
-//                     if !floating_point!($ety) {
-//                         assert_eq!(res, output);
-//                     } else {
-//                         for i in 0..$ecount {
-//                             let r = res[i];
-//                             let o = output[i];
-//                             assert_eq!(r.is_nan(), o.is_nan());
-//                             if !r.is_nan() {
-//                                 assert_eq!(r, o);
-//                             }
-//                         }
-//                     }
-//                 }
-//             }
-//         }
-//     }
-//
-//     macro_rules! test_bops {
-//         ($id:ident[$ety:ident; $ecount:expr] |
-//          $binary_op:ident [$op_test_id:ident]:
-//          ([$($in_a:expr),*], $in_b:expr) => [$($out:expr),*]) => {
-//             #[wasm_bindgen_test]
-//             fn $op_test_id() {
-//                 unsafe {
-//                     let a_input: [$ety; $ecount] = [$($in_a),*];
-//                     let output: [$ety; $ecount] = [$($out),*];
-//
-//                     let a_vec_in: v128 = transmute(a_input);
-//                     let vec_res: v128 = $id::$binary_op(a_vec_in, $in_b);
-//
-//                     let res: [$ety; $ecount] = transmute(vec_res);
-//                     assert_eq!(res, output);
-//                 }
-//             }
-//         }
-//     }
-//
-//     macro_rules! test_uop {
-//         ($id:ident[$ety:ident; $ecount:expr] |
-//          $unary_op:ident [$op_test_id:ident]: [$($in_a:expr),*] => [$($out:expr),*]) => {
-//             #[wasm_bindgen_test]
-//             fn $op_test_id() {
-//                 unsafe {
-//                     let a_input: [$ety; $ecount] = [$($in_a),*];
-//                     let output: [$ety; $ecount] = [$($out),*];
-//
-//                     let a_vec_in: v128 = transmute(a_input);
-//                     let vec_res: v128 = $id::$unary_op(a_vec_in);
-//
-//                     let res: [$ety; $ecount] = transmute(vec_res);
-//                     assert_eq!(res, output);
-//                 }
-//             }
-//         }
-//     }
-//
-//     test_bop!(i8x16[i8; 16] | add[i8x16_add_test]:
-//               ([0, -1, 2, 3, 4, 5, 6, i8::max_value(), 1, 1, 1, 1, 1, 1, 1, 1],
-//                [8, i8::min_value(), 10, 11, 12, 13, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1]) =>
-//               [8, i8::max_value(), 12, 14, 16, 18, 20, i8::min_value(), 2, 2, 2, 2, 2, 2, 2, 2]);
-//     test_bop!(i8x16[i8; 16] | sub[i8x16_sub_test]:
-//               ([0, -1, 2, 3, 4, 5, 6, -1, 1, 1, 1, 1, 1, 1, 1, 1],
-//                [8, i8::min_value(), 10, 11, 12, 13, 14, i8::max_value(), 1, 1, 1, 1, 1, 1, 1, 1]) =>
-//               [-8, i8::max_value(), -8, -8, -8, -8, -8, i8::min_value(), 0, 0, 0, 0, 0, 0, 0, 0]);
-//     test_bop!(i8x16[i8; 16] | mul[i8x16_mul_test]:
-//               ([0, -2, 2, 3, 4, 5, 6, 2, 1, 1, 1, 1, 1, 1, 1, 1],
-//                [8, i8::min_value(), 10, 11, 12, 13, 14, i8::max_value(), 1, 1, 1, 1, 1, 1, 1, 1]) =>
-//               [0, 0, 20, 33, 48, 65, 84, -2, 1, 1, 1, 1, 1, 1, 1, 1]);
-//     test_uop!(i8x16[i8; 16] | neg[i8x16_neg_test]:
-//               [8, i8::min_value(), 10, 11, 12, 13, 14, i8::max_value(), 1, 1, 1, 1, 1, 1, 1, 1] =>
-//               [-8, i8::min_value(), -10, -11, -12, -13, -14, i8::min_value() + 1, -1, -1, -1, -1, -1, -1, -1, -1]);
-//
-//     test_bop!(i16x8[i16; 8] | add[i16x8_add_test]:
-//               ([0, -1, 2, 3, 4, 5, 6, i16::max_value()],
-//                [8, i16::min_value(), 10, 11, 12, 13, 14, 1]) =>
-//               [8, i16::max_value(), 12, 14, 16, 18, 20, i16::min_value()]);
-//     test_bop!(i16x8[i16; 8] | sub[i16x8_sub_test]:
-//               ([0, -1, 2, 3, 4, 5, 6, -1],
-//                [8, i16::min_value(), 10, 11, 12, 13, 14, i16::max_value()]) =>
-//               [-8, i16::max_value(), -8, -8, -8, -8, -8, i16::min_value()]);
-//     test_bop!(i16x8[i16; 8] | mul[i16x8_mul_test]:
-//               ([0, -2, 2, 3, 4, 5, 6, 2],
-//                [8, i16::min_value(), 10, 11, 12, 13, 14, i16::max_value()]) =>
-//               [0, 0, 20, 33, 48, 65, 84, -2]);
-//     test_uop!(i16x8[i16; 8] | neg[i16x8_neg_test]:
-//               [8, i16::min_value(), 10, 11, 12, 13, 14, i16::max_value()] =>
-//               [-8, i16::min_value(), -10, -11, -12, -13, -14, i16::min_value() + 1]);
-//
-//     test_bop!(i32x4[i32; 4] | add[i32x4_add_test]:
-//               ([0, -1, 2, i32::max_value()],
-//                [8, i32::min_value(), 10, 1]) =>
-//               [8, i32::max_value(), 12, i32::min_value()]);
-//     test_bop!(i32x4[i32; 4] | sub[i32x4_sub_test]:
-//               ([0, -1, 2, -1],
-//                [8, i32::min_value(), 10, i32::max_value()]) =>
-//               [-8, i32::max_value(), -8, i32::min_value()]);
-//     test_bop!(i32x4[i32; 4] | mul[i32x4_mul_test]:
-//               ([0, -2, 2, 2],
-//                [8, i32::min_value(), 10, i32::max_value()]) =>
-//               [0, 0, 20, -2]);
-//     test_uop!(i32x4[i32; 4] | neg[i32x4_neg_test]:
-//               [8, i32::min_value(), 10, i32::max_value()] =>
-//               [-8, i32::min_value(), -10, i32::min_value() + 1]);
-//
-//     test_bop!(i64x2[i64; 2] | add[i64x2_add_test]:
-//               ([-1, i64::max_value()],
-//                [i64::min_value(), 1]) =>
-//               [i64::max_value(), i64::min_value()]);
-//     test_bop!(i64x2[i64; 2] | sub[i64x2_sub_test]:
-//               ([-1, -1],
-//                [i64::min_value(), i64::max_value()]) =>
-//               [ i64::max_value(), i64::min_value()]);
-//     // note: mul for i64x2 is not part of the spec
-//     test_uop!(i64x2[i64; 2] | neg[i64x2_neg_test]:
-//               [i64::min_value(), i64::max_value()] =>
-//               [i64::min_value(), i64::min_value() + 1]);
-//
-//     test_bops!(i8x16[i8; 16] | shl[i8x16_shl_test]:
-//                ([0, -1, 2, 3, 4, 5, 6, i8::max_value(), 1, 1, 1, 1, 1, 1, 1, 1], 1) =>
-//                [0, -2, 4, 6, 8, 10, 12, -2, 2, 2, 2, 2, 2, 2, 2, 2]);
-//     test_bops!(i16x8[i16; 8] | shl[i16x8_shl_test]:
-//                ([0, -1, 2, 3, 4, 5, 6, i16::max_value()], 1) =>
-//                [0, -2, 4, 6, 8, 10, 12, -2]);
-//     test_bops!(i32x4[i32; 4] | shl[i32x4_shl_test]:
-//                ([0, -1, 2, 3], 1) => [0, -2, 4, 6]);
-//     test_bops!(i64x2[i64; 2] | shl[i64x2_shl_test]:
-//                ([0, -1], 1) => [0, -2]);
-//
-//     test_bops!(i8x16[i8; 16] | shr_s[i8x16_shr_s_test]:
-//                ([0, -1, 2, 3, 4, 5, 6, i8::max_value(), 1, 1, 1, 1, 1, 1, 1, 1], 1) =>
-//                [0, -1, 1, 1, 2, 2, 3, 63, 0, 0, 0, 0, 0, 0, 0, 0]);
-//     test_bops!(i16x8[i16; 8] | shr_s[i16x8_shr_s_test]:
-//                ([0, -1, 2, 3, 4, 5, 6, i16::max_value()], 1) =>
-//                [0, -1, 1, 1, 2, 2, 3, i16::max_value() / 2]);
-//     test_bops!(i32x4[i32; 4] | shr_s[i32x4_shr_s_test]:
-//                ([0, -1, 2, 3], 1) => [0, -1, 1, 1]);
-//     test_bops!(i64x2[i64; 2] | shr_s[i64x2_shr_s_test]:
-//                ([0, -1], 1) => [0, -1]);
-//
-//     test_bops!(i8x16[i8; 16] | shr_u[i8x16_uhr_u_test]:
-//                ([0, -1, 2, 3, 4, 5, 6, i8::max_value(), 1, 1, 1, 1, 1, 1, 1, 1], 1) =>
-//                [0, i8::max_value(), 1, 1, 2, 2, 3, 63, 0, 0, 0, 0, 0, 0, 0, 0]);
-//     test_bops!(i16x8[i16; 8] | shr_u[i16x8_uhr_u_test]:
-//                ([0, -1, 2, 3, 4, 5, 6, i16::max_value()], 1) =>
-//                [0, i16::max_value(), 1, 1, 2, 2, 3, i16::max_value() / 2]);
-//     test_bops!(i32x4[i32; 4] | shr_u[i32x4_uhr_u_test]:
-//                ([0, -1, 2, 3], 1) => [0, i32::max_value(), 1, 1]);
-//     test_bops!(i64x2[i64; 2] | shr_u[i64x2_uhr_u_test]:
-//                ([0, -1], 1) => [0, i64::max_value()]);
-//
-//     #[wasm_bindgen_test]
-//     fn v128_bitwise_logical_ops() {
-//         unsafe {
-//             let a: [u32; 4] = [u32::max_value(), 0, u32::max_value(), 0];
-//             let b: [u32; 4] = [u32::max_value(); 4];
-//             let c: [u32; 4] = [0; 4];
-//
-//             let vec_a: v128 = transmute(a);
-//             let vec_b: v128 = transmute(b);
-//             let vec_c: v128 = transmute(c);
-//
-//             let r: v128 = v128::and(vec_a, vec_a);
-//             compare_bytes(r, vec_a);
-//             let r: v128 = v128::and(vec_a, vec_b);
-//             compare_bytes(r, vec_a);
-//             let r: v128 = v128::or(vec_a, vec_b);
-//             compare_bytes(r, vec_b);
-//             let r: v128 = v128::not(vec_b);
-//             compare_bytes(r, vec_c);
-//             let r: v128 = v128::xor(vec_a, vec_c);
-//             compare_bytes(r, vec_a);
-//
-//             let r: v128 = v128::bitselect(vec_b, vec_c, vec_b);
-//             compare_bytes(r, vec_b);
-//             let r: v128 = v128::bitselect(vec_b, vec_c, vec_c);
-//             compare_bytes(r, vec_c);
-//             let r: v128 = v128::bitselect(vec_b, vec_c, vec_a);
-//             compare_bytes(r, vec_a);
-//         }
-//     }
-//
-//     macro_rules! test_bool_red {
-//         ($id:ident[$test_id:ident] | [$($true:expr),*] | [$($false:expr),*] | [$($alt:expr),*]) => {
-//             #[wasm_bindgen_test]
-//             fn $test_id() {
-//                 unsafe {
-//                     let vec_a: v128 = transmute([$($true),*]); // true
-//                     let vec_b: v128 = transmute([$($false),*]); // false
-//                     let vec_c: v128 = transmute([$($alt),*]); // alternating
-//
-//                     assert_eq!($id::any_true(vec_a), 1);
-//                     assert_eq!($id::any_true(vec_b), 0);
-//                     assert_eq!($id::any_true(vec_c), 1);
-//
-//                     assert_eq!($id::all_true(vec_a), 1);
-//                     assert_eq!($id::all_true(vec_b), 0);
-//                     assert_eq!($id::all_true(vec_c), 0);
-//                 }
-//             }
-//         }
-//     }
-//
-//     test_bool_red!(
-//         i8x16[i8x16_boolean_reductions]
-//             | [1_i8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
-//             | [0_i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
-//             | [1_i8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
-//     );
-//     test_bool_red!(
-//         i16x8[i16x8_boolean_reductions]
-//             | [1_i16, 1, 1, 1, 1, 1, 1, 1]
-//             | [0_i16, 0, 0, 0, 0, 0, 0, 0]
-//             | [1_i16, 0, 1, 0, 1, 0, 1, 0]
-//     );
-//     test_bool_red!(
-//         i32x4[i32x4_boolean_reductions]
-//             | [1_i32, 1, 1, 1]
-//             | [0_i32, 0, 0, 0]
-//             | [1_i32, 0, 1, 0]
-//     );
-//     test_bool_red!(
-//         i64x2[i64x2_boolean_reductions] | [1_i64, 1] | [0_i64, 0] | [1_i64, 0]
-//     );
-//
-//     test_bop!(i8x16[i8; 16] | eq[i8x16_eq_test]:
-//               ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
-//                [0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15]) =>
-//               [-1, 0, -1, 0 ,-1, 0, -1, -1, -1, 0, -1, 0 ,-1, 0, -1, -1]);
-//     test_bop!(i16x8[i16; 8] | eq[i16x8_eq_test]:
-//               ([0, 1, 2, 3, 4, 5, 6, 7], [0, 2, 2, 4, 4, 6, 6, 7]) =>
-//               [-1, 0, -1, 0 ,-1, 0, -1, -1]);
-//     test_bop!(i32x4[i32; 4] | eq[i32x4_eq_test]:
-//               ([0, 1, 2, 3], [0, 2, 2, 4]) => [-1, 0, -1, 0]);
-//     test_bop!(i64x2[i64; 2] | eq[i64x2_eq_test]: ([0, 1], [0, 2]) => [-1, 0]);
-//     test_bop!(f32x4[f32; 4] => i32 | eq[f32x4_eq_test]:
-//               ([0., 1., 2., 3.], [0., 2., 2., 4.]) => [-1, 0, -1, 0]);
-//     test_bop!(f64x2[f64; 2] => i64 | eq[f64x2_eq_test]: ([0., 1.], [0., 2.]) => [-1, 0]);
-//
-//     test_bop!(i8x16[i8; 16] | ne[i8x16_ne_test]:
-//               ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
-//                [0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15]) =>
-//               [0, -1, 0, -1 ,0, -1, 0, 0, 0, -1, 0, -1 ,0, -1, 0, 0]);
-//     test_bop!(i16x8[i16; 8] | ne[i16x8_ne_test]:
-//               ([0, 1, 2, 3, 4, 5, 6, 7], [0, 2, 2, 4, 4, 6, 6, 7]) =>
-//               [0, -1, 0, -1 ,0, -1, 0, 0]);
-//     test_bop!(i32x4[i32; 4] | ne[i32x4_ne_test]:
-//               ([0, 1, 2, 3], [0, 2, 2, 4]) => [0, -1, 0, -1]);
-//     test_bop!(i64x2[i64; 2] | ne[i64x2_ne_test]: ([0, 1], [0, 2]) => [0, -1]);
-//     test_bop!(f32x4[f32; 4] => i32 | ne[f32x4_ne_test]:
-//               ([0., 1., 2., 3.], [0., 2., 2., 4.]) => [0, -1, 0, -1]);
-//     test_bop!(f64x2[f64; 2] => i64 | ne[f64x2_ne_test]: ([0., 1.], [0., 2.]) => [0, -1]);
-//
-//     test_bop!(i8x16[i8; 16] | lt[i8x16_lt_test]:
-//               ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
-//                [0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15]) =>
-//               [0, -1, 0, -1 ,0, -1, 0, 0, 0, -1, 0, -1 ,0, -1, 0, 0]);
-//     test_bop!(i16x8[i16; 8] | lt[i16x8_lt_test]:
-//               ([0, 1, 2, 3, 4, 5, 6, 7], [0, 2, 2, 4, 4, 6, 6, 7]) =>
-//               [0, -1, 0, -1 ,0, -1, 0, 0]);
-//     test_bop!(i32x4[i32; 4] | lt[i32x4_lt_test]:
-//               ([0, 1, 2, 3], [0, 2, 2, 4]) => [0, -1, 0, -1]);
-//     test_bop!(i64x2[i64; 2] | lt[i64x2_lt_test]: ([0, 1], [0, 2]) => [0, -1]);
-//     test_bop!(f32x4[f32; 4] => i32 | lt[f32x4_lt_test]:
-//               ([0., 1., 2., 3.], [0., 2., 2., 4.]) => [0, -1, 0, -1]);
-//     test_bop!(f64x2[f64; 2] => i64 | lt[f64x2_lt_test]: ([0., 1.], [0., 2.]) => [0, -1]);
-//
-//     test_bop!(i8x16[i8; 16] | gt[i8x16_gt_test]:
-//           ([0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15],
-//            [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) =>
-//               [0, -1, 0, -1 ,0, -1, 0, 0, 0, -1, 0, -1 ,0, -1, 0, 0]);
-//     test_bop!(i16x8[i16; 8] | gt[i16x8_gt_test]:
-//               ([0, 2, 2, 4, 4, 6, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]) =>
-//               [0, -1, 0, -1 ,0, -1, 0, 0]);
-//     test_bop!(i32x4[i32; 4] | gt[i32x4_gt_test]:
-//               ([0, 2, 2, 4], [0, 1, 2, 3]) => [0, -1, 0, -1]);
-//     test_bop!(i64x2[i64; 2] | gt[i64x2_gt_test]: ([0, 2], [0, 1]) => [0, -1]);
-//     test_bop!(f32x4[f32; 4] => i32 | gt[f32x4_gt_test]:
-//               ([0., 2., 2., 4.], [0., 1., 2., 3.]) => [0, -1, 0, -1]);
-//     test_bop!(f64x2[f64; 2] => i64 | gt[f64x2_gt_test]: ([0., 2.], [0., 1.]) => [0, -1]);
-//
-//     test_bop!(i8x16[i8; 16] | ge[i8x16_ge_test]:
-//               ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
-//                [0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15]) =>
-//               [-1, 0, -1, 0 ,-1, 0, -1, -1, -1, 0, -1, 0 ,-1, 0, -1, -1]);
-//     test_bop!(i16x8[i16; 8] | ge[i16x8_ge_test]:
-//               ([0, 1, 2, 3, 4, 5, 6, 7], [0, 2, 2, 4, 4, 6, 6, 7]) =>
-//               [-1, 0, -1, 0 ,-1, 0, -1, -1]);
-//     test_bop!(i32x4[i32; 4] | ge[i32x4_ge_test]:
-//               ([0, 1, 2, 3], [0, 2, 2, 4]) => [-1, 0, -1, 0]);
-//     test_bop!(i64x2[i64; 2] | ge[i64x2_ge_test]: ([0, 1], [0, 2]) => [-1, 0]);
-//     test_bop!(f32x4[f32; 4] => i32 | ge[f32x4_ge_test]:
-//               ([0., 1., 2., 3.], [0., 2., 2., 4.]) => [-1, 0, -1, 0]);
-//     test_bop!(f64x2[f64; 2] => i64 | ge[f64x2_ge_test]: ([0., 1.], [0., 2.]) => [-1, 0]);
-//
-//     test_bop!(i8x16[i8; 16] | le[i8x16_le_test]:
-//               ([0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15],
-//                [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
-//               ) =>
-//               [-1, 0, -1, 0 ,-1, 0, -1, -1, -1, 0, -1, 0 ,-1, 0, -1, -1]);
-//     test_bop!(i16x8[i16; 8] | le[i16x8_le_test]:
-//               ([0, 2, 2, 4, 4, 6, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]) =>
-//               [-1, 0, -1, 0 ,-1, 0, -1, -1]);
-//     test_bop!(i32x4[i32; 4] | le[i32x4_le_test]:
-//               ([0, 2, 2, 4], [0, 1, 2, 3]) => [-1, 0, -1, 0]);
-//     test_bop!(i64x2[i64; 2] | le[i64x2_le_test]: ([0, 2], [0, 1]) => [-1, 0]);
-//     test_bop!(f32x4[f32; 4] => i32 | le[f32x4_le_test]:
-//               ([0., 2., 2., 4.], [0., 1., 2., 3.]) => [-1, 0, -1, -0]);
-//     test_bop!(f64x2[f64; 2] => i64 | le[f64x2_le_test]: ([0., 2.], [0., 1.]) => [-1, 0]);
-//
-//     #[wasm_bindgen_test]
-//     fn v128_bitwise_load_store() {
-//         unsafe {
-//             let mut arr: [i32; 4] = [0, 1, 2, 3];
-//
-//             let vec = v128::load(arr.as_ptr() as *const v128);
-//             let vec = i32x4::add(vec, vec);
-//             v128::store(arr.as_mut_ptr() as *mut v128, vec);
-//
-//             assert_eq!(arr, [0, 2, 4, 6]);
-//         }
-//     }
-//
-//     test_uop!(f32x4[f32; 4] | neg[f32x4_neg_test]: [0., 1., 2., 3.] => [ 0., -1., -2., -3.]);
-//     test_uop!(f32x4[f32; 4] | abs[f32x4_abs_test]: [0., -1., 2., -3.] => [ 0., 1., 2., 3.]);
-//     test_bop!(f32x4[f32; 4] | min[f32x4_min_test]:
-//               ([0., -1., 7., 8.], [1., -3., -4., 10.]) => [0., -3., -4., 8.]);
-//     test_bop!(f32x4[f32; 4] | min[f32x4_min_test_nan]:
-//               ([0., -1., 7., 8.], [1., -3., -4., std::f32::NAN])
-//               => [0., -3., -4., std::f32::NAN]);
-//     test_bop!(f32x4[f32; 4] | max[f32x4_max_test]:
-//               ([0., -1., 7., 8.], [1., -3., -4., 10.]) => [1., -1., 7., 10.]);
-//     test_bop!(f32x4[f32; 4] | max[f32x4_max_test_nan]:
-//               ([0., -1., 7., 8.], [1., -3., -4., std::f32::NAN])
-//               => [1., -1., 7., std::f32::NAN]);
-//     test_bop!(f32x4[f32; 4] | add[f32x4_add_test]:
-//               ([0., -1., 7., 8.], [1., -3., -4., 10.]) => [1., -4., 3., 18.]);
-//     test_bop!(f32x4[f32; 4] | sub[f32x4_sub_test]:
-//               ([0., -1., 7., 8.], [1., -3., -4., 10.]) => [-1., 2., 11., -2.]);
-//     test_bop!(f32x4[f32; 4] | mul[f32x4_mul_test]:
-//               ([0., -1., 7., 8.], [1., -3., -4., 10.]) => [0., 3., -28., 80.]);
-//     test_bop!(f32x4[f32; 4] | div[f32x4_div_test]:
-//               ([0., -8., 70., 8.], [1., 4., 10., 2.]) => [0., -2., 7., 4.]);
-//
-//     test_uop!(f64x2[f64; 2] | neg[f64x2_neg_test]: [0., 1.] => [ 0., -1.]);
-//     test_uop!(f64x2[f64; 2] | abs[f64x2_abs_test]: [0., -1.] => [ 0., 1.]);
-//     test_bop!(f64x2[f64; 2] | min[f64x2_min_test]:
-//               ([0., -1.], [1., -3.]) => [0., -3.]);
-//     test_bop!(f64x2[f64; 2] | min[f64x2_min_test_nan]:
-//               ([7., 8.], [-4., std::f64::NAN])
-//               => [ -4., std::f64::NAN]);
-//     test_bop!(f64x2[f64; 2] | max[f64x2_max_test]:
-//               ([0., -1.], [1., -3.]) => [1., -1.]);
-//     test_bop!(f64x2[f64; 2] | max[f64x2_max_test_nan]:
-//               ([7., 8.], [ -4., std::f64::NAN])
-//               => [7., std::f64::NAN]);
-//     test_bop!(f64x2[f64; 2] | add[f64x2_add_test]:
-//               ([0., -1.], [1., -3.]) => [1., -4.]);
-//     test_bop!(f64x2[f64; 2] | sub[f64x2_sub_test]:
-//               ([0., -1.], [1., -3.]) => [-1., 2.]);
-//     test_bop!(f64x2[f64; 2] | mul[f64x2_mul_test]:
-//               ([0., -1.], [1., -3.]) => [0., 3.]);
-//     test_bop!(f64x2[f64; 2] | div[f64x2_div_test]:
-//               ([0., -8.], [1., 4.]) => [0., -2.]);
-//
-//     macro_rules! test_conv {
-//         ($test_id:ident | $conv_id:ident | $to_ty:ident | $from:expr,  $to:expr) => {
-//             #[wasm_bindgen_test]
-//             fn $test_id() {
-//                 unsafe {
-//                     let from: v128 = transmute($from);
-//                     let to: v128 = transmute($to);
-//
-//                     let r: v128 = $to_ty::$conv_id(from);
-//
-//                     compare_bytes(r, to);
-//                 }
-//             }
-//         };
-//     }
-//
-//     test_conv!(
-//         f32x4_convert_s_i32x4 | convert_s_i32x4 | f32x4 | [1_i32, 2, 3, 4],
-//         [1_f32, 2., 3., 4.]
-//     );
-//     test_conv!(
-//         f32x4_convert_u_i32x4
-//             | convert_u_i32x4
-//             | f32x4
-//             | [u32::max_value(), 2, 3, 4],
-//         [u32::max_value() as f32, 2., 3., 4.]
-//     );
-//     test_conv!(
-//         f64x2_convert_s_i64x2 | convert_s_i64x2 | f64x2 | [1_i64, 2],
-//         [1_f64, 2.]
-//     );
-//     test_conv!(
-//         f64x2_convert_u_i64x2
-//             | convert_u_i64x2
-//             | f64x2
-//             | [u64::max_value(), 2],
-//         [18446744073709552000.0, 2.]
-//     );
-//
-//     // FIXME: this fails, and produces -2147483648 instead of saturating at
-//     // i32::max_value() test_conv!(i32x4_trunc_s_f32x4_sat | trunc_s_f32x4_sat
-//     // | i32x4 | [1_f32, 2., (i32::max_value() as f32 + 1.), 4.],
-//     // [1_i32, 2, i32::max_value(), 4]); FIXME: add other saturating tests
-// }
+#[cfg(test)]
+pub mod tests {
+    use super::*;
+    use std;
+    use std::mem;
+    use std::num::Wrapping;
+    use std::prelude::v1::*;
+    use wasm_bindgen_test::*;
+
+    fn compare_bytes(a: v128, b: v128) {
+        let a: [u8; 16] = unsafe { transmute(a) };
+        let b: [u8; 16] = unsafe { transmute(b) };
+        assert_eq!(a, b);
+    }
+
+    #[wasm_bindgen_test]
+    #[cfg(not(only_node_compatible_functions))]
+    fn test_v128_const() {
+        const A: v128 =
+            unsafe { super::v128_const(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) };
+        compare_bytes(A, A);
+    }
+
+    macro_rules! test_splat {
+        ($test_id:ident: $val:expr => $($vals:expr),*) => {
+            #[wasm_bindgen_test]
+            fn $test_id() {
+                let a = super::$test_id($val);
+                let b: v128 = unsafe {
+                    transmute([$($vals as u8),*])
+                };
+                compare_bytes(a, b);
+            }
+        }
+    }
+
+    test_splat!(i8x16_splat: 42 => 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42);
+    test_splat!(i16x8_splat: 42 => 42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0);
+    test_splat!(i32x4_splat: 42 => 42, 0, 0, 0, 42, 0, 0, 0, 42, 0, 0, 0, 42, 0, 0, 0);
+    #[cfg(not(only_node_compatible_functions))]
+    test_splat!(i64x2_splat: 42 => 42, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0);
+    test_splat!(f32x4_splat: 42. => 0, 0, 40, 66, 0, 0, 40, 66, 0, 0, 40, 66, 0, 0, 40, 66);
+    #[cfg(not(only_node_compatible_functions))]
+    test_splat!(f64x2_splat: 42. => 0, 0, 0, 0, 0, 0, 69, 64, 0, 0, 0, 0, 0, 0, 69, 64);
+
+    // tests extract and replace lanes
+    macro_rules! test_extract {
+        (
+            name: $test_id:ident,
+            extract: $extract:ident,
+            replace: $replace:ident,
+            elem: $elem:ty,
+            count: $count:expr,
+            indices: [$($idx:expr),*],
+        ) => {
+            #[wasm_bindgen_test]
+            fn $test_id() {
+                unsafe {
+                    let arr: [$elem; $count] = [123 as $elem; $count];
+                    let vec: v128 = transmute(arr);
+                    $(
+                        assert_eq!($extract(vec, $idx), 123 as $elem);
+                    )*;
+
+                    // create a vector from array and check that the indices contain
+                    // the same values as in the array:
+                    let arr: [$elem; $count] = [$($idx as $elem),*];
+                    let vec: v128 = transmute(arr);
+                    $(
+                        assert_eq!($extract(vec, $idx), $idx as $elem);
+
+                        let tmp = $replace(vec, $idx, 124 as $elem);
+                        assert_eq!($extract(tmp, $idx), 124 as $elem);
+                    )*;
+                }
+            }
+        }
+    }
+
+    test_extract! {
+        name: test_i8x16_extract_replace,
+        extract: i8x16_extract_lane,
+        replace: i8x16_replace_lane,
+        elem: i8,
+        count: 16,
+        indices: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
+    }
+    test_extract! {
+        name: test_i16x8_extract_replace,
+        extract: i16x8_extract_lane,
+        replace: i16x8_replace_lane,
+        elem: i16,
+        count: 8,
+        indices: [0, 1, 2, 3, 4, 5, 6, 7],
+    }
+    test_extract! {
+        name: test_i32x4_extract_replace,
+        extract: i32x4_extract_lane,
+        replace: i32x4_replace_lane,
+        elem: i32,
+        count: 4,
+        indices: [0, 1, 2, 3],
+    }
+    #[cfg(not(only_node_compatible_functions))]
+    test_extract! {
+        name: test_i64x2_extract_replace,
+        extract: i64x2_extract_lane,
+        replace: i64x2_replace_lane,
+        elem: i64,
+        count: 2,
+        indices: [0, 1],
+    }
+    test_extract! {
+        name: test_f32x4_extract_replace,
+        extract: f32x4_extract_lane,
+        replace: f32x4_replace_lane,
+        elem: f32,
+        count: 4,
+        indices: [0, 1, 2, 3],
+    }
+    #[cfg(not(only_node_compatible_functions))]
+    test_extract! {
+        name: test_f64x2_extract_replace,
+        extract: f64x2_extract_lane,
+        replace: f64x2_replace_lane,
+        elem: f64,
+        count: 2,
+        indices: [0, 1],
+    }
+
+    macro_rules! test_binop {
+        (
+            $($name:ident => {
+                $([$($vec1:tt)*] ($op:tt | $f:ident) [$($vec2:tt)*],)*
+            })*
+        ) => ($(
+            #[wasm_bindgen_test]
+            fn $name() {
+                unsafe {
+                    $(
+                        let v1 = [$($vec1)*];
+                        let v2 = [$($vec2)*];
+                        let v1_v128: v128 = mem::transmute(v1);
+                        let v2_v128: v128 = mem::transmute(v2);
+                        let v3_v128 = super::$f(v1_v128, v2_v128);
+                        let mut v3 = [$($vec1)*];
+                        drop(v3);
+                        v3 = mem::transmute(v3_v128);
+
+                        for (i, actual) in v3.iter().enumerate() {
+                            let expected = (Wrapping(v1[i]) $op Wrapping(v2[i])).0;
+                            assert_eq!(*actual, expected);
+                        }
+                    )*
+                }
+            }
+        )*)
+    }
+
+    macro_rules! test_unop {
+        (
+            $($name:ident => {
+                $(($op:tt | $f:ident) [$($vec1:tt)*],)*
+            })*
+        ) => ($(
+            #[wasm_bindgen_test]
+            fn $name() {
+                unsafe {
+                    $(
+                        let v1 = [$($vec1)*];
+                        let v1_v128: v128 = mem::transmute(v1);
+                        let v2_v128 = super::$f(v1_v128);
+                        let mut v2 = [$($vec1)*];
+                        drop(v2);
+                        v2 = mem::transmute(v2_v128);
+
+                        for (i, actual) in v2.iter().enumerate() {
+                            let expected = ($op Wrapping(v1[i])).0;
+                            assert_eq!(*actual, expected);
+                        }
+                    )*
+                }
+            }
+        )*)
+    }
+
+    test_binop! {
+        test_i8x16_add => {
+            [0i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+                (+ | i8x16_add)
+            [1i8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
+
+            [1i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+                (+ | i8x16_add)
+            [-2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -18],
+
+            [1i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+                (+ | i8x16_add)
+            [127, -44, 43, 126, 4, 2, 9, -3, -59, -43, 39, -69, 79, -3, 9, -24],
+        }
+        test_i8x16_sub => {
+            [0i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+                (- | i8x16_sub)
+            [1i8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
+
+            [1i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+                (- | i8x16_sub)
+            [-2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -18],
+
+            [1i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+                (- | i8x16_sub)
+            [-127, -44, 43, 126, 4, 2, 9, -3, -59, -43, 39, -69, 79, -3, 4, 8],
+        }
+        test_i8x16_mul => {
+            [0i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+                (* | i8x16_mul)
+            [1i8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
+
+            [1i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+                (* | i8x16_mul)
+            [-2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -18],
+
+            [1i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+                (* | i8x16_mul)
+            [-127, -44, 43, 126, 4, 2, 9, -3, -59, -43, 39, -69, 79, -3, 30, 3],
+        }
+
+        test_i16x8_add => {
+            [0i16, 0, 0, 0, 0, 0, 0, 0]
+                (+ | i16x8_add)
+            [1i16, 1, 1, 1, 1, 1, 1, 1],
+
+            [1i16, 2, 3, 4, 5, 6, 7, 8]
+                (+ | i16x8_add)
+            [32767, 8, -2494,-4, 4882, -4, 848, 3830],
+        }
+
+        test_i16x8_sub => {
+            [0i16, 0, 0, 0, 0, 0, 0, 0]
+                (- | i16x8_sub)
+            [1i16, 1, 1, 1, 1, 1, 1, 1],
+
+            [1i16, 2, 3, 4, 5, 6, 7, 8]
+                (- | i16x8_sub)
+            [32767, 8, -2494,-4, 4882, -4, 848, 3830],
+        }
+
+        test_i16x8_mul => {
+            [0i16, 0, 0, 0, 0, 0, 0, 0]
+                (* | i16x8_mul)
+            [1i16, 1, 1, 1, 1, 1, 1, 1],
+
+            [1i16, 2, 3, 4, 5, 6, 7, 8]
+                (* | i16x8_mul)
+            [32767, 8, -2494,-4, 4882, -4, 848, 3830],
+        }
+
+        test_i32x4_add => {
+            [0i32, 0, 0, 0] (+ | i32x4_add) [1, 2, 3, 4],
+            [1i32, 1283, i32::max_value(), i32::min_value()]
+                (+ | i32x4_add)
+            [i32::max_value(); 4],
+        }
+
+        test_i32x4_sub => {
+            [0i32, 0, 0, 0] (- | i32x4_sub) [1, 2, 3, 4],
+            [1i32, 1283, i32::max_value(), i32::min_value()]
+                (- | i32x4_sub)
+            [i32::max_value(); 4],
+        }
+
+        test_i32x4_mul => {
+            [0i32, 0, 0, 0] (* | i32x4_mul) [1, 2, 3, 4],
+            [1i32, 1283, i32::max_value(), i32::min_value()]
+                (* | i32x4_mul)
+            [i32::max_value(); 4],
+        }
+
+        // TODO: test_i64x2_add
+        // TODO: test_i64x2_sub
+    }
+
+    test_unop! {
+        test_i8x16_neg => {
+            (- | i8x16_neg)
+            [1i8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
+
+            (- | i8x16_neg)
+            [-2i8, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -18],
+
+            (- | i8x16_neg)
+            [-127i8, -44, 43, 126, 4, -128, 127, -59, -43, 39, -69, 79, -3, 35, 83, 13],
+        }
+
+        test_i16x8_neg => {
+            (- | i16x8_neg) [1i16, 1, 1, 1, 1, 1, 1, 1],
+            (- | i16x8_neg) [2i16, 0x7fff, !0, 4, 42, -5, 33, -4847],
+        }
+
+        test_i32x4_neg => {
+            (- | i32x4_neg) [1i32, 2, 3, 4],
+            (- | i32x4_neg) [i32::min_value(), i32::max_value(), 0, 4],
+        }
+
+        // TODO: test_i64x2_neg
+    }
+
+    // #[wasm_bindgen_test]
+    // fn v8x16_shuffle() {
+    //     unsafe {
+    //         let a = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+    //         let b = [
+    //             16_u8, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+    //             31,
+    //         ];
+    //
+    //         let vec_a: v128 = transmute(a);
+    //         let vec_b: v128 = transmute(b);
+    //
+    //         let vec_r = v8x16_shuffle!(
+    //             vec_a,
+    //             vec_b,
+    //             [0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30]
+    //         );
+    //
+    //         let e =
+    //             [0_u8, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30];
+    //         let vec_e: v128 = transmute(e);
+    //         compare_bytes(vec_r, vec_e);
+    //     }
+    // }
+    //
+    // macro_rules! floating_point {
+    //     (f32) => {
+    //         true
+    //     };
+    //     (f64) => {
+    //         true
+    //     };
+    //     ($id:ident) => {
+    //         false
+    //     };
+    // }
+    //
+    // trait IsNan: Sized {
+    //     fn is_nan(self) -> bool {
+    //         false
+    //     }
+    // }
+    // impl IsNan for i8 {}
+    // impl IsNan for i16 {}
+    // impl IsNan for i32 {}
+    // impl IsNan for i64 {}
+    //
+    // macro_rules! test_bop {
+    //     ($id:ident[$ety:ident; $ecount:expr] |
+    //      $binary_op:ident [$op_test_id:ident] :
+    //      ([$($in_a:expr),*], [$($in_b:expr),*]) => [$($out:expr),*]) => {
+    //         test_bop!(
+    //             $id[$ety; $ecount] => $ety | $binary_op [ $op_test_id ]:
+    //             ([$($in_a),*], [$($in_b),*]) => [$($out),*]
+    //         );
+    //
+    //     };
+    //     ($id:ident[$ety:ident; $ecount:expr] => $oty:ident |
+    //      $binary_op:ident [$op_test_id:ident] :
+    //      ([$($in_a:expr),*], [$($in_b:expr),*]) => [$($out:expr),*]) => {
+    //         #[wasm_bindgen_test]
+    //         fn $op_test_id() {
+    //             unsafe {
+    //                 let a_input: [$ety; $ecount] = [$($in_a),*];
+    //                 let b_input: [$ety; $ecount] = [$($in_b),*];
+    //                 let output: [$oty; $ecount] = [$($out),*];
+    //
+    //                 let a_vec_in: v128 = transmute(a_input);
+    //                 let b_vec_in: v128 = transmute(b_input);
+    //                 let vec_res: v128 = $id::$binary_op(a_vec_in, b_vec_in);
+    //
+    //                 let res: [$oty; $ecount] = transmute(vec_res);
+    //
+    //                 if !floating_point!($ety) {
+    //                     assert_eq!(res, output);
+    //                 } else {
+    //                     for i in 0..$ecount {
+    //                         let r = res[i];
+    //                         let o = output[i];
+    //                         assert_eq!(r.is_nan(), o.is_nan());
+    //                         if !r.is_nan() {
+    //                             assert_eq!(r, o);
+    //                         }
+    //                     }
+    //                 }
+    //             }
+    //         }
+    //     }
+    // }
+    //
+    // macro_rules! test_bops {
+    //     ($id:ident[$ety:ident; $ecount:expr] |
+    //      $binary_op:ident [$op_test_id:ident]:
+    //      ([$($in_a:expr),*], $in_b:expr) => [$($out:expr),*]) => {
+    //         #[wasm_bindgen_test]
+    //         fn $op_test_id() {
+    //             unsafe {
+    //                 let a_input: [$ety; $ecount] = [$($in_a),*];
+    //                 let output: [$ety; $ecount] = [$($out),*];
+    //
+    //                 let a_vec_in: v128 = transmute(a_input);
+    //                 let vec_res: v128 = $id::$binary_op(a_vec_in, $in_b);
+    //
+    //                 let res: [$ety; $ecount] = transmute(vec_res);
+    //                 assert_eq!(res, output);
+    //             }
+    //         }
+    //     }
+    // }
+    //
+    // macro_rules! test_uop {
+    //     ($id:ident[$ety:ident; $ecount:expr] |
+    //      $unary_op:ident [$op_test_id:ident]: [$($in_a:expr),*] => [$($out:expr),*]) => {
+    //         #[wasm_bindgen_test]
+    //         fn $op_test_id() {
+    //             unsafe {
+    //                 let a_input: [$ety; $ecount] = [$($in_a),*];
+    //                 let output: [$ety; $ecount] = [$($out),*];
+    //
+    //                 let a_vec_in: v128 = transmute(a_input);
+    //                 let vec_res: v128 = $id::$unary_op(a_vec_in);
+    //
+    //                 let res: [$ety; $ecount] = transmute(vec_res);
+    //                 assert_eq!(res, output);
+    //             }
+    //         }
+    //     }
+    // }
+    //
+    //
+    //
+    // test_bops!(i8x16[i8; 16] | shl[i8x16_shl_test]:
+    //            ([0, -1, 2, 3, 4, 5, 6, i8::max_value(), 1, 1, 1, 1, 1, 1, 1, 1], 1) =>
+    //            [0, -2, 4, 6, 8, 10, 12, -2, 2, 2, 2, 2, 2, 2, 2, 2]);
+    // test_bops!(i16x8[i16; 8] | shl[i16x8_shl_test]:
+    //            ([0, -1, 2, 3, 4, 5, 6, i16::max_value()], 1) =>
+    //            [0, -2, 4, 6, 8, 10, 12, -2]);
+    // test_bops!(i32x4[i32; 4] | shl[i32x4_shl_test]:
+    //            ([0, -1, 2, 3], 1) => [0, -2, 4, 6]);
+    // test_bops!(i64x2[i64; 2] | shl[i64x2_shl_test]:
+    //            ([0, -1], 1) => [0, -2]);
+    //
+    // test_bops!(i8x16[i8; 16] | shr_s[i8x16_shr_s_test]:
+    //            ([0, -1, 2, 3, 4, 5, 6, i8::max_value(), 1, 1, 1, 1, 1, 1, 1, 1], 1) =>
+    //            [0, -1, 1, 1, 2, 2, 3, 63, 0, 0, 0, 0, 0, 0, 0, 0]);
+    // test_bops!(i16x8[i16; 8] | shr_s[i16x8_shr_s_test]:
+    //            ([0, -1, 2, 3, 4, 5, 6, i16::max_value()], 1) =>
+    //            [0, -1, 1, 1, 2, 2, 3, i16::max_value() / 2]);
+    // test_bops!(i32x4[i32; 4] | shr_s[i32x4_shr_s_test]:
+    //            ([0, -1, 2, 3], 1) => [0, -1, 1, 1]);
+    // test_bops!(i64x2[i64; 2] | shr_s[i64x2_shr_s_test]:
+    //            ([0, -1], 1) => [0, -1]);
+    //
+    // test_bops!(i8x16[i8; 16] | shr_u[i8x16_uhr_u_test]:
+    //            ([0, -1, 2, 3, 4, 5, 6, i8::max_value(), 1, 1, 1, 1, 1, 1, 1, 1], 1) =>
+    //            [0, i8::max_value(), 1, 1, 2, 2, 3, 63, 0, 0, 0, 0, 0, 0, 0, 0]);
+    // test_bops!(i16x8[i16; 8] | shr_u[i16x8_uhr_u_test]:
+    //            ([0, -1, 2, 3, 4, 5, 6, i16::max_value()], 1) =>
+    //            [0, i16::max_value(), 1, 1, 2, 2, 3, i16::max_value() / 2]);
+    // test_bops!(i32x4[i32; 4] | shr_u[i32x4_uhr_u_test]:
+    //            ([0, -1, 2, 3], 1) => [0, i32::max_value(), 1, 1]);
+    // test_bops!(i64x2[i64; 2] | shr_u[i64x2_uhr_u_test]:
+    //            ([0, -1], 1) => [0, i64::max_value()]);
+    //
+    // #[wasm_bindgen_test]
+    // fn v128_bitwise_logical_ops() {
+    //     unsafe {
+    //         let a: [u32; 4] = [u32::max_value(), 0, u32::max_value(), 0];
+    //         let b: [u32; 4] = [u32::max_value(); 4];
+    //         let c: [u32; 4] = [0; 4];
+    //
+    //         let vec_a: v128 = transmute(a);
+    //         let vec_b: v128 = transmute(b);
+    //         let vec_c: v128 = transmute(c);
+    //
+    //         let r: v128 = v128::and(vec_a, vec_a);
+    //         compare_bytes(r, vec_a);
+    //         let r: v128 = v128::and(vec_a, vec_b);
+    //         compare_bytes(r, vec_a);
+    //         let r: v128 = v128::or(vec_a, vec_b);
+    //         compare_bytes(r, vec_b);
+    //         let r: v128 = v128::not(vec_b);
+    //         compare_bytes(r, vec_c);
+    //         let r: v128 = v128::xor(vec_a, vec_c);
+    //         compare_bytes(r, vec_a);
+    //
+    //         let r: v128 = v128::bitselect(vec_b, vec_c, vec_b);
+    //         compare_bytes(r, vec_b);
+    //         let r: v128 = v128::bitselect(vec_b, vec_c, vec_c);
+    //         compare_bytes(r, vec_c);
+    //         let r: v128 = v128::bitselect(vec_b, vec_c, vec_a);
+    //         compare_bytes(r, vec_a);
+    //     }
+    // }
+    //
+    // macro_rules! test_bool_red {
+    //     ($id:ident[$test_id:ident] | [$($true:expr),*] | [$($false:expr),*] | [$($alt:expr),*]) => {
+    //         #[wasm_bindgen_test]
+    //         fn $test_id() {
+    //             unsafe {
+    //                 let vec_a: v128 = transmute([$($true),*]); // true
+    //                 let vec_b: v128 = transmute([$($false),*]); // false
+    //                 let vec_c: v128 = transmute([$($alt),*]); // alternating
+    //
+    //                 assert_eq!($id::any_true(vec_a), 1);
+    //                 assert_eq!($id::any_true(vec_b), 0);
+    //                 assert_eq!($id::any_true(vec_c), 1);
+    //
+    //                 assert_eq!($id::all_true(vec_a), 1);
+    //                 assert_eq!($id::all_true(vec_b), 0);
+    //                 assert_eq!($id::all_true(vec_c), 0);
+    //             }
+    //         }
+    //     }
+    // }
+    //
+    // test_bool_red!(
+    //     i8x16[i8x16_boolean_reductions]
+    //         | [1_i8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
+    //         | [0_i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+    //         | [1_i8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
+    // );
+    // test_bool_red!(
+    //     i16x8[i16x8_boolean_reductions]
+    //         | [1_i16, 1, 1, 1, 1, 1, 1, 1]
+    //         | [0_i16, 0, 0, 0, 0, 0, 0, 0]
+    //         | [1_i16, 0, 1, 0, 1, 0, 1, 0]
+    // );
+    // test_bool_red!(
+    //     i32x4[i32x4_boolean_reductions]
+    //         | [1_i32, 1, 1, 1]
+    //         | [0_i32, 0, 0, 0]
+    //         | [1_i32, 0, 1, 0]
+    // );
+    // test_bool_red!(
+    //     i64x2[i64x2_boolean_reductions] | [1_i64, 1] | [0_i64, 0] | [1_i64, 0]
+    // );
+    //
+    // test_bop!(i8x16[i8; 16] | eq[i8x16_eq_test]:
+    //           ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
+    //            [0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15]) =>
+    //           [-1, 0, -1, 0 ,-1, 0, -1, -1, -1, 0, -1, 0 ,-1, 0, -1, -1]);
+    // test_bop!(i16x8[i16; 8] | eq[i16x8_eq_test]:
+    //           ([0, 1, 2, 3, 4, 5, 6, 7], [0, 2, 2, 4, 4, 6, 6, 7]) =>
+    //           [-1, 0, -1, 0 ,-1, 0, -1, -1]);
+    // test_bop!(i32x4[i32; 4] | eq[i32x4_eq_test]:
+    //           ([0, 1, 2, 3], [0, 2, 2, 4]) => [-1, 0, -1, 0]);
+    // test_bop!(i64x2[i64; 2] | eq[i64x2_eq_test]: ([0, 1], [0, 2]) => [-1, 0]);
+    // test_bop!(f32x4[f32; 4] => i32 | eq[f32x4_eq_test]:
+    //           ([0., 1., 2., 3.], [0., 2., 2., 4.]) => [-1, 0, -1, 0]);
+    // test_bop!(f64x2[f64; 2] => i64 | eq[f64x2_eq_test]: ([0., 1.], [0., 2.]) => [-1, 0]);
+    //
+    // test_bop!(i8x16[i8; 16] | ne[i8x16_ne_test]:
+    //           ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
+    //            [0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15]) =>
+    //           [0, -1, 0, -1 ,0, -1, 0, 0, 0, -1, 0, -1 ,0, -1, 0, 0]);
+    // test_bop!(i16x8[i16; 8] | ne[i16x8_ne_test]:
+    //           ([0, 1, 2, 3, 4, 5, 6, 7], [0, 2, 2, 4, 4, 6, 6, 7]) =>
+    //           [0, -1, 0, -1 ,0, -1, 0, 0]);
+    // test_bop!(i32x4[i32; 4] | ne[i32x4_ne_test]:
+    //           ([0, 1, 2, 3], [0, 2, 2, 4]) => [0, -1, 0, -1]);
+    // test_bop!(i64x2[i64; 2] | ne[i64x2_ne_test]: ([0, 1], [0, 2]) => [0, -1]);
+    // test_bop!(f32x4[f32; 4] => i32 | ne[f32x4_ne_test]:
+    //           ([0., 1., 2., 3.], [0., 2., 2., 4.]) => [0, -1, 0, -1]);
+    // test_bop!(f64x2[f64; 2] => i64 | ne[f64x2_ne_test]: ([0., 1.], [0., 2.]) => [0, -1]);
+    //
+    // test_bop!(i8x16[i8; 16] | lt[i8x16_lt_test]:
+    //           ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
+    //            [0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15]) =>
+    //           [0, -1, 0, -1 ,0, -1, 0, 0, 0, -1, 0, -1 ,0, -1, 0, 0]);
+    // test_bop!(i16x8[i16; 8] | lt[i16x8_lt_test]:
+    //           ([0, 1, 2, 3, 4, 5, 6, 7], [0, 2, 2, 4, 4, 6, 6, 7]) =>
+    //           [0, -1, 0, -1 ,0, -1, 0, 0]);
+    // test_bop!(i32x4[i32; 4] | lt[i32x4_lt_test]:
+    //           ([0, 1, 2, 3], [0, 2, 2, 4]) => [0, -1, 0, -1]);
+    // test_bop!(i64x2[i64; 2] | lt[i64x2_lt_test]: ([0, 1], [0, 2]) => [0, -1]);
+    // test_bop!(f32x4[f32; 4] => i32 | lt[f32x4_lt_test]:
+    //           ([0., 1., 2., 3.], [0., 2., 2., 4.]) => [0, -1, 0, -1]);
+    // test_bop!(f64x2[f64; 2] => i64 | lt[f64x2_lt_test]: ([0., 1.], [0., 2.]) => [0, -1]);
+    //
+    // test_bop!(i8x16[i8; 16] | gt[i8x16_gt_test]:
+    //       ([0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15],
+    //        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) =>
+    //           [0, -1, 0, -1 ,0, -1, 0, 0, 0, -1, 0, -1 ,0, -1, 0, 0]);
+    // test_bop!(i16x8[i16; 8] | gt[i16x8_gt_test]:
+    //           ([0, 2, 2, 4, 4, 6, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]) =>
+    //           [0, -1, 0, -1 ,0, -1, 0, 0]);
+    // test_bop!(i32x4[i32; 4] | gt[i32x4_gt_test]:
+    //           ([0, 2, 2, 4], [0, 1, 2, 3]) => [0, -1, 0, -1]);
+    // test_bop!(i64x2[i64; 2] | gt[i64x2_gt_test]: ([0, 2], [0, 1]) => [0, -1]);
+    // test_bop!(f32x4[f32; 4] => i32 | gt[f32x4_gt_test]:
+    //           ([0., 2., 2., 4.], [0., 1., 2., 3.]) => [0, -1, 0, -1]);
+    // test_bop!(f64x2[f64; 2] => i64 | gt[f64x2_gt_test]: ([0., 2.], [0., 1.]) => [0, -1]);
+    //
+    // test_bop!(i8x16[i8; 16] | ge[i8x16_ge_test]:
+    //           ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
+    //            [0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15]) =>
+    //           [-1, 0, -1, 0 ,-1, 0, -1, -1, -1, 0, -1, 0 ,-1, 0, -1, -1]);
+    // test_bop!(i16x8[i16; 8] | ge[i16x8_ge_test]:
+    //           ([0, 1, 2, 3, 4, 5, 6, 7], [0, 2, 2, 4, 4, 6, 6, 7]) =>
+    //           [-1, 0, -1, 0 ,-1, 0, -1, -1]);
+    // test_bop!(i32x4[i32; 4] | ge[i32x4_ge_test]:
+    //           ([0, 1, 2, 3], [0, 2, 2, 4]) => [-1, 0, -1, 0]);
+    // test_bop!(i64x2[i64; 2] | ge[i64x2_ge_test]: ([0, 1], [0, 2]) => [-1, 0]);
+    // test_bop!(f32x4[f32; 4] => i32 | ge[f32x4_ge_test]:
+    //           ([0., 1., 2., 3.], [0., 2., 2., 4.]) => [-1, 0, -1, 0]);
+    // test_bop!(f64x2[f64; 2] => i64 | ge[f64x2_ge_test]: ([0., 1.], [0., 2.]) => [-1, 0]);
+    //
+    // test_bop!(i8x16[i8; 16] | le[i8x16_le_test]:
+    //           ([0, 2, 2, 4, 4, 6, 6, 7, 8, 10, 10, 12, 12, 14, 14, 15],
+    //            [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
+    //           ) =>
+    //           [-1, 0, -1, 0 ,-1, 0, -1, -1, -1, 0, -1, 0 ,-1, 0, -1, -1]);
+    // test_bop!(i16x8[i16; 8] | le[i16x8_le_test]:
+    //           ([0, 2, 2, 4, 4, 6, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]) =>
+    //           [-1, 0, -1, 0 ,-1, 0, -1, -1]);
+    // test_bop!(i32x4[i32; 4] | le[i32x4_le_test]:
+    //           ([0, 2, 2, 4], [0, 1, 2, 3]) => [-1, 0, -1, 0]);
+    // test_bop!(i64x2[i64; 2] | le[i64x2_le_test]: ([0, 2], [0, 1]) => [-1, 0]);
+    // test_bop!(f32x4[f32; 4] => i32 | le[f32x4_le_test]:
+    //           ([0., 2., 2., 4.], [0., 1., 2., 3.]) => [-1, 0, -1, -0]);
+    // test_bop!(f64x2[f64; 2] => i64 | le[f64x2_le_test]: ([0., 2.], [0., 1.]) => [-1, 0]);
+    //
+    // #[wasm_bindgen_test]
+    // fn v128_bitwise_load_store() {
+    //     unsafe {
+    //         let mut arr: [i32; 4] = [0, 1, 2, 3];
+    //
+    //         let vec = v128::load(arr.as_ptr() as *const v128);
+    //         let vec = i32x4::add(vec, vec);
+    //         v128::store(arr.as_mut_ptr() as *mut v128, vec);
+    //
+    //         assert_eq!(arr, [0, 2, 4, 6]);
+    //     }
+    // }
+    //
+    // test_uop!(f32x4[f32; 4] | neg[f32x4_neg_test]: [0., 1., 2., 3.] => [ 0., -1., -2., -3.]);
+    // test_uop!(f32x4[f32; 4] | abs[f32x4_abs_test]: [0., -1., 2., -3.] => [ 0., 1., 2., 3.]);
+    // test_bop!(f32x4[f32; 4] | min[f32x4_min_test]:
+    //           ([0., -1., 7., 8.], [1., -3., -4., 10.]) => [0., -3., -4., 8.]);
+    // test_bop!(f32x4[f32; 4] | min[f32x4_min_test_nan]:
+    //           ([0., -1., 7., 8.], [1., -3., -4., std::f32::NAN])
+    //           => [0., -3., -4., std::f32::NAN]);
+    // test_bop!(f32x4[f32; 4] | max[f32x4_max_test]:
+    //           ([0., -1., 7., 8.], [1., -3., -4., 10.]) => [1., -1., 7., 10.]);
+    // test_bop!(f32x4[f32; 4] | max[f32x4_max_test_nan]:
+    //           ([0., -1., 7., 8.], [1., -3., -4., std::f32::NAN])
+    //           => [1., -1., 7., std::f32::NAN]);
+    // test_bop!(f32x4[f32; 4] | add[f32x4_add_test]:
+    //           ([0., -1., 7., 8.], [1., -3., -4., 10.]) => [1., -4., 3., 18.]);
+    // test_bop!(f32x4[f32; 4] | sub[f32x4_sub_test]:
+    //           ([0., -1., 7., 8.], [1., -3., -4., 10.]) => [-1., 2., 11., -2.]);
+    // test_bop!(f32x4[f32; 4] | mul[f32x4_mul_test]:
+    //           ([0., -1., 7., 8.], [1., -3., -4., 10.]) => [0., 3., -28., 80.]);
+    // test_bop!(f32x4[f32; 4] | div[f32x4_div_test]:
+    //           ([0., -8., 70., 8.], [1., 4., 10., 2.]) => [0., -2., 7., 4.]);
+    //
+    // test_uop!(f64x2[f64; 2] | neg[f64x2_neg_test]: [0., 1.] => [ 0., -1.]);
+    // test_uop!(f64x2[f64; 2] | abs[f64x2_abs_test]: [0., -1.] => [ 0., 1.]);
+    // test_bop!(f64x2[f64; 2] | min[f64x2_min_test]:
+    //           ([0., -1.], [1., -3.]) => [0., -3.]);
+    // test_bop!(f64x2[f64; 2] | min[f64x2_min_test_nan]:
+    //           ([7., 8.], [-4., std::f64::NAN])
+    //           => [ -4., std::f64::NAN]);
+    // test_bop!(f64x2[f64; 2] | max[f64x2_max_test]:
+    //           ([0., -1.], [1., -3.]) => [1., -1.]);
+    // test_bop!(f64x2[f64; 2] | max[f64x2_max_test_nan]:
+    //           ([7., 8.], [ -4., std::f64::NAN])
+    //           => [7., std::f64::NAN]);
+    // test_bop!(f64x2[f64; 2] | add[f64x2_add_test]:
+    //           ([0., -1.], [1., -3.]) => [1., -4.]);
+    // test_bop!(f64x2[f64; 2] | sub[f64x2_sub_test]:
+    //           ([0., -1.], [1., -3.]) => [-1., 2.]);
+    // test_bop!(f64x2[f64; 2] | mul[f64x2_mul_test]:
+    //           ([0., -1.], [1., -3.]) => [0., 3.]);
+    // test_bop!(f64x2[f64; 2] | div[f64x2_div_test]:
+    //           ([0., -8.], [1., 4.]) => [0., -2.]);
+    //
+    // macro_rules! test_conv {
+    //     ($test_id:ident | $conv_id:ident | $to_ty:ident | $from:expr,  $to:expr) => {
+    //         #[wasm_bindgen_test]
+    //         fn $test_id() {
+    //             unsafe {
+    //                 let from: v128 = transmute($from);
+    //                 let to: v128 = transmute($to);
+    //
+    //                 let r: v128 = $to_ty::$conv_id(from);
+    //
+    //                 compare_bytes(r, to);
+    //             }
+    //         }
+    //     };
+    // }
+    //
+    // test_conv!(
+    //     f32x4_convert_s_i32x4 | convert_s_i32x4 | f32x4 | [1_i32, 2, 3, 4],
+    //     [1_f32, 2., 3., 4.]
+    // );
+    // test_conv!(
+    //     f32x4_convert_u_i32x4
+    //         | convert_u_i32x4
+    //         | f32x4
+    //         | [u32::max_value(), 2, 3, 4],
+    //     [u32::max_value() as f32, 2., 3., 4.]
+    // );
+    // test_conv!(
+    //     f64x2_convert_s_i64x2 | convert_s_i64x2 | f64x2 | [1_i64, 2],
+    //     [1_f64, 2.]
+    // );
+    // test_conv!(
+    //     f64x2_convert_u_i64x2
+    //         | convert_u_i64x2
+    //         | f64x2
+    //         | [u64::max_value(), 2],
+    //     [18446744073709552000.0, 2.]
+    // );
+    //
+    // // FIXME: this fails, and produces -2147483648 instead of saturating at
+    // // i32::max_value() test_conv!(i32x4_trunc_s_f32x4_sat | trunc_s_f32x4_sat
+    // // | i32x4 | [1_f32, 2., (i32::max_value() as f32 + 1.), 4.],
+    // // [1_i32, 2, i32::max_value(), 4]); FIXME: add other saturating tests
+}

From 2ed8a39ea2cb5cfabfaddf0b94146b3689cc1bff Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Wed, 24 Apr 2019 10:37:06 -0700
Subject: [PATCH 4/4] Download node binaries

---
 ci/docker/wasm32-unknown-unknown/Dockerfile | 20 +++-----------------
 1 file changed, 3 insertions(+), 17 deletions(-)

diff --git a/ci/docker/wasm32-unknown-unknown/Dockerfile b/ci/docker/wasm32-unknown-unknown/Dockerfile
index 4e84b05728..ff8eb28442 100644
--- a/ci/docker/wasm32-unknown-unknown/Dockerfile
+++ b/ci/docker/wasm32-unknown-unknown/Dockerfile
@@ -1,18 +1,3 @@
-FROM ubuntu:18.04 as node
-
-RUN apt-get update -y && apt-get install -y \
-  g++ \
-  git \
-  make \
-  python
-
-
-# Install `node`
-RUN git clone https://github.com/nodejs/node --depth 1
-WORKDIR node
-RUN ./configure --prefix=/node-install
-RUN make -j$(nproc) install
-
 FROM ubuntu:18.04
 
 RUN apt-get update -y && apt-get install -y --no-install-recommends \
@@ -31,8 +16,9 @@ RUN git clone --recursive https://github.com/WebAssembly/wabt
 RUN make -C wabt -j$(nproc)
 ENV PATH=$PATH:/wabt/bin
 
-COPY --from=node /node-install /
-ENV PATH=$PATH:/node-install/bin
+# Install `node`
+RUN curl https://nodejs.org/dist/v12.0.0/node-v12.0.0-linux-x64.tar.xz | tar xJf -
+ENV PATH=$PATH:/node-v12.0.0-linux-x64/bin
 
 COPY docker/wasm32-unknown-unknown/wasm-entrypoint.sh /wasm-entrypoint.sh
 ENTRYPOINT ["/wasm-entrypoint.sh"]