fib/
fib.rs

1// SPDX-License-Identifier: MIT
2//
3// Copyright (c) 2023, Johannes Stoelp <dev@memzero.de>
4
5//! Fibonacci example.
6//!
7//! Jit compile a function at runtime (generate native host code) to compute the fibonacci sequence
8//! to demonstrate the [`juicebox_asm`] crate.
9
10use juicebox_asm::insn::*;
11use juicebox_asm::Runtime;
12use juicebox_asm::{Asm, Imm64, Label, Reg64};
13
14const fn fib_rs(n: u64) -> u64 {
15    match n {
16        0 => 0,
17        1 => 1,
18        _ => fib_rs(n - 2) + fib_rs(n - 1),
19    }
20}
21
22fn main() {
23    let mut asm = Asm::new();
24
25    let mut lp = Label::new();
26    let mut end = Label::new();
27
28    // Reference implementation:
29    //
30    // int fib(int n) {
31    //   int tmp = 0;
32    //   int prv = 1;
33    //   int sum = 0;
34    // loop:
35    //   if (n == 0) goto end;
36    //   tmp = sum;
37    //   sum += prv;
38    //   prv = tmp;
39    //   --n;
40    //   goto loop;
41    // end:
42    //   return sum;
43    // }
44
45    // SystemV abi:
46    //   rdi -> first argument
47    //   rax -> return value
48    let n = Reg64::rdi;
49    let sum = Reg64::rax;
50
51    let tmp = Reg64::rcx;
52    let prv = Reg64::rdx;
53
54    asm.mov(tmp, Imm64::from(0));
55    asm.mov(prv, Imm64::from(1));
56    asm.mov(sum, Imm64::from(0));
57
58    asm.bind(&mut lp);
59    asm.test(n, n);
60    asm.jz(&mut end);
61    asm.mov(tmp, sum);
62    asm.add(sum, prv);
63    asm.mov(prv, tmp);
64    asm.dec(n);
65    asm.jmp(&mut lp);
66    asm.bind(&mut end);
67    asm.ret();
68
69    // Move code into executable page and get function pointer to it.
70    let mut rt = Runtime::new();
71    let fib = unsafe { rt.add_code::<extern "C" fn(u64) -> u64>(asm.into_code()) };
72
73    // Disassemble JIT code and write to stdout.
74    rt.disasm();
75
76    for n in 0..15 {
77        let fib_jit = fib(n);
78        println!("fib({}) = {}", n, fib_jit);
79        assert_eq!(fib_jit, fib_rs(n));
80    }
81}