diff --git a/fuzz/fuzz_targets/differential.rs b/fuzz/fuzz_targets/differential.rs index 33ad38896125..f4d321faaa78 100644 --- a/fuzz/fuzz_targets/differential.rs +++ b/fuzz/fuzz_targets/differential.rs @@ -355,6 +355,8 @@ fn winch_supports_module(module: &[u8]) -> bool { | LocalGet { .. } | LocalSet { .. } | LocalTee { .. } + | GlobalGet { .. } + | GlobalSet { .. } | Call { .. } | Nop { .. } | End { .. } diff --git a/tests/misc_testsuite/winch/globals.wast b/tests/misc_testsuite/winch/globals.wast new file mode 100644 index 000000000000..fa2a8f75ff15 --- /dev/null +++ b/tests/misc_testsuite/winch/globals.wast @@ -0,0 +1,154 @@ +;; Test globals + +(module + (global (import "spectest" "global_i32") i32) + (global (import "spectest" "global_i64") i64) + + (global $a i32 (i32.const -2)) + (global $b i64 (i64.const -5)) + + (global $x (mut i32) (i32.const -12)) + (global $y (mut i64) (i64.const -15)) + + (global $z1 i32 (global.get 0)) + (global $z2 i64 (global.get 1)) + + (func (export "get-a") (result i32) (global.get $a)) + (func (export "get-b") (result i64) (global.get $b)) + (func (export "get-x") (result i32) (global.get $x)) + (func (export "get-y") (result i64) (global.get $y)) + (func (export "get-z1") (result i32) (global.get $z1)) + (func (export "get-z2") (result i64) (global.get $z2)) + (func (export "set-x") (param i32) (global.set $x (local.get 0))) + (func (export "set-y") (param i64) (global.set $y (local.get 0))) + + ;; As the argument of control constructs and instructions + + (memory 1) + + (func $dummy) + + (func (export "as-loop-first") (result i32) + (loop (result i32) + (global.get $x) (call $dummy) (call $dummy) + ) + ) + (func (export "as-loop-mid") (result i32) + (loop (result i32) + (call $dummy) (global.get $x) (call $dummy) + ) + ) + (func (export "as-loop-last") (result i32) + (loop (result i32) + (call $dummy) (call $dummy) (global.get $x) + ) + ) + + (func (export "as-if-condition") (result i32) + (if (result i32) (global.get $x) + (then (call $dummy) (i32.const 2)) + (else (call $dummy) (i32.const 3)) + ) + ) + (func (export "as-if-then") (result i32) + (if (result i32) (i32.const 1) + (then (global.get $x)) (else (i32.const 2)) + ) + ) + (func (export "as-if-else") (result i32) + (if (result i32) (i32.const 0) + (then (i32.const 2)) (else (global.get $x)) + ) + ) + + (func (export "as-br_if-first") (result i32) + (block (result i32) + (br_if 0 (global.get $x) (i32.const 2)) + (return (i32.const 3)) + ) + ) + (func (export "as-br_if-last") (result i32) + (block (result i32) + (br_if 0 (i32.const 2) (global.get $x)) + (return (i32.const 3)) + ) + ) + + (func $f (param i32) (result i32) (local.get 0)) + (func (export "as-call-value") (result i32) + (call $f (global.get $x)) + ) + + (func (export "as-return-value") (result i32) + (global.get $x) (return) + ) + (func (export "as-br-value") (result i32) + (block (result i32) (br 0 (global.get $x))) + ) + + (func (export "as-local.set-value") (param i32) (result i32) + (local.set 0 (global.get $x)) + (local.get 0) + ) + (func (export "as-local.tee-value") (param i32) (result i32) + (local.tee 0 (global.get $x)) + ) + (func (export "as-global.set-value") (result i32) + (global.set $x (global.get $x)) + (global.get $x) + ) + + (func (export "as-unary-operand") (result i32) + (i32.eqz (global.get $x)) + ) + (func (export "as-binary-operand") (result i32) + (i32.mul + (global.get $x) (global.get $x) + ) + ) + (func (export "as-compare-operand") (result i32) + (i32.gt_u + (global.get 0) (i32.const 1) + ) + ) +) + +(assert_return (invoke "get-a") (i32.const -2)) +(assert_return (invoke "get-b") (i64.const -5)) +(assert_return (invoke "get-x") (i32.const -12)) +(assert_return (invoke "get-y") (i64.const -15)) +(assert_return (invoke "get-z1") (i32.const 666)) +(assert_return (invoke "get-z2") (i64.const 666)) + +(assert_return (invoke "set-x" (i32.const 6))) +(assert_return (invoke "set-y" (i64.const 7))) + +(assert_return (invoke "get-x") (i32.const 6)) +(assert_return (invoke "get-y") (i64.const 7)) + +(assert_return (invoke "get-x") (i32.const 6)) +(assert_return (invoke "get-y") (i64.const 7)) + +(assert_return (invoke "as-loop-first") (i32.const 6)) +(assert_return (invoke "as-loop-mid") (i32.const 6)) +(assert_return (invoke "as-loop-last") (i32.const 6)) + +(assert_return (invoke "as-if-condition") (i32.const 2)) +(assert_return (invoke "as-if-then") (i32.const 6)) +(assert_return (invoke "as-if-else") (i32.const 6)) + +(assert_return (invoke "as-br_if-first") (i32.const 6)) +(assert_return (invoke "as-br_if-last") (i32.const 2)) + +(assert_return (invoke "as-call-value") (i32.const 6)) + +(assert_return (invoke "as-return-value") (i32.const 6)) +(assert_return (invoke "as-br-value") (i32.const 6)) + +(assert_return (invoke "as-local.set-value" (i32.const 1)) (i32.const 6)) +(assert_return (invoke "as-local.tee-value" (i32.const 1)) (i32.const 6)) +(assert_return (invoke "as-global.set-value") (i32.const 6)) + +(assert_return (invoke "as-unary-operand") (i32.const 0)) +(assert_return (invoke "as-binary-operand") (i32.const 36)) +(assert_return (invoke "as-compare-operand") (i32.const 1)) diff --git a/winch/codegen/src/codegen/env.rs b/winch/codegen/src/codegen/env.rs index 78ceee2b47ad..c3451630a354 100644 --- a/winch/codegen/src/codegen/env.rs +++ b/winch/codegen/src/codegen/env.rs @@ -1,7 +1,8 @@ use smallvec::{smallvec, SmallVec}; use wasmparser::BlockType; use wasmtime_environ::{ - FuncIndex, ModuleTranslation, PtrSize, TypeConvert, VMOffsets, WasmFuncType, WasmType, + FuncIndex, GlobalIndex, ModuleTranslation, PtrSize, TypeConvert, VMOffsets, WasmFuncType, + WasmType, }; /// The function environment. @@ -50,6 +51,17 @@ impl<'a, P: PtrSize> FuncEnv<'a, P> { _ => unimplemented!("multi-value"), } } + + /// Resolves the type and offset of a global at the given index. + pub fn resolve_global_type_and_offset(&self, index: GlobalIndex) -> (WasmType, u32) { + let ty = self.translation.module.globals[index].wasm_ty; + let offset = match self.translation.module.defined_global_index(index) { + Some(defined_index) => self.vmoffsets.vmctx_vmglobal_definition(defined_index), + None => self.vmoffsets.vmctx_vmglobal_import_from(index), + }; + + (ty, offset) + } } /// Metadata about a function callee. Use by the code generation diff --git a/winch/codegen/src/visitor.rs b/winch/codegen/src/visitor.rs index 310f51305873..27bf2028f19b 100644 --- a/winch/codegen/src/visitor.rs +++ b/winch/codegen/src/visitor.rs @@ -4,12 +4,13 @@ //! which validates and dispatches to the corresponding //! machine code emitter. +use crate::abi::ABI; use crate::codegen::CodeGen; use crate::codegen::ControlStackFrame; use crate::masm::{CmpKind, DivKind, MacroAssembler, OperandSize, RegImm, RemKind, ShiftKind}; use crate::stack::Val; use wasmparser::{BlockType, VisitOperator}; -use wasmtime_environ::{FuncIndex, WasmType}; +use wasmtime_environ::{FuncIndex, GlobalIndex, WasmType}; /// A macro to define unsupported WebAssembly operators. /// @@ -106,6 +107,8 @@ macro_rules! def_unsupported { (emit Return $($rest:tt)*) => {}; (emit Unreachable $($rest:tt)*) => {}; (emit LocalTee $($rest:tt)*) => {}; + (emit GlobalGet $($rest:tt)*) => {}; + (emit GlobalSet $($rest:tt)*) => {}; (emit $unsupported:tt $($rest:tt)*) => {$($rest)*}; } @@ -599,6 +602,28 @@ where self.context.stack.push(Val::reg(src)); } + fn visit_global_get(&mut self, global_index: u32) { + let index = GlobalIndex::from_u32(global_index); + let (ty, offset) = self.env.resolve_global_type_and_offset(index); + let addr = self + .masm + .address_at_reg(::vmctx_reg(), offset); + let dst = self.context.any_gpr(self.masm); + self.masm.load(addr, dst, ty.into()); + self.context.stack.push(Val::reg(dst)); + } + + fn visit_global_set(&mut self, global_index: u32) { + let index = GlobalIndex::from_u32(global_index); + let (ty, offset) = self.env.resolve_global_type_and_offset(index); + let addr = self + .masm + .address_at_reg(::vmctx_reg(), offset); + let reg = self.context.pop_to_reg(self.masm, None, ty.into()); + self.context.free_gpr(reg); + self.masm.store(reg.into(), addr, ty.into()); + } + wasmparser::for_each_operator!(def_unsupported); }