Coverage Report

Created: 2025-12-09 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/regalloc2/src/fuzzing/ion.rs
Line
Count
Source
1
//! Fuzz the `ion` register allocator.
2
3
use crate::{checker, fuzzing::func, ion};
4
use arbitrary::{Arbitrary, Result, Unstructured};
5
use core::cell::RefCell;
6
use std::thread_local;
7
8
/// `ion`-specific options for generating functions.
9
const OPTIONS: func::Options = func::Options {
10
    reused_inputs: true,
11
    fixed_regs: true,
12
    fixed_nonallocatable: true,
13
    clobbers: true,
14
    reftypes: true,
15
    callsite_ish_constraints: true,
16
    ..func::Options::DEFAULT
17
};
18
19
/// A convenience wrapper to generate a [`func::Func`] with `ion`-specific
20
/// options enabled.
21
#[derive(Clone, Debug)]
22
pub struct TestCase {
23
    func: func::Func,
24
    annotate: bool,
25
    check_ssa: bool,
26
}
27
28
impl Arbitrary<'_> for TestCase {
29
10.8k
    fn arbitrary(u: &mut Unstructured) -> Result<TestCase> {
30
10.8k
        let func = func::Func::arbitrary_with_options(u, &OPTIONS)?;
31
10.8k
        let annotate = bool::arbitrary(u)?;
32
10.8k
        let check_ssa = bool::arbitrary(u)?;
33
10.8k
        Ok(TestCase {
34
10.8k
            func,
35
10.8k
            annotate,
36
10.8k
            check_ssa,
37
10.8k
        })
38
10.8k
    }
39
}
40
41
/// Test a single function with the `ion` allocator.
42
///
43
/// This also:
44
/// - optionally creates annotations
45
/// - optionally verifies the incoming SSA
46
/// - runs the [`checker`].
47
10.8k
pub fn check(t: TestCase) {
48
    let TestCase {
49
10.8k
        func,
50
10.8k
        annotate,
51
10.8k
        check_ssa,
52
10.8k
    } = &t;
53
10.8k
    log::trace!("func:\n{func:?}");
54
55
10.8k
    let env = func::machine_env();
56
    thread_local! {
57
        // We test that ctx is cleared properly between runs.
58
        static CTX: RefCell<ion::Ctx> = RefCell::default();
59
    }
60
61
10.8k
    CTX.with(|ctx| {
62
10.8k
        ion::run(func, &env, &mut *ctx.borrow_mut(), *annotate, *check_ssa)
63
10.8k
            .expect("regalloc did not succeed");
64
65
10.8k
        let mut checker = checker::Checker::new(func, &env);
66
10.8k
        checker.prepare(&ctx.borrow().output);
67
10.8k
        checker.run().expect("checker failed");
68
10.8k
    });
69
10.8k
}
70
71
#[test]
72
fn smoke() {
73
    arbtest::arbtest(|u| {
74
        let test_case = TestCase::arbitrary(u)?;
75
        check(test_case);
76
        Ok(())
77
    })
78
    .budget_ms(1_000);
79
}