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

Implement the wide-arithmetic proposal #9403

Merged
merged 1 commit into from
Oct 8, 2024
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
8 changes: 8 additions & 0 deletions crates/c-api/include/wasmtime/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@ WASMTIME_CONFIG_PROP(void, wasm_multi_memory, bool)
*/
WASMTIME_CONFIG_PROP(void, wasm_memory64, bool)

/**
* \brief Configures whether the WebAssembly wide-arithmetic proposal is
* enabled.
*
* This setting is `false` by default.
*/
WASMTIME_CONFIG_PROP(void, wasm_wide_arithmetic, bool)

#ifdef WASMTIME_FEATURE_COMPILER

/**
Expand Down
5 changes: 5 additions & 0 deletions crates/c-api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,3 +460,8 @@ pub unsafe extern "C" fn wasmtime_config_host_memory_creator_set(
pub extern "C" fn wasmtime_config_memory_init_cow_set(c: &mut wasm_config_t, enable: bool) {
c.config.memory_init_cow(enable);
}

#[no_mangle]
pub extern "C" fn wasmtime_config_wasm_wide_arithmetic_set(c: &mut wasm_config_t, enable: bool) {
c.config.wasm_wide_arithmetic(enable);
}
5 changes: 5 additions & 0 deletions crates/cli-flags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ wasmtime_option_group! {
pub gc: Option<bool>,
/// Configure support for the custom-page-sizes proposal.
pub custom_page_sizes: Option<bool>,
/// Configure support for the wide-arithmetic proposal.
pub wide_arithmetic: Option<bool>,
}

enum Wasm {
Expand Down Expand Up @@ -724,6 +726,9 @@ impl CommonOptions {
if let Some(enable) = self.wasm.custom_page_sizes.or(all) {
config.wasm_custom_page_sizes(enable);
}
if let Some(enable) = self.wasm.wide_arithmetic.or(all) {
config.wasm_wide_arithmetic(enable);
}

macro_rules! handle_conditionally_compiled {
($(($feature:tt, $field:tt, $method:tt))*) => ($(
Expand Down
38 changes: 31 additions & 7 deletions crates/cranelift/src/translate/code_translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2793,13 +2793,37 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
));
}

Operator::I64Add128
| Operator::I64Sub128
| Operator::I64MulWideS
| Operator::I64MulWideU => {
return Err(wasm_unsupported!(
"wide-arithmetic operators are not yet implemented"
));
Operator::I64MulWideS => {
let (arg1, arg2) = state.pop2();
let arg1 = builder.ins().sextend(I128, arg1);
let arg2 = builder.ins().sextend(I128, arg2);
let result = builder.ins().imul(arg1, arg2);
let (lo, hi) = builder.ins().isplit(result);
state.push2(lo, hi);
}
Operator::I64MulWideU => {
let (arg1, arg2) = state.pop2();
let arg1 = builder.ins().uextend(I128, arg1);
let arg2 = builder.ins().uextend(I128, arg2);
let result = builder.ins().imul(arg1, arg2);
let (lo, hi) = builder.ins().isplit(result);
state.push2(lo, hi);
}
Operator::I64Add128 => {
let (arg1, arg2, arg3, arg4) = state.pop4();
let arg1 = builder.ins().iconcat(arg1, arg2);
let arg2 = builder.ins().iconcat(arg3, arg4);
let result = builder.ins().iadd(arg1, arg2);
let (res1, res2) = builder.ins().isplit(result);
state.push2(res1, res2);
}
Operator::I64Sub128 => {
let (arg1, arg2, arg3, arg4) = state.pop4();
let arg1 = builder.ins().iconcat(arg1, arg2);
let arg2 = builder.ins().iconcat(arg3, arg4);
let result = builder.ins().isub(arg1, arg2);
let (res1, res2) = builder.ins().isplit(result);
state.push2(res1, res2);
}
};
Ok(())
Expand Down
6 changes: 6 additions & 0 deletions crates/cranelift/src/translate/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ impl FuncTranslationState {
self.stack.push(val);
}

/// Push two values.
pub(crate) fn push2(&mut self, val1: Value, val2: Value) {
self.stack.push(val1);
self.stack.push(val2);
}

/// Push multiple values.
pub(crate) fn pushn(&mut self, vals: &[Value]) {
self.stack.extend_from_slice(vals);
Expand Down
6 changes: 6 additions & 0 deletions crates/fuzzing/src/generators/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ impl Config {
.wasm_threads(self.module_config.config.threads_enabled)
.wasm_function_references(self.module_config.config.gc_enabled)
.wasm_gc(self.module_config.config.gc_enabled)
.wasm_wide_arithmetic(self.module_config.config.wide_arithmetic_enabled)
.native_unwind_info(cfg!(target_os = "windows") || self.wasmtime.native_unwind_info)
.cranelift_nan_canonicalization(self.wasmtime.canonicalize_nans)
.cranelift_opt_level(self.wasmtime.opt_level.to_wasmtime())
Expand Down Expand Up @@ -474,6 +475,10 @@ impl WasmtimeConfig {
// Not fully implemented in Wasmtime and fuzzing.
config.gc_enabled = false;

// Off-by-default in wasm-smith but implemented in wasmtime, so give the
// fuzzers a chance to run it.
config.wide_arithmetic_enabled = u.arbitrary()?;

// Winch doesn't support the same set of wasm proposal as Cranelift at
// this time, so if winch is selected be sure to disable wasm proposals
// in `Config` to ensure that Winch can compile the module that
Expand All @@ -485,6 +490,7 @@ impl WasmtimeConfig {
config.threads_enabled = false;
config.tail_call_enabled = false;
config.reference_types_enabled = false;
config.wide_arithmetic_enabled = false;

// Winch requires host trap handlers to be enabled at this time.
self.signals_based_traps = true;
Expand Down
33 changes: 20 additions & 13 deletions crates/fuzzing/src/generators/single_inst_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,36 +163,38 @@ impl<'a> SingleInstModule<'a> {
// instructions compactly and allow for easier changes to the Rust code (e.g.,
// `SingleInstModule`).

macro_rules! valtype {
(i32) => {
macro_rules! valtypes {
(@list ($($ty:tt),*)) => {&[$(valtypes!(@one $ty)),*]};
(@list $ty:tt) => {&[valtypes!(@one $ty)]};
(@one i32) => {
ValType::I32
};
(i64) => {
(@one i64) => {
ValType::I64
};
(f32) => {
(@one f32) => {
ValType::F32
};
(f64) => {
(@one f64) => {
ValType::F64
};
(v128) => {
(@one v128) => {
ValType::V128
};
}

macro_rules! inst {
($inst:ident, ($($arguments_ty:tt),*) -> $result_ty:tt) => {
inst! { $inst, ($($arguments_ty),*) -> $result_ty, |_| true }
($inst:ident, $arguments:tt -> $results:tt) => {
inst! { $inst, $arguments -> $results, |_| true }
};
($inst:ident, ($($arguments_ty:tt),*) -> $result_ty:tt, $feature:expr) => {
inst! { $inst, ($($arguments_ty),*) -> $result_ty, $feature, None }
($inst:ident, $arguments:tt -> $results:tt, $feature:expr) => {
inst! { $inst, $arguments -> $results, $feature, None }
};
($inst:ident, ($($arguments_ty:tt),*) -> $result_ty:tt, $feature:expr, $nan:expr) => {
($inst:ident, $arguments:tt -> $results:tt, $feature:expr, $nan:expr) => {
SingleInstModule {
instruction: Instruction::$inst,
parameters: &[$(valtype!($arguments_ty)),*],
results: &[valtype!($result_ty)],
parameters: valtypes!(@list $arguments),
results: valtypes!(@list $results),
feature: $feature,
canonicalize_nan: $nan,
}
Expand Down Expand Up @@ -568,6 +570,11 @@ static INSTRUCTIONS: &[SingleInstModule] = &[
inst!(F64x2ConvertLowI32x4U, (v128) -> v128, |c| c.config.simd_enabled),
inst!(F32x4DemoteF64x2Zero, (v128) -> v128, |c| c.config.simd_enabled),
inst!(F64x2PromoteLowF32x4, (v128) -> v128, |c| c.config.simd_enabled),
// wide arithmetic
inst!(I64Add128, (i64, i64, i64, i64) -> (i64, i64), |c| c.config.wide_arithmetic_enabled && c.config.multi_value_enabled),
inst!(I64Sub128, (i64, i64, i64, i64) -> (i64, i64), |c| c.config.wide_arithmetic_enabled && c.config.multi_value_enabled),
inst!(I64MulWideS, (i64, i64) -> (i64, i64), |c| c.config.wide_arithmetic_enabled && c.config.multi_value_enabled),
inst!(I64MulWideU, (i64, i64) -> (i64, i64), |c| c.config.wide_arithmetic_enabled && c.config.multi_value_enabled),
];

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions crates/fuzzing/src/oracles/diff_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ impl SpecInterpreter {
config.reference_types_enabled = false;
config.tail_call_enabled = false;
config.relaxed_simd_enabled = false;
config.wide_arithmetic_enabled = false;

Self
}
Expand Down
1 change: 1 addition & 0 deletions crates/fuzzing/src/oracles/diff_v8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ impl V8Engine {
config.min_memories = config.min_memories.min(1);
config.max_memories = config.max_memories.min(1);
config.memory64_enabled = false;
config.wide_arithmetic_enabled = false;

Self {
isolate: Rc::new(RefCell::new(v8::Isolate::new(Default::default()))),
Expand Down
1 change: 1 addition & 0 deletions crates/fuzzing/src/oracles/diff_wasmi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ impl WasmiEngine {
config.threads_enabled = false;
config.exceptions_enabled = false;
config.gc_enabled = false;
config.wide_arithmetic_enabled = false;
config.max_memories = config.max_memories.min(1);
config.min_memories = config.min_memories.min(1);

Expand Down
11 changes: 11 additions & 0 deletions crates/wasmtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,17 @@ impl Config {
self
}

/// Configures whether the [WebAssembly wide-arithmetic][proposal] will be
/// enabled for compilation.
///
/// This feature is `false` by default.
///
/// [proposal]: https://github.com/WebAssembly/wide-arithmetic
pub fn wasm_wide_arithmetic(&mut self, enable: bool) -> &mut Self {
self.wasm_feature(WasmFeatures::WIDE_ARITHMETIC, enable);
self
}

/// Configures whether the [WebAssembly Garbage Collection
/// proposal][proposal] will be enabled for compilation.
///
Expand Down
2 changes: 2 additions & 0 deletions docs/stability-tiers.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@ For explanations of what each tier means see below.
| Target | Support for `#![no_std]` | Support beyond CI checks |
| WebAssembly Proposal | [`memory64`] | Unstable wasm proposal |
| WebAssembly Proposal | [`function-references`] | Unstable wasm proposal |
| WebAssembly Proposal | [`wide-arithmetic`] | Unstable wasm proposal |

[`memory64`]: https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md
[`multi-memory`]: https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md
[`threads`]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md
[`component-model`]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md
[`relaxed-simd`]: https://github.com/WebAssembly/relaxed-simd/blob/main/proposals/relaxed-simd/Overview.md
[`function-references`]: https://github.com/WebAssembly/function-references/blob/main/proposals/function-references/Overview.md
[`wide-arithmetic`]: https://github.com/WebAssembly/wide-arithmetic/blob/main/proposals/wide-arithmetic/Overview.md

#### Tier 3

Expand Down
91 changes: 91 additions & 0 deletions tests/disas/aarch64-wide-arithmetic.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
;;! target = "aarch64"
;;! test = "compile"
;;! flags = "-Wwide-arithmetic"

(module
(func $add128 (param i64 i64 i64 i64) (result i64 i64)
local.get 0
local.get 1
local.get 2
local.get 3
i64.add128)

(func $sub128 (param i64 i64 i64 i64) (result i64 i64)
local.get 0
local.get 1
local.get 2
local.get 3
i64.sub128)

(func $signed (param i64 i64) (result i64 i64)
local.get 0
local.get 1
i64.mul_wide_s)

(func $unsigned (param i64 i64) (result i64 i64)
local.get 0
local.get 1
i64.mul_wide_u)

(func $signed_only_high (param i64 i64) (result i64)
local.get 0
local.get 1
i64.mul_wide_s
local.set 0
drop
local.get 0)

(func $unsigned_only_high (param i64 i64) (result i64)
local.get 0
local.get 1
i64.mul_wide_u
local.set 0
drop
local.get 0)
)

;; wasm[0]::function[0]::add128:
;; stp x29, x30, [sp, #-0x10]!
;; mov x29, sp
;; adds x2, x4, x6
;; adc x3, x5, x7
;; ldp x29, x30, [sp], #0x10
;; ret
;;
;; wasm[0]::function[1]::sub128:
;; stp x29, x30, [sp, #-0x10]!
;; mov x29, sp
;; subs x2, x4, x6
;; sbc x3, x5, x7
;; ldp x29, x30, [sp], #0x10
;; ret
;;
;; wasm[0]::function[2]::signed:
;; stp x29, x30, [sp, #-0x10]!
;; mov x29, sp
;; mul x2, x4, x5
;; smulh x3, x4, x5
;; ldp x29, x30, [sp], #0x10
;; ret
;;
;; wasm[0]::function[3]::unsigned:
;; stp x29, x30, [sp, #-0x10]!
;; mov x29, sp
;; mul x2, x4, x5
;; umulh x3, x4, x5
;; ldp x29, x30, [sp], #0x10
;; ret
;;
;; wasm[0]::function[4]::signed_only_high:
;; stp x29, x30, [sp, #-0x10]!
;; mov x29, sp
;; smulh x2, x4, x5
;; ldp x29, x30, [sp], #0x10
;; ret
;;
;; wasm[0]::function[5]::unsigned_only_high:
;; stp x29, x30, [sp, #-0x10]!
;; mov x29, sp
;; umulh x2, x4, x5
;; ldp x29, x30, [sp], #0x10
;; ret
Loading