diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 82441c05d524..4bf6b44e2003 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -271,6 +271,32 @@ jobs: env: RUST_BACKTRACE: 1 + # Perform all tests (debug mode) for `wasmtime` with the experimental x64 + # backend. This runs on the nightly channel of Rust (because of issues with + # unifying Cargo features on stable) on Ubuntu. + test_x64: + name: Test x64 new backend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - uses: ./.github/actions/install-rust + with: + toolchain: nightly-2020-08-25 + - uses: ./.github/actions/define-llvm-env + + # Install wasm32 targets in order to build various tests throughout the + # repo. + - run: rustup target add wasm32-wasi + - run: rustup target add wasm32-unknown-unknown + + # Run the x64 CI script. + - run: ./ci/run-experimental-x64-ci.sh + env: + CARGO_VERSION: "+nightly-2020-08-25" + RUST_BACKTRACE: 1 + # Verify that cranelift's code generation is deterministic meta_determinist_check: name: Meta deterministic check diff --git a/build.rs b/build.rs index e23e8c218041..25a3f23e7ba8 100644 --- a/build.rs +++ b/build.rs @@ -182,6 +182,10 @@ fn experimental_x64_should_panic(testsuite: &str, testname: &str, strategy: &str match (testsuite, testname) { ("simd", "simd_address") => return false, ("simd", "simd_const") => return false, + ("simd", "simd_i8x16_arith") => return false, + ("simd", "simd_i16x8_arith") => return false, + ("simd", "simd_i32x4_arith") => return false, + ("simd", "simd_i64x2_arith") => return false, ("simd", "simd_f32x4_arith") => return false, ("simd", "simd_f32x4_cmp") => return false, ("simd", "simd_f64x2_arith") => return false, diff --git a/ci/run-experimental-x64-ci.sh b/ci/run-experimental-x64-ci.sh index 2773eee2d8b6..edadba2b9c84 100755 --- a/ci/run-experimental-x64-ci.sh +++ b/ci/run-experimental-x64-ci.sh @@ -1,6 +1,11 @@ #!/bin/bash -cargo +nightly \ +# Use the Nightly variant of the compiler to properly unify the +# experimental_x64 feature across all crates. Once the feature has stabilized +# and become the default, we can remove this. +CARGO_VERSION=${CARGO_VERSION:-"+nightly"} + +cargo $CARGO_VERSION \ -Zfeatures=all -Zpackage-features \ test \ --features test-programs/test_programs \ @@ -14,4 +19,5 @@ cargo +nightly \ --exclude peepmatic-runtime \ --exclude peepmatic-test \ --exclude peepmatic-souper \ - --exclude lightbeam + --exclude lightbeam \ + $@ diff --git a/cranelift/codegen/src/isa/x64/abi.rs b/cranelift/codegen/src/isa/x64/abi.rs index 15c7837a3b11..b9d55349cf96 100644 --- a/cranelift/codegen/src/isa/x64/abi.rs +++ b/cranelift/codegen/src/isa/x64/abi.rs @@ -195,65 +195,23 @@ impl ABIMachineSpec for X64ABIMachineSpec { } fn gen_load_stack(mem: StackAMode, into_reg: Writable, ty: Type) -> Self::I { - let (is_int, ext_mode) = match ty { - types::B1 | types::B8 | types::I8 => (true, Some(ExtMode::BQ)), - types::B16 | types::I16 => (true, Some(ExtMode::WQ)), - types::B32 | types::I32 => (true, Some(ExtMode::LQ)), - types::B64 | types::I64 | types::R64 => (true, None), - types::F32 | types::F64 => (false, None), + let ext_kind = match ty { + types::B1 + | types::B8 + | types::I8 + | types::B16 + | types::I16 + | types::B32 + | types::I32 => ExtKind::SignExtend, + types::B64 | types::I64 | types::R64 | types::F32 | types::F64 => ExtKind::None, + _ if ty.bytes() == 16 => ExtKind::None, _ => panic!("load_stack({})", ty), }; - - let mem = SyntheticAmode::from(mem); - - if is_int { - match ext_mode { - Some(ext_mode) => Inst::movsx_rm_r( - ext_mode, - RegMem::mem(mem), - into_reg, - /* infallible load */ None, - ), - None => Inst::mov64_m_r(mem, into_reg, None /* infallible */), - } - } else { - let sse_op = match ty { - types::F32 => SseOpcode::Movss, - types::F64 => SseOpcode::Movsd, - _ => unreachable!(), - }; - Inst::xmm_mov( - sse_op, - RegMem::mem(mem), - into_reg, - None, /* infallible */ - ) - } + Inst::load(ty, mem, into_reg, ext_kind, /* infallible */ None) } fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Self::I { - let (is_int, size) = match ty { - types::B1 | types::B8 | types::I8 => (true, 1), - types::B16 | types::I16 => (true, 2), - types::B32 | types::I32 => (true, 4), - types::B64 | types::I64 | types::R64 => (true, 8), - types::F32 => (false, 4), - types::F64 => (false, 8), - _ => unimplemented!("store_stack({})", ty), - }; - - let mem = SyntheticAmode::from(mem); - - if is_int { - Inst::mov_r_m(size, from_reg, mem, /* infallible store */ None) - } else { - let sse_op = match size { - 4 => SseOpcode::Movss, - 8 => SseOpcode::Movsd, - _ => unreachable!(), - }; - Inst::xmm_mov_r_m(sse_op, from_reg, mem, /* infallible store */ None) - } + Inst::store(ty, from_reg, mem, /* infallible */ None) } fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Self::I { diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index a7dfe0a72398..9383af9a8ca6 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -88,12 +88,22 @@ pub extern "C" fn wasmtime_f32_trunc(x: f32) -> f32 { /// Implementation of f32.nearest #[allow(clippy::float_arithmetic, clippy::float_cmp)] pub extern "C" fn wasmtime_f32_nearest(x: f32) -> f32 { - // Rust doesn't have a nearest function, so do it manually. + // Rust doesn't have a nearest function; there's nearbyint, but it's not + // stabilized, so do it manually. // Nearest is either ceil or floor depending on which is nearest or even. // This approach exploited round half to even default mode. let i = x.to_bits(); let e = i >> 23 & 0xff; if e >= 0x7f_u32 + 23 { + // Check for NaNs. + if e == 0xff { + // Read the 23-bits significand. + if i & 0x7fffff != 0 { + // Ensure it's arithmetic by setting the significand's most + // significant bit to 1; it also works for canonical NaNs. + return f32::from_bits(i | (1 << 22)); + } + } x } else { (x.abs() + TOINT_32 - TOINT_32).copysign(x) @@ -153,12 +163,22 @@ pub extern "C" fn wasmtime_f64_trunc(x: f64) -> f64 { /// Implementation of f64.nearest #[allow(clippy::float_arithmetic, clippy::float_cmp)] pub extern "C" fn wasmtime_f64_nearest(x: f64) -> f64 { - // Rust doesn't have a nearest function, so do it manually. + // Rust doesn't have a nearest function; there's nearbyint, but it's not + // stabilized, so do it manually. // Nearest is either ceil or floor depending on which is nearest or even. // This approach exploited round half to even default mode. let i = x.to_bits(); let e = i >> 52 & 0x7ff; if e >= 0x3ff_u64 + 52 { + // Check for NaNs. + if e == 0x7ff { + // Read the 52-bits significand. + if i & 0xfffffffffffff != 0 { + // Ensure it's arithmetic by setting the significand's most + // significant bit to 1; it also works for canonical NaNs. + return f64::from_bits(i | (1 << 51)); + } + } x } else { (x.abs() + TOINT_64 - TOINT_64).copysign(x)