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

Commit b4cb5f9

Browse files
chore: simplify instruction macros
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
1 parent 197c32f commit b4cb5f9

File tree

4 files changed

+119
-250
lines changed

4 files changed

+119
-250
lines changed
Lines changed: 50 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -1,233 +1,97 @@
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.
1+
//! More generic macros for various instructions
2+
//!
3+
//! These macros are used to generate the actual instruction implementations.
74
8-
/// Add two values from the stack
9-
macro_rules! add_instr {
10-
($ty:ty, $stack:ident) => {{
11-
let [a, b] = $stack.values.pop_n_const::<2>()?;
12-
let a: $ty = a.into();
13-
let b: $ty = b.into();
14-
$stack.values.push((a + b).into());
15-
}};
16-
}
17-
18-
/// Subtract the top two values on the stack
19-
macro_rules! sub_instr {
20-
($ty:ty, $stack:ident) => {{
21-
let [a, b] = $stack.values.pop_n_const::<2>()?;
22-
let a: $ty = a.into();
23-
let b: $ty = b.into();
24-
$stack.values.push((a - b).into());
25-
}};
26-
}
27-
28-
/// Divide the top two values on the stack
29-
macro_rules! checked_divs_instr {
30-
($ty:ty, $stack:ident) => {{
31-
let [a, b] = $stack.values.pop_n_const::<2>()?;
32-
let a: $ty = a.into();
33-
let b: $ty = b.into();
34-
let Some(res) = a.checked_div(b) else {
35-
return Err(Error::Trap(crate::Trap::DivisionByZero));
36-
};
37-
38-
$stack.values.push(res.into());
39-
}};
40-
}
41-
42-
/// Divide the top two values on the stack
43-
macro_rules! checked_divu_instr {
44-
($ty:ty, $uty:ty, $stack:ident) => {{
45-
let [a, b] = $stack.values.pop_n_const::<2>()?;
46-
let a: $ty = a.into();
47-
let b: $ty = b.into();
48-
let Some(res) = (a as $uty).checked_div(b as $uty) else {
49-
return Err(Error::Trap(crate::Trap::DivisionByZero));
50-
};
51-
52-
$stack.values.push((res as $ty).into());
53-
}};
54-
}
55-
56-
/// Divide the top two values on the stack
57-
macro_rules! div_instr {
58-
($ty:ty, $stack:ident) => {{
59-
let [a, b] = $stack.values.pop_n_const::<2>()?;
60-
let a: $ty = a.into();
61-
let b: $ty = b.into();
62-
$stack.values.push((a / b).into());
63-
}};
64-
}
65-
66-
/// Less than signed instruction
67-
macro_rules! lts_instr {
68-
($ty:ty, $stack:ident) => {{
69-
let [a, b] = $stack.values.pop_n_const::<2>()?;
70-
let a: $ty = a.into();
71-
let b: $ty = b.into();
72-
$stack.values.push(((a < b) as i32).into());
5+
/// Convert the top value on the stack to a specific type
6+
macro_rules! conv_1 {
7+
($from:ty, $to:ty, $stack:ident) => {{
8+
let a: $from = $stack.values.pop()?.into();
9+
$stack.values.push((a as $to).into());
7310
}};
7411
}
7512

76-
/// Less than unsigned instruction
77-
macro_rules! ltu_instr {
78-
($ty:ty, $uty:ty, $stack:ident) => {{
79-
let [a, b] = $stack.values.pop_n_const::<2>()?;
80-
let a: $ty = a.into();
81-
let b: $ty = b.into();
82-
// Cast to unsigned type before comparison
83-
let a_unsigned: $uty = a as $uty;
84-
let b_unsigned: $uty = b as $uty;
85-
$stack.values.push(((a_unsigned < b_unsigned) as i32).into());
13+
/// Convert the unsigned value on the top of the stack to a specific type
14+
macro_rules! conv_2 {
15+
($ty:ty, $uty:ty, $to:ty, $stack:ident) => {{
16+
let a: $ty = $stack.values.pop()?.into();
17+
$stack.values.push((a as $uty as $to).into());
8618
}};
8719
}
8820

89-
/// Less than equal signed instruction
90-
macro_rules! les_instr {
91-
($ty:ty, $stack:ident) => {{
21+
/// Compare two values on the stack
22+
macro_rules! comp {
23+
($op:tt, $ty:ty, $stack:ident) => {{
9224
let [a, b] = $stack.values.pop_n_const::<2>()?;
9325
let a: $ty = a.into();
9426
let b: $ty = b.into();
95-
96-
$stack.values.push(((a <= b) as i32).into());
27+
$stack.values.push(((a $op b) as i32).into());
9728
}};
9829
}
9930

100-
/// Less than equal unsigned instruction
101-
macro_rules! leu_instr {
102-
($ty:ty, $uty:ty, $stack:ident) => {{
31+
/// Compare two values on the stack (cast to ty2 before comparison)
32+
macro_rules! comp_cast {
33+
($op:tt, $ty:ty, $ty2:ty, $stack:ident) => {{
10334
let [a, b] = $stack.values.pop_n_const::<2>()?;
10435
let a: $ty = a.into();
10536
let b: $ty = b.into();
10637

10738
// 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-
114-
/// Multiply the top two values on the stack
115-
macro_rules! mul_instr {
116-
($ty:ty, $stack:ident) => {{
117-
let [a, b] = $stack.values.pop_n_const::<2>()?;
118-
let a: $ty = a.into();
119-
let b: $ty = b.into();
120-
$stack.values.push((a * b).into());
39+
let a_unsigned: $ty2 = a as $ty2;
40+
let b_unsigned: $ty2 = b as $ty2;
41+
$stack.values.push(((a_unsigned $op b_unsigned) as i32).into());
12142
}};
12243
}
12344

124-
/// Compare the top two values on the stack for equality
125-
macro_rules! eq_instr {
126-
($ty:ty, $stack:ident) => {{
127-
let [a, b] = $stack.values.pop_n_const::<2>()?;
128-
let a: $ty = a.into();
129-
let b: $ty = b.into();
130-
$stack.values.push(((a == b) as i32).into());
131-
}};
132-
}
133-
134-
/// Compare the top value on the stack for equality with zero
135-
macro_rules! eqz_instr {
136-
($ty:ty, $stack:ident) => {{
45+
/// Compare a value on the stack to zero
46+
macro_rules! comp_zero {
47+
($op:tt, $ty:ty, $stack:ident) => {{
13748
let a: $ty = $stack.values.pop()?.into();
138-
$stack.values.push(((a == 0) as i32).into());
49+
$stack.values.push(((a $op 0) as i32).into());
13950
}};
14051
}
14152

142-
/// Compare the top two values on the stack for inequality
143-
macro_rules! ne_instr {
144-
($ty:ty, $stack:ident) => {{
53+
/// Apply an arithmetic operation to two values on the stack
54+
macro_rules! arithmetic {
55+
($op:tt, $ty:ty, $stack:ident) => {{
14556
let [a, b] = $stack.values.pop_n_const::<2>()?;
14657
let a: $ty = a.into();
14758
let b: $ty = b.into();
148-
$stack.values.push(((a != b) as i32).into());
59+
$stack.values.push((a $op b).into());
14960
}};
15061
}
15162

152-
/// Greater or equal than signed instruction
153-
macro_rules! ges_instr {
154-
($ty:ty, $stack:ident) => {{
63+
/// Apply an arithmetic operation to two values on the stack
64+
macro_rules! checked_arithmetic {
65+
($op:ident, $ty:ty, $stack:ident, $trap:expr) => {{
15566
let [a, b] = $stack.values.pop_n_const::<2>()?;
15667
let a: $ty = a.into();
15768
let b: $ty = b.into();
158-
$stack.values.push(((a >= b) as i32).into());
69+
let result = a.$op(b).ok_or_else(|| Error::Trap($trap))?;
70+
$stack.values.push(result.into());
15971
}};
16072
}
16173

162-
/// Greater or equal than unsigned instruction
163-
macro_rules! geu_instr {
164-
($ty:ty, $uty:ty, $stack:ident) => {{
74+
/// Apply an arithmetic operation to two values on the stack (cast to ty2 before operation)
75+
macro_rules! checked_arithmetic_cast {
76+
($op:ident, $ty:ty, $ty2:ty, $stack:ident, $trap:expr) => {{
16577
let [a, b] = $stack.values.pop_n_const::<2>()?;
16678
let a: $ty = a.into();
16779
let b: $ty = b.into();
168-
// Cast to unsigned type before comparison
169-
let a_unsigned: $uty = a as $uty;
170-
let b_unsigned: $uty = b as $uty;
171-
$stack.values.push(((a_unsigned >= b_unsigned) as i32).into());
172-
}};
173-
}
17480

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();
81+
// Cast to unsigned type before operation
82+
let a_unsigned: $ty2 = a as $ty2;
83+
let b_unsigned: $ty2 = b as $ty2;
18184

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());
85+
let result = a_unsigned.$op(b_unsigned).ok_or_else(|| Error::Trap($trap))?;
86+
$stack.values.push((result as $ty).into());
21287
}};
21388
}
21489

215-
pub(super) use add_instr;
216-
pub(super) use checked_divs_instr;
217-
pub(super) use checked_divu_instr;
90+
pub(super) use arithmetic;
91+
pub(super) use checked_arithmetic;
92+
pub(super) use checked_arithmetic_cast;
93+
pub(super) use comp;
94+
pub(super) use comp_cast;
95+
pub(super) use comp_zero;
21896
pub(super) use conv_1;
21997
pub(super) use conv_2;
220-
pub(super) use div_instr;
221-
pub(super) use eq_instr;
222-
pub(super) use eqz_instr;
223-
pub(super) use ges_instr;
224-
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;
229-
pub(super) use lts_instr;
230-
pub(super) use ltu_instr;
231-
pub(super) use mul_instr;
232-
pub(super) use ne_instr;
233-
pub(super) use sub_instr;

0 commit comments

Comments
 (0)