Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

winch(x64): Add support for global get and set #6703

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions fuzz/fuzz_targets/differential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ fn winch_supports_module(module: &[u8]) -> bool {
| LocalGet { .. }
| LocalSet { .. }
| LocalTee { .. }
| GlobalGet { .. }
| GlobalSet { .. }
| Call { .. }
| Nop { .. }
| End { .. }
Expand Down
154 changes: 154 additions & 0 deletions tests/misc_testsuite/winch/globals.wast
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't see any f32 or f64 globals being tested here. Are those valtypes not supported by winch at all yet? If they are supported, then there should be some exercising of globals of those types. If not, then I guess there should eventually be that same exercising but not in this PR :-p

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, not supported yet, but I'll be working on introducing support for them next.

Original file line number Diff line number Diff line change
@@ -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))
14 changes: 13 additions & 1 deletion winch/codegen/src/codegen/env.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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
Expand Down
27 changes: 26 additions & 1 deletion winch/codegen/src/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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)*};
}
Expand Down Expand Up @@ -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(<M::ABI as ABI>::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(<M::ABI as ABI>::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);
}

Expand Down