summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry <mail@henrygressmann.de>2026-04-03 23:56:03 +0200
committerHenry <mail@henrygressmann.de>2026-04-03 23:56:03 +0200
commitddc997ab59762958da139a333a2fa5f0ce37eace (patch)
tree04785a45c53fa6edfb75a6cae4ad1cc2565e56f5
parent1f741ba37d8217de333488d0a66fa6cc7f8537a7 (diff)
feat: Wide Arithmetic
Signed-off-by: Henry <mail@henrygressmann.de>
-rw-r--r--README.md2
-rw-r--r--crates/parser/src/lib.rs4
-rw-r--r--crates/parser/src/visit.rs5
-rw-r--r--crates/tinywasm/Cargo.toml5
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs36
-rw-r--r--crates/tinywasm/tests/generated/wasm-wide-arithmetic.csv1
-rw-r--r--crates/tinywasm/tests/test-wasm-wide-arithmetic.rs13
-rw-r--r--crates/types/src/instructions.rs5
-rwxr-xr-xexamples/rust/build.sh6
9 files changed, 70 insertions, 7 deletions
diff --git a/README.md b/README.md
index cb3a475..3ea59e4 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@ Untrusted WebAssembly code should not be able to crash the runtime or access mem
| [**Memory64**](https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md) | 🟢 | `next` |
| [**Tail Call**](https://github.com/WebAssembly/tail-call/blob/main/proposals/tail-call/Overview.md) | 🟢 | `next` |
| [**Relaxed SIMD**](https://github.com/WebAssembly/relaxed-simd/blob/main/proposals/relaxed-simd/Overview.md) | 🟢 | `next` |
-| [**Wide Arithmetic**](https://github.com/WebAssembly/wide-arithmetic/blob/main/proposals/wide-arithmetic/Overview.md) | 🚧 | - |
+| [**Wide Arithmetic**](https://github.com/WebAssembly/wide-arithmetic/blob/main/proposals/wide-arithmetic/Overview.md) | 🟢 | `next` |
| [**Custom Descriptors**](https://github.com/WebAssembly/custom-descriptors/blob/main/proposals/custom-descriptors/Overview.md) | 🌑 | - |
| [**Exception Handling**](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md) | 🌑 | - |
| [**Function References**](https://github.com/WebAssembly/function-references/blob/main/proposals/function-references/Overview.md) | 🌑 | - |
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index a799f69..f7e713b 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -66,20 +66,20 @@ impl Parser {
custom_page_sizes: true,
bulk_memory_opt: true,
call_indirect_overlong: true,
+ wide_arithmetic: true,
+ relaxed_simd: true,
compact_imports: false,
cm_map: false,
custom_descriptors: false,
cm_threading: false,
extended_const: false,
- wide_arithmetic: false,
gc_types: true,
stack_switching: false,
component_model: false,
exceptions: false,
gc: false,
memory_control: false,
- relaxed_simd: true,
threads: false,
shared_everything_threads: false,
legacy_exceptions: false,
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index e3de009..d6bccdb 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -363,6 +363,7 @@ macro_rules! impl_visit_operator {
(@@saturating_float_to_int $($rest:tt)* ) => {};
(@@bulk_memory $($rest:tt)* ) => {};
(@@simd $($rest:tt)* ) => {};
+ (@@wide_arithmetic $($rest:tt)* ) => {};
(@@relaxed_simd $($rest:tt)* ) => {};
(@@tail_call $($rest:tt)* ) => {};
@@ -402,6 +403,10 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
visit_memory_init(MemoryInit, u32, u32), visit_memory_copy(MemoryCopy, u32, u32), visit_table_init(TableInit, u32, u32), visit_memory_fill(MemoryFill, u32), visit_data_drop(DataDrop, u32), visit_elem_drop(ElemDrop, u32)
}
+ define_operands! {
+ visit_i64_add128(I64Add128), visit_i64_sub128(I64Sub128), visit_i64_mul_wide_s(I64MulWideS), visit_i64_mul_wide_u(I64MulWideU)
+ }
+
fn visit_global_set(&mut self, global_index: u32) -> Self::Output {
match self.validator.get_operand_type(0) {
Some(Some(t)) => self.instructions.push(match t {
diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml
index b89c907..274946a 100644
--- a/crates/tinywasm/Cargo.toml
+++ b/crates/tinywasm/Cargo.toml
@@ -104,6 +104,11 @@ harness=false
test=false
[[test]]
+name="test-wasm-wide-arithmetic"
+harness=false
+test=false
+
+[[test]]
name="test-wast"
harness=false
test=false
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index 17343ee..2292a70 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -57,9 +57,25 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
(binary try $ty:ty, |$a:ident, $b:ident| $expr:expr) => { self.store.stack.values.binary::<$ty>(|$a, $b| $expr)? };
(unary $from:ty => $to:ty, |$v:ident| $expr:expr) => { self.store.stack.values.unary_into::<$from, $to>(|$v| Ok($expr))? };
(binary $from:ty => $to:ty, |$a:ident, $b:ident| $expr:expr) => { self.store.stack.values.binary_into::<$from, $to>(|$a, $b| Ok($expr))? };
+ (binary_into2 $from:ty => $to:ty, |$a:ident, $b:ident| $expr:expr) => {{
+ let $b = self.store.stack.values.pop::<$from>();
+ let $a = self.store.stack.values.pop::<$from>();
+ let out = $expr;
+ self.store.stack.values.push::<$to>(out.0)?;
+ self.store.stack.values.push::<$to>(out.1)?;
+ }};
(binary $a:ty, $b:ty, |$lhs:ident, $rhs:ident| $expr:expr) => { stack_op!(binary $a, $b => $b, |$lhs, $rhs| $expr) };
(binary $a:ty, $b:ty => $res:ty, |$lhs:ident, $rhs:ident| $expr:expr) => { self.store.stack.values.binary_mixed::<$a, $b, $res>(|$lhs, $rhs| Ok($expr))? };
(ternary $ty:ty, |$a:ident, $b:ident, $c:ident| $expr:expr) => { self.store.stack.values.ternary::<$ty>(|$a, $b, $c| Ok($expr))? };
+ (quaternary_into2 $from:ty => $to:ty, |$a:ident, $b:ident, $c:ident, $d:ident| $expr:expr) => {{
+ let $d = self.store.stack.values.pop::<$from>();
+ let $c = self.store.stack.values.pop::<$from>();
+ let $b = self.store.stack.values.pop::<$from>();
+ let $a = self.store.stack.values.pop::<$from>();
+ let out = $expr;
+ self.store.stack.values.push::<$to>(out.0)?;
+ self.store.stack.values.push::<$to>(out.1)?;
+ }};
(local_set_pop $ty:ty, $local_index:expr) => {{
let val = self.store.stack.values.pop::<$ty>();
self.store.stack.values.local_set(&self.cf, *$local_index, val);
@@ -266,6 +282,26 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
I64Rotl => stack_op!(binary i64, |a, b| a.wasm_rotl(b)),
I32Rotr => stack_op!(binary i32, |a, b| a.wasm_rotr(b)),
I64Rotr => stack_op!(binary i64, |a, b| a.wasm_rotr(b)),
+ I64Add128 => stack_op!(quaternary_into2 i64 => i64, |a_lo, a_hi, b_lo, b_hi| {
+ let lo = a_lo.wrapping_add(b_lo);
+ let carry = u64::from((lo as u64) < (a_lo as u64));
+ let hi = a_hi.wrapping_add(b_hi).wrapping_add(carry as i64);
+ (lo, hi)
+ }),
+ I64Sub128 => stack_op!(quaternary_into2 i64 => i64, |a_lo, a_hi, b_lo, b_hi| {
+ let lo = a_lo.wrapping_sub(b_lo);
+ let borrow = u64::from((a_lo as u64) < (b_lo as u64));
+ let hi = a_hi.wrapping_sub(b_hi).wrapping_sub(borrow as i64);
+ (lo, hi)
+ }),
+ I64MulWideS => stack_op!(binary_into2 i64 => i64, |a, b| {
+ let product = (a as i128).wrapping_mul(b as i128);
+ (product as i64, (product >> 64) as i64)
+ }),
+ I64MulWideU => stack_op!(binary_into2 i64 => i64, |a, b| {
+ let product = (a as u64 as u128).wrapping_mul(b as u64 as u128);
+ (product as u64 as i64, (product >> 64) as u64 as i64)
+ }),
I32Clz => stack_op!(unary i32, |v| v.leading_zeros() as i32),
I64Clz => stack_op!(unary i64, |v| i64::from(v.leading_zeros())),
I32Ctz => stack_op!(unary i32, |v| v.trailing_zeros() as i32),
diff --git a/crates/tinywasm/tests/generated/wasm-wide-arithmetic.csv b/crates/tinywasm/tests/generated/wasm-wide-arithmetic.csv
new file mode 100644
index 0000000..10d7685
--- /dev/null
+++ b/crates/tinywasm/tests/generated/wasm-wide-arithmetic.csv
@@ -0,0 +1 @@
+0.9.0-alpha.0,109,0,[{"name":"wide-arithmetic.wast","passed":109,"failed":0}]
diff --git a/crates/tinywasm/tests/test-wasm-wide-arithmetic.rs b/crates/tinywasm/tests/test-wasm-wide-arithmetic.rs
new file mode 100644
index 0000000..2aa6b43
--- /dev/null
+++ b/crates/tinywasm/tests/test-wasm-wide-arithmetic.rs
@@ -0,0 +1,13 @@
+mod testsuite;
+use eyre::Result;
+use testsuite::TestSuite;
+use wasm_testsuite::data::{Proposal, proposal};
+
+fn main() -> Result<()> {
+ TestSuite::set_log_level(log::LevelFilter::Off);
+
+ let mut test_suite = TestSuite::new();
+ test_suite.run_files(proposal(&Proposal::WideArithmetic))?;
+ test_suite.save_csv("./tests/generated/wasm-wide-arithmetic.csv", env!("CARGO_PKG_VERSION"))?;
+ test_suite.report_status()
+}
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index 59dc49f..efb7172 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -176,7 +176,10 @@ pub enum Instruction {
DataDrop(DataAddr),
ElemDrop(ElemAddr),
- // > SIMD Instructions
+ // > Wide Arithmetic
+ I64Add128, I64Sub128, I64MulWideS, I64MulWideU,
+
+ // > SIMD
V128Load(MemoryArg),
V128Load8x8S(MemoryArg), V128Load8x8U(MemoryArg),
V128Load16x4S(MemoryArg), V128Load16x4U(MemoryArg),
diff --git a/examples/rust/build.sh b/examples/rust/build.sh
index d51840b..36f9568 100755
--- a/examples/rust/build.sh
+++ b/examples/rust/build.sh
@@ -6,8 +6,8 @@ exclude_wat=("tinywasm")
out_dir="./target/wasm32-unknown-unknown/wasm"
dest_dir="out"
-rust_features="+simd128,+reference-types,+bulk-memory,+mutable-globals,+multivalue,+sign-ext,+nontrapping-fptoint"
-wasmopt_features="--enable-simd --enable-tail-call --enable-extended-const --enable-reference-types --enable-bulk-memory --enable-mutable-globals --enable-multivalue --enable-sign-ext --enable-nontrapping-float-to-int --duplicate-function-elimination"
+rust_features="+simd128,+relaxed-simd,+reference-types,+bulk-memory,+mutable-globals,+multivalue,+sign-ext,+nontrapping-fptoint"
+wasmopt_features="--enable-simd --enable-relaxed-simd --enable-tail-call --enable-extended-const --enable-reference-types --enable-bulk-memory --enable-mutable-globals --enable-multivalue --enable-sign-ext --enable-nontrapping-float-to-int --duplicate-function-elimination"
# ensure out dir exists
mkdir -p "$dest_dir"
@@ -25,4 +25,4 @@ for bin in "${bins[@]}"; do
if [[ ! " ${exclude_wat[@]} " =~ " $bin " ]]; then
wasm2wat "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wat"
fi
-done \ No newline at end of file
+done