diff --git a/ci/docker/wasm32-unknown-unknown/Dockerfile b/ci/docker/wasm32-unknown-unknown/Dockerfile index e385541f9c..ff8eb28442 100644 --- a/ci/docker/wasm32-unknown-unknown/Dockerfile +++ b/ci/docker/wasm32-unknown-unknown/Dockerfile @@ -16,12 +16,9 @@ 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 - # 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 +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"] 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/foo.wasm b/crates/core_arch/foo.wasm deleted file mode 100755 index 34e1133664..0000000000 Binary files a/crates/core_arch/foo.wasm and /dev/null differ diff --git a/crates/core_arch/src/wasm32/simd128.rs b/crates/core_arch/src/wasm32/simd128.rs index e853fdd599..7bf579f38e 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,597 +1597,738 @@ 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())) } } -// #[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 +} 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> { 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> = HashMap::new(); let mut lines = output.lines().map(|s| s.trim());