1use super::{DEF_SPEC, with_evm_context};
2use crate::{Backend, EvmCompiler};
3use paste::paste;
4use revm_bytecode::opcode as op;
5use revm_interpreter::InstructionResult;
6use revm_primitives::U256;
7
8macro_rules! fibonacci_tests {
9 ($($i:expr),* $(,)?) => {paste! {
10 $(
11 matrix_tests!([<native_ $i>] = |jit| run_fibonacci_test(jit, $i, false));
12 matrix_tests!([<dynamic_ $i>] = |jit| run_fibonacci_test(jit, $i, true));
13 )*
14 }};
15}
16
17fibonacci_tests!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 100, 1000);
18
19fn run_fibonacci_test<B: Backend>(compiler: &mut EvmCompiler<B>, input: u16, dynamic: bool) {
20 let code = mk_fibonacci_code(input, dynamic);
21
22 unsafe { compiler.clear() }.unwrap();
23 compiler.inspect_stack(true);
24 let f = unsafe { compiler.jit("fib", &code, DEF_SPEC) }.unwrap();
25
26 with_evm_context(&code, DEF_SPEC, |ecx, stack, stack_len| {
27 if dynamic {
28 stack.set(0, U256::from(input).into());
29 *stack_len = 1;
30 }
31 let r = unsafe { f.call(stack, stack_len, ecx) };
32 assert_eq!(r, InstructionResult::Stop);
33 assert_eq!(*stack_len, 1);
35 assert_eq!(unsafe { stack.as_slice(*stack_len) }[0].to_u256(), fibonacci_rust(input + 1));
36 });
37}
38
39fn mk_fibonacci_code(input: u16, dynamic: bool) -> Vec<u8> {
40 if dynamic {
41 [&[op::JUMPDEST; 3][..], FIBONACCI_CODE].concat()
42 } else {
43 let input = input.to_be_bytes();
44 [[op::PUSH2].as_slice(), input.as_slice(), FIBONACCI_CODE].concat()
45 }
46}
47
48#[rustfmt::skip]
50const FIBONACCI_CODE: &[u8] = &[
51 op::PUSH1, 0,
56 op::PUSH1, 1,
57 op::JUMPDEST,
61 op::DUP3,
62 op::ISZERO,
63 op::PUSH1, 28, op::JUMPI,
65
66 op::DUP2,
68 op::DUP2,
69 op::ADD,
70 op::SWAP2,
71 op::POP,
72 op::SWAP1,
73 op::SWAP2,
77 op::PUSH1, 1,
78 op::SWAP1,
79 op::SUB,
80 op::SWAP2,
81 op::PUSH1, 7, op::JUMP,
83 op::JUMPDEST,
87 op::SWAP2,
88 op::POP,
89 op::POP,
90 op::STOP,
92];
93
94fn fibonacci_rust(n: u16) -> U256 {
95 let mut a = U256::from(0);
96 let mut b = U256::from(1);
97 for _ in 0..n {
98 let tmp = a;
99 a = b;
100 b = b.wrapping_add(tmp);
101 }
102 a
103}
104
105#[test]
106fn test_fibonacci_rust() {
107 revm_primitives::uint! {
108 assert_eq!(fibonacci_rust(0), 0_U256);
109 assert_eq!(fibonacci_rust(1), 1_U256);
110 assert_eq!(fibonacci_rust(2), 1_U256);
111 assert_eq!(fibonacci_rust(3), 2_U256);
112 assert_eq!(fibonacci_rust(4), 3_U256);
113 assert_eq!(fibonacci_rust(5), 5_U256);
114 assert_eq!(fibonacci_rust(6), 8_U256);
115 assert_eq!(fibonacci_rust(7), 13_U256);
116 assert_eq!(fibonacci_rust(8), 21_U256);
117 assert_eq!(fibonacci_rust(9), 34_U256);
118 assert_eq!(fibonacci_rust(10), 55_U256);
119 assert_eq!(fibonacci_rust(100), 354224848179261915075_U256);
120 assert_eq!(fibonacci_rust(1000), 0x2e3510283c1d60b00930b7e8803c312b4c8e6d5286805fc70b594dc75cc0604b_U256);
121 }
122}