aboutsummaryrefslogblamecommitdiffhomepage
path: root/examples/fib.rs
blob: e523b9d2d6fc3befb04808b860bad368d5aa71f3 (plain) (tree)
1
2
3
4
5
6
7




                                                                                                   
                             
                          





























































                                                                     

                                                                        






                                             
//! Fibonacci example.
//!
//! Jit compile a function at runtime (generate native host code) to compute the fibonacci sequence
//! to demonstrate the [`juicebox_asm`] crate.

use juicebox_asm::prelude::*;
use juicebox_asm::Runtime;

const fn fib_rs(n: u64) -> u64 {
    match n {
        0 => 0,
        1 => 1,
        _ => fib_rs(n - 2) + fib_rs(n - 1),
    }
}

fn main() {
    let mut asm = Asm::new();

    let mut lp = Label::new();
    let mut end = Label::new();

    // Reference implementation:
    //
    // int fib(int n) {
    //   int tmp = 0;
    //   int prv = 1;
    //   int sum = 0;
    // loop:
    //   if (n == 0) goto end;
    //   tmp = sum;
    //   sum += prv;
    //   prv = tmp;
    //   --n;
    //   goto loop;
    // end:
    //   return sum;
    // }

    // SystemV abi:
    //   rdi -> first argument
    //   rax -> return value
    let n = Reg64::rdi;
    let sum = Reg64::rax;

    let tmp = Reg64::rcx;
    let prv = Reg64::rbx;

    asm.mov(tmp, Imm64::from(0));
    asm.mov(prv, Imm64::from(1));
    asm.mov(sum, Imm64::from(0));

    asm.bind(&mut lp);
    asm.test(n, n);
    asm.jz(&mut end);
    asm.mov(tmp, sum);
    asm.add(sum, prv);
    asm.mov(prv, tmp);
    asm.dec(n);
    asm.jmp(&mut lp);
    asm.bind(&mut end);
    asm.ret();

    // Write out JIT code for visualization.
    // Disassemble for example with `ndisasm -b 64 jit.asm`.
    let code = asm.into_code();
    std::fs::write("jit.asm", &code).unwrap();

    // Move code into executable page and get function pointer to it.
    let mut rt = Runtime::new();
    let fib = unsafe { rt.add_code::<extern "C" fn(u64) -> u64>(code) };

    for n in 0..15 {
        let fib_jit = fib(n);
        println!("fib({}) = {}", n, fib_jit);
        assert_eq!(fib_jit, fib_rs(n));
    }
}