Coverage Report

Created: 2026-08-15 07:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasmtime/cranelift/filetests/src/test_compile.rs
Line
Count
Source
1
//! Test command for testing the code generator pipeline
2
//!
3
//! The `compile` test command runs each function through the full code generator pipeline
4
5
use crate::subtest::{Context, SubTest, check_precise_output, run_filecheck};
6
use anyhow::Result;
7
use cranelift_codegen::ir;
8
use cranelift_reader::{TestCommand, TestOption};
9
use log::info;
10
use std::borrow::Cow;
11
12
struct TestCompile {
13
    /// Flag indicating that the text expectation, comments after the function,
14
    /// must be a precise 100% match on the compiled output of the function.
15
    /// This test assertion is also automatically-update-able to allow tweaking
16
    /// the code generator and easily updating all affected tests.
17
    precise_output: bool,
18
    /// Flag indicating that we expect compilation to fail, not succeed.
19
    expect_fail: bool,
20
}
21
22
0
pub fn subtest(parsed: &TestCommand) -> Result<Box<dyn SubTest>> {
23
0
    assert_eq!(parsed.command, "compile");
24
0
    let mut test = TestCompile {
25
0
        precise_output: false,
26
0
        expect_fail: false,
27
0
    };
28
0
    for option in parsed.options.iter() {
29
0
        match option {
30
0
            TestOption::Flag("precise-output") => test.precise_output = true,
31
0
            TestOption::Flag("expect-fail") => test.expect_fail = true,
32
0
            _ => anyhow::bail!("unknown option on {parsed}"),
33
        }
34
    }
35
0
    Ok(Box::new(test))
36
0
}
37
38
impl SubTest for TestCompile {
39
0
    fn name(&self) -> &'static str {
40
0
        "compile"
41
0
    }
42
43
0
    fn is_mutating(&self) -> bool {
44
0
        true
45
0
    }
46
47
0
    fn needs_isa(&self) -> bool {
48
0
        true
49
0
    }
50
51
0
    fn run(&self, func: Cow<ir::Function>, context: &Context) -> Result<()> {
52
0
        let isa = context.isa.expect("compile needs an ISA");
53
0
        let params = func.params.clone();
54
0
        let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned());
55
56
        // With `MachBackend`s, we need to explicitly request disassembly results.
57
0
        comp_ctx.set_disasm(true);
58
59
0
        let compiled_code = comp_ctx.compile(isa, &mut Default::default());
60
61
0
        let compiled_code = if self.expect_fail {
62
0
            if compiled_code.is_ok() {
63
0
                anyhow::bail!("Expected compilation failure but compilation succeeded");
64
0
            }
65
0
            return Ok(());
66
        } else {
67
0
            compiled_code.map_err(|e| crate::pretty_anyhow_error(&e.func, e.inner))?
68
        };
69
0
        let total_size = compiled_code.code_info().total_size;
70
71
0
        let vcode = compiled_code.vcode.as_ref().unwrap();
72
73
0
        info!("Generated {total_size} bytes of code:\n{vcode}");
74
75
0
        if self.precise_output {
76
0
            let dis = match isa.triple().architecture {
77
                target_lexicon::Architecture::Pulley32 | target_lexicon::Architecture::Pulley64 => {
78
                    // Disable hexdumps/offsets to reduce the churn in these
79
                    // tests as instructions are encoded differently and/or
80
                    // their immediates change.
81
0
                    let mut disas =
82
0
                        pulley_interpreter::disas::Disassembler::new(compiled_code.buffer.data());
83
0
                    disas.hexdump(false).offsets(false);
84
0
                    pulley_interpreter::decode::Decoder::decode_all(&mut disas)?;
85
0
                    disas.disas().to_string()
86
                }
87
                _ => {
88
0
                    let cs = isa.to_capstone().map_err(|e| anyhow::format_err!("{e}"))?;
89
0
                    compiled_code.disassemble(Some(&params), &cs)?
90
                }
91
            };
92
93
0
            let actual = Vec::from_iter(
94
0
                std::iter::once("VCode:")
95
0
                    .chain(compiled_code.vcode.as_ref().unwrap().lines())
96
0
                    .chain(["", "Disassembled:"])
97
0
                    .chain(dis.lines()),
98
            );
99
100
0
            check_precise_output(&actual, context)
101
        } else {
102
0
            run_filecheck(&vcode, context)
103
        }
104
0
    }
105
}