use crate::{checker, fuzzing::func, ion};
use arbitrary::{Arbitrary, Result, Unstructured};
use core::cell::RefCell;
use std::thread_local;
const OPTIONS: func::Options = func::Options {
reused_inputs: true,
fixed_regs: true,
fixed_nonallocatable: true,
clobbers: true,
reftypes: true,
callsite_ish_constraints: true,
..func::Options::DEFAULT
};
#[derive(Clone, Debug)]
pub struct TestCase {
func: func::Func,
annotate: bool,
check_ssa: bool,
}
impl Arbitrary<'_> for TestCase {
fn arbitrary(u: &mut Unstructured) -> Result<TestCase> {
let func = func::Func::arbitrary_with_options(u, &OPTIONS)?;
let annotate = bool::arbitrary(u)?;
let check_ssa = bool::arbitrary(u)?;
Ok(TestCase {
func,
annotate,
check_ssa,
})
}
}
pub fn check(t: TestCase) {
let TestCase {
func,
annotate,
check_ssa,
} = &t;
log::trace!("func:\n{func:?}");
let env = func::machine_env();
thread_local! {
static CTX: RefCell<ion::Ctx> = RefCell::default();
}
CTX.with(|ctx| {
ion::run(func, &env, &mut *ctx.borrow_mut(), *annotate, *check_ssa)
.expect("regalloc did not succeed");
let mut checker = checker::Checker::new(func, &env);
checker.prepare(&ctx.borrow().output);
checker.run().expect("checker failed");
});
}
#[test]
fn smoke() {
arbtest::arbtest(|u| {
let test_case = TestCase::arbitrary(u)?;
check(test_case);
Ok(())
})
.budget_ms(1_000);
}