Skip to main content

revmc_codegen/tests/
macros.rs

1macro_rules! matrix_tests {
2    ($run:ident) => {
3        #[cfg(feature = "llvm")]
4        mod llvm {
5            use super::*;
6            #[allow(unused_imports)]
7            use similar_asserts::assert_eq;
8
9            fn run_llvm(compiler: &mut EvmCompiler<revmc_llvm::EvmLlvmBackend>) {
10                if std::env::var_os("REVMC_TEST_DUMP").is_some() {
11                    crate::tests::set_test_dump(compiler, module_path!());
12                }
13                $run(compiler);
14            }
15
16            #[test]
17            fn unopt() {
18                crate::tests::with_jit_compiler(revmc_backend::OptimizationLevel::None, run_llvm);
19            }
20
21            #[test]
22            fn opt() {
23                crate::tests::with_jit_compiler(
24                    revmc_backend::OptimizationLevel::default(),
25                    run_llvm,
26                );
27            }
28        }
29    };
30
31    ($name:ident = | $compiler:ident | $e:expr) => {
32        mod $name {
33            use super::*;
34            #[allow(unused_imports)]
35            use similar_asserts::assert_eq;
36
37            fn run_generic<B: Backend>($compiler: &mut EvmCompiler<B>) {
38                $e;
39            }
40
41            matrix_tests!(run_generic);
42        }
43    };
44    ($name:ident = $run:ident) => {
45        mod $name {
46            use super::*;
47            #[allow(unused_imports)]
48            use similar_asserts::assert_eq;
49
50            matrix_tests!($run);
51        }
52    };
53}
54
55macro_rules! build_push32 {
56    ($code:ident[$i:ident], $x:expr) => {{
57        $code[$i] = op::PUSH32;
58        $i += 1;
59        $code[$i..$i + 32].copy_from_slice(&$x.to_be_bytes::<32>());
60        $i += 32;
61    }};
62}
63
64macro_rules! tests {
65    ($($group:ident { $($t:tt)* })*) => { uint! {
66        $(
67            mod $group {
68                use super::*;
69                #[allow(unused_imports)]
70                use similar_asserts::assert_eq;
71
72                tests!(@cases $($t)*);
73            }
74        )*
75    }};
76
77    (@cases $( $name:ident($($t:tt)*) ),* $(,)?) => {
78        $(
79            matrix_tests!($name = |jit| run_test_case(tests!(@case $($t)*), jit));
80            tests!(@maybe_opaque $name($($t)*));
81        )*
82    };
83
84    // Generate companion tests for every const/dynamic operand combination.
85    // Dynamic operands use MSTORE+MLOAD to make them invisible to the compiler.
86    (@maybe_opaque $name:ident(@raw { $($fields:tt)* })) => {};
87    (@maybe_opaque $name:ident($op:expr, $a:expr => $($ret:expr),* $(; $($_r1:tt)*)?)) => {
88        paste::paste! {
89            matrix_tests!([<$name _dyn>] = |jit| run_test_case(
90                &TestCase {
91                    bytecode: &bytecode_unop_opaque($op, $a),
92                    expected_stack: &[$($ret),*],
93                    expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
94                    expected_gas: GAS_WHAT_INTERPRETER_SAYS,
95                    ..Default::default()
96                },
97                jit,
98            ));
99        }
100    };
101    (@maybe_opaque $name:ident($op:expr, $a:expr, $b:expr => $($ret:expr),* $(; $($_r2:tt)*)?)) => {
102        paste::paste! {
103            tests!(@mixed_binop [<$name _const_dyn>] $op, $a, $b, true, false => $($ret),*);
104            tests!(@mixed_binop [<$name _dyn_const>] $op, $a, $b, false, true => $($ret),*);
105            tests!(@mixed_binop [<$name _dyn_dyn>] $op, $a, $b, false, false => $($ret),*);
106        }
107    };
108    (@maybe_opaque $name:ident($op:expr, $a:expr, $b:expr, $c:expr => $($ret:expr),* $(; $($_r3:tt)*)?)) => {
109        paste::paste! {
110            tests!(@mixed_ternop [<$name _const_const_dyn>] $op, $a, $b, $c, true, true, false => $($ret),*);
111            tests!(@mixed_ternop [<$name _const_dyn_const>] $op, $a, $b, $c, true, false, true => $($ret),*);
112            tests!(@mixed_ternop [<$name _const_dyn_dyn>] $op, $a, $b, $c, true, false, false => $($ret),*);
113            tests!(@mixed_ternop [<$name _dyn_const_const>] $op, $a, $b, $c, false, true, true => $($ret),*);
114            tests!(@mixed_ternop [<$name _dyn_const_dyn>] $op, $a, $b, $c, false, true, false => $($ret),*);
115            tests!(@mixed_ternop [<$name _dyn_dyn_const>] $op, $a, $b, $c, false, false, true => $($ret),*);
116            tests!(@mixed_ternop [<$name _dyn_dyn_dyn>] $op, $a, $b, $c, false, false, false => $($ret),*);
117        }
118    };
119
120    (@mixed_binop $name:ident $op:expr, $a:expr, $b:expr, $a_const:expr, $b_const:expr => $($ret:expr),*) => {
121        matrix_tests!($name = |jit| run_test_case(
122            &TestCase {
123                bytecode: &bytecode_binop_mixed($op, $a, $b, $a_const, $b_const),
124                expected_stack: &[$($ret),*],
125                expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
126                expected_gas: GAS_WHAT_INTERPRETER_SAYS,
127                ..Default::default()
128            },
129            jit,
130        ));
131    };
132
133    (@mixed_ternop $name:ident $op:expr, $a:expr, $b:expr, $c:expr, $a_const:expr, $b_const:expr, $c_const:expr => $($ret:expr),*) => {
134        matrix_tests!($name = |jit| run_test_case(
135            &TestCase {
136                bytecode: &bytecode_ternop_mixed($op, $a, $b, $c, $a_const, $b_const, $c_const),
137                expected_stack: &[$($ret),*],
138                expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
139                expected_gas: GAS_WHAT_INTERPRETER_SAYS,
140                ..Default::default()
141            },
142            jit,
143        ));
144    };
145
146    (@case @raw { $($fields:tt)* }) => { &TestCase { $($fields)* ..Default::default() } };
147
148    (@case $op:expr $(, $args:expr)* $(,)? => $($ret:expr),* $(,)? $(; op_gas($op_gas:expr))?) => {
149        &TestCase {
150            bytecode: &tests!(@bytecode $op, $($args),*),
151            expected_stack: &[$($ret),*],
152            expected_gas: tests!(@gas $op $(, $op_gas)?; $($args),*),
153            ..Default::default()
154        }
155    };
156
157    (@bytecode $op:expr, $a:expr) => { bytecode_unop($op, $a) };
158    (@bytecode $op:expr, $a:expr, $b:expr) => { bytecode_binop($op, $a, $b) };
159    (@bytecode $op:expr, $a:expr, $b:expr, $c:expr) => { bytecode_ternop($op, $a, $b, $c) };
160
161    (@gas $op:expr; $($args:expr),+) => {
162        tests!(@gas
163            $op,
164            DEF_OPINFOS[$op as usize].base_gas() as u64;
165            $($args),+
166        )
167    };
168    (@gas $op:expr, $op_gas:expr; $($args:expr),+) => {
169        $op_gas + tests!(@gas_base $($args),+)
170    };
171    (@gas_base $a:expr) => { 3 };
172    (@gas_base $a:expr, $b:expr) => { 6 };
173    (@gas_base $a:expr, $b:expr, $c:expr) => { 9 };
174}