Skip to content

Commit

Permalink
Translate doctests into explicit tests
Browse files Browse the repository at this point in the history
Ideally this would not be necessary, but gettin Tarpaulin to compute coverage
for doctests (xd009642/tarpaulin#13) is supported, but trickier than it first
appears. For me, the following command appears to hang during the compilation
of a transitively-required crate:

    cargo tarpaulin --verbose --run-types Tests,Doctests

so as a workaround to institute coverage, the doctests are duplicated as
explicit tests.
  • Loading branch information
kulp committed May 11, 2020
1 parent 24d3069 commit 9a32fad
Showing 1 changed file with 129 additions and 0 deletions.
129 changes: 129 additions & 0 deletions src/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,133 @@ mod tests {
Reg::F(jit.f_num()-1).to_ffi();
Reg::F(0).to_ffi();
}

#[test]
fn test_printf() {
use std::ffi::CString;
use crate::{Jit, JitWord, Reg, JitPointer};
use std::convert::TryInto;

let jit = Jit::new();
let js = jit.new_state();

// make sure this outlives any calls
let cs = CString::new("generated %d bytes\n").unwrap();

let start = js.note(file!(), line!());
js.prolog();
let inarg = js.arg();
js.getarg(Reg::R(1), &inarg);
js.prepare();
js.pushargi(cs.as_ptr() as JitWord);
js.ellipsis();
js.pushargr(Reg::R(1));
js.finishi(libc::printf as JitPointer);
js.ret();
js.epilog();
let end = js.note(file!(), line!());

let my_function = unsafe{ js.emit::<extern fn(JitWord)>() };
/* call the generated code, passing its size as argument */
my_function((js.address(&end) as u64 - js.address(&start) as u64).try_into().unwrap());
js.clear();

// TODO: dissasembly has not been implemented yet
// js.dissasemble();
}

#[test]
fn test_fibonacci() {
use crate::{Jit, JitWord, Reg, JitPointer, NULL};

let jit = Jit::new();
let js = jit.new_state();

let label = js.label();
js.prolog();
let inarg = js.arg();
js.getarg(Reg::R(0), &inarg);
let zero = js.beqi(Reg::R(0), 0);
js.movr(Reg::V(0), Reg::R(0));
js.movi(Reg::R(0), 1);
let refr = js.blei(Reg::V(0), 2);
js.subi(Reg::V(1), Reg::V(0), 1);
js.subi(Reg::V(2), Reg::V(0), 2);
js.prepare();
js.pushargr(Reg::V(1));
let call = js.finishi(NULL);
js.patch_at(&call, &label);
js.retval(Reg::V(1));
js.prepare();
js.pushargr(Reg::V(2));
let call2 = js.finishi(NULL);
js.patch_at(&call2, &label);
js.retval(Reg::R(0));
js.addr(Reg::R(0), Reg::R(0), Reg::V(1));

js.patch(&refr);
js.patch(&zero);
js.retr(Reg::R(0));
js.epilog();

let fib = unsafe{ js.emit::<extern fn(JitWord) -> JitWord>() };
js.clear();

println!("fib({})={}", 32, fib(32));
assert_eq!(0, fib(0));
assert_eq!(1, fib(1));
assert_eq!(1, fib(2));
assert_eq!(2178309, fib(32));
}

#[test]
fn test_factorial() {
use crate::{Jit, JitWord, Reg, NULL};

let jit = Jit::new();
let js = jit.new_state();

let fact = js.forward();

js.prolog();
let inarg = js.arg();
js.getarg(Reg::R(0), &inarg);
js.prepare();
js.pushargi(1);
js.pushargr(Reg::R(0));
let call = js.finishi(NULL);
js.patch_at(&call, &fact);

js.retval(Reg::R(0));
js.retr(Reg::R(0));
js.epilog();

js.link(&fact);
js.prolog();
js.frame(16);
let f_ent = js.label(); // TCO entry point
let ac = js.arg();
let ina = js.arg();
js.getarg(Reg::R(0), &ac);
js.getarg(Reg::R(1), &ina);
let f_out = js.blei(Reg::R(1), 1);
js.mulr(Reg::R(0), Reg::R(0), Reg::R(1));
js.putargr(Reg::R(0), &ac);
js.subi(Reg::R(1), Reg::R(1), 1);
js.putargr(Reg::R(1), &ina);
let jump = js.jmpi(); // tail call optimiation
js.patch_at(&jump, &f_ent);
js.patch(&f_out);
js.retr(Reg::R(0));

let factorial = unsafe{ js.emit::<extern fn(JitWord) -> JitWord>() };
js.clear();

println!("factorial({}) = {}", 5, factorial(5));
assert_eq!(1, factorial(1));
assert_eq!(2, factorial(2));
assert_eq!(6, factorial(3));
assert_eq!(24, factorial(4));
assert_eq!(120, factorial(5));
}
}

0 comments on commit 9a32fad

Please sign in to comment.