Skip to content
This repository was archived by the owner on Oct 3, 2025. It is now read-only.

Commit 197c32f

Browse files
feat: support a bunch more new instructions
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
1 parent d2b30c3 commit 197c32f

File tree

2 files changed

+113
-2
lines changed

2 files changed

+113
-2
lines changed

crates/tinywasm/src/runtime/executor/macros.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
/// More generic macros for various instructions
2+
///
3+
/// These macros are used to generate the actual instruction implementations.
4+
///
5+
/// A bunch of these could be simplified, but some copy-paste is sometimes just simpler - this is way nicer for debugging.
6+
/// Might also be nicer for the compiler to not have closures everywhere, the assembly from this in godbolt is pretty good like this.
7+
18
/// Add two values from the stack
29
macro_rules! add_instr {
310
($ty:ty, $stack:ident) => {{
@@ -79,6 +86,31 @@ macro_rules! ltu_instr {
7986
}};
8087
}
8188

89+
/// Less than equal signed instruction
90+
macro_rules! les_instr {
91+
($ty:ty, $stack:ident) => {{
92+
let [a, b] = $stack.values.pop_n_const::<2>()?;
93+
let a: $ty = a.into();
94+
let b: $ty = b.into();
95+
96+
$stack.values.push(((a <= b) as i32).into());
97+
}};
98+
}
99+
100+
/// Less than equal unsigned instruction
101+
macro_rules! leu_instr {
102+
($ty:ty, $uty:ty, $stack:ident) => {{
103+
let [a, b] = $stack.values.pop_n_const::<2>()?;
104+
let a: $ty = a.into();
105+
let b: $ty = b.into();
106+
107+
// Cast to unsigned type before comparison
108+
let a_unsigned: $uty = a as $uty;
109+
let b_unsigned: $uty = b as $uty;
110+
$stack.values.push(((a_unsigned <= b_unsigned) as i32).into());
111+
}};
112+
}
113+
82114
/// Multiply the top two values on the stack
83115
macro_rules! mul_instr {
84116
($ty:ty, $stack:ident) => {{
@@ -140,14 +172,60 @@ macro_rules! geu_instr {
140172
}};
141173
}
142174

175+
/// Greater than instruction
176+
macro_rules! gts_instr {
177+
($ty:ty, $stack:ident) => {{
178+
let [a, b] = $stack.values.pop_n_const::<2>()?;
179+
let a: $ty = a.into();
180+
let b: $ty = b.into();
181+
182+
$stack.values.push(((a > b) as i32).into());
183+
}};
184+
}
185+
186+
/// Greater than instruction (convert to unsigned before comparison)
187+
macro_rules! gtu_instr {
188+
($ty:ty, $uty:ty, $stack:ident) => {{
189+
let [a, b] = $stack.values.pop_n_const::<2>()?;
190+
let a: $ty = a.into();
191+
let b: $ty = b.into();
192+
// Cast to unsigned type before comparison
193+
let a_unsigned: $uty = a as $uty;
194+
let b_unsigned: $uty = b as $uty;
195+
$stack.values.push(((a_unsigned > b_unsigned) as i32).into());
196+
}};
197+
}
198+
199+
/// Convert the top value on the stack to a specific type
200+
macro_rules! conv_1 {
201+
($from:ty, $to:ty, $stack:ident) => {{
202+
let a: $from = $stack.values.pop()?.into();
203+
$stack.values.push((a as $to).into());
204+
}};
205+
}
206+
207+
/// Convert the unsigned value on the top of the stack to a specific type
208+
macro_rules! conv_2 {
209+
($ty:ty, $uty:ty, $to:ty, $stack:ident) => {{
210+
let a: $ty = $stack.values.pop()?.into();
211+
$stack.values.push((a as $uty as $to).into());
212+
}};
213+
}
214+
143215
pub(super) use add_instr;
144216
pub(super) use checked_divs_instr;
145217
pub(super) use checked_divu_instr;
218+
pub(super) use conv_1;
219+
pub(super) use conv_2;
146220
pub(super) use div_instr;
147221
pub(super) use eq_instr;
148222
pub(super) use eqz_instr;
149223
pub(super) use ges_instr;
150224
pub(super) use geu_instr;
225+
pub(super) use gts_instr;
226+
pub(super) use gtu_instr;
227+
pub(super) use les_instr;
228+
pub(super) use leu_instr;
151229
pub(super) use lts_instr;
152230
pub(super) use ltu_instr;
153231
pub(super) use mul_instr;

crates/tinywasm/src/runtime/executor/mod.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,9 @@ fn exec_one(
7777
store: &mut Store,
7878
module: &ModuleInstance,
7979
) -> Result<ExecResult> {
80-
use tinywasm_types::Instruction::*;
81-
8280
info!("ptr: {} instr: {:?}", cf.instr_ptr, instr);
8381

82+
use tinywasm_types::Instruction::*;
8483
match instr {
8584
Nop => { /* do nothing */ }
8685
Unreachable => return Ok(ExecResult::Trap(crate::Trap::Unreachable)), // we don't need to include the call frame here because it's already on the stack
@@ -224,17 +223,33 @@ fn exec_one(
224223
F32Lt => lts_instr!(f32, stack),
225224
F64Lt => lts_instr!(f64, stack),
226225

226+
I32LeS => les_instr!(i32, stack),
227+
I64LeS => les_instr!(i64, stack),
228+
I32LeU => leu_instr!(i32, u32, stack),
229+
I64LeU => leu_instr!(i64, u64, stack),
230+
F32Le => les_instr!(f32, stack),
231+
F64Le => les_instr!(f64, stack),
232+
227233
I32GeS => ges_instr!(i32, stack),
228234
I64GeS => ges_instr!(i64, stack),
229235
I32GeU => geu_instr!(i32, u32, stack),
230236
I64GeU => geu_instr!(i64, u64, stack),
231237
F32Ge => ges_instr!(f32, stack),
232238
F64Ge => ges_instr!(f64, stack),
233239

240+
I32GtS => gts_instr!(i32, stack),
241+
I64GtS => gts_instr!(i64, stack),
242+
I32GtU => gtu_instr!(i32, u32, stack),
243+
I64GtU => gtu_instr!(i64, u64, stack),
244+
F32Gt => gts_instr!(f32, stack),
245+
F64Gt => gts_instr!(f64, stack),
246+
247+
// these can trap
234248
I32DivS => checked_divs_instr!(i32, stack),
235249
I64DivS => checked_divs_instr!(i64, stack),
236250
I32DivU => checked_divu_instr!(i32, u32, stack),
237251
I64DivU => checked_divu_instr!(i64, u64, stack),
252+
238253
F32Div => div_instr!(f32, stack),
239254
F64Div => div_instr!(f64, stack),
240255

@@ -255,6 +270,24 @@ fn exec_one(
255270
F32Ne => ne_instr!(f32, stack),
256271
F64Ne => ne_instr!(f64, stack),
257272

273+
F32ConvertI32S => conv_1!(i32, f32, stack),
274+
F32ConvertI64S => conv_1!(i64, f32, stack),
275+
F64ConvertI32S => conv_1!(i32, f64, stack),
276+
F64ConvertI64S => conv_1!(i64, f64, stack),
277+
F32ConvertI32U => conv_2!(i32, u32, f32, stack),
278+
F32ConvertI64U => conv_2!(i64, u64, f32, stack),
279+
F64ConvertI32U => conv_2!(i32, u32, f64, stack),
280+
F64ConvertI64U => conv_2!(i64, u64, f64, stack),
281+
I64ExtendI32U => conv_2!(i32, u32, i64, stack),
282+
I64ExtendI32S => conv_1!(i32, i64, stack),
283+
I32WrapI64 => conv_1!(i64, i32, stack),
284+
285+
// no-op instructions since types are erased at runtime
286+
I32ReinterpretF32 => {}
287+
I64ReinterpretF64 => {}
288+
F32ReinterpretI32 => {}
289+
F64ReinterpretI64 => {}
290+
258291
i => todo!("{:?}", i),
259292
};
260293

0 commit comments

Comments
 (0)