cranelift_filetests/
test_compile.rs1use crate::subtest::{check_precise_output, run_filecheck, Context, SubTest};
6use anyhow::Result;
7use cranelift_codegen::ir;
8use cranelift_reader::{TestCommand, TestOption};
9use log::info;
10use std::borrow::Cow;
11
12struct TestCompile {
13 precise_output: bool,
18 expect_fail: bool,
20}
21
22pub fn subtest(parsed: &TestCommand) -> Result<Box<dyn SubTest>> {
23 assert_eq!(parsed.command, "compile");
24 let mut test = TestCompile {
25 precise_output: false,
26 expect_fail: false,
27 };
28 for option in parsed.options.iter() {
29 match option {
30 TestOption::Flag("precise-output") => test.precise_output = true,
31 TestOption::Flag("expect-fail") => test.expect_fail = true,
32 _ => anyhow::bail!("unknown option on {}", parsed),
33 }
34 }
35 Ok(Box::new(test))
36}
37
38impl SubTest for TestCompile {
39 fn name(&self) -> &'static str {
40 "compile"
41 }
42
43 fn is_mutating(&self) -> bool {
44 true
45 }
46
47 fn needs_isa(&self) -> bool {
48 true
49 }
50
51 fn run(&self, func: Cow<ir::Function>, context: &Context) -> Result<()> {
52 let isa = context.isa.expect("compile needs an ISA");
53 let params = func.params.clone();
54 let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned());
55
56 comp_ctx.set_disasm(true);
58
59 let compiled_code = comp_ctx.compile(isa, &mut Default::default());
60
61 let compiled_code = if self.expect_fail {
62 if compiled_code.is_ok() {
63 anyhow::bail!("Expected compilation failure but compilation succeeded");
64 }
65 return Ok(());
66 } else {
67 compiled_code.map_err(|e| crate::pretty_anyhow_error(&e.func, e.inner))?
68 };
69 let total_size = compiled_code.code_info().total_size;
70
71 let vcode = compiled_code.vcode.as_ref().unwrap();
72
73 info!("Generated {} bytes of code:\n{}", total_size, vcode);
74
75 if self.precise_output {
76 let dis = match isa.triple().architecture {
77 target_lexicon::Architecture::Pulley32 | target_lexicon::Architecture::Pulley64 => {
78 let mut disas =
82 pulley_interpreter::disas::Disassembler::new(compiled_code.buffer.data());
83 disas.hexdump(false).offsets(false);
84 pulley_interpreter::decode::Decoder::decode_all(&mut disas)?;
85 disas.disas().to_string()
86 }
87 _ => {
88 let cs = isa
89 .to_capstone()
90 .map_err(|e| anyhow::format_err!("{}", e))?;
91 compiled_code.disassemble(Some(¶ms), &cs)?
92 }
93 };
94
95 let actual = Vec::from_iter(
96 std::iter::once("VCode:")
97 .chain(compiled_code.vcode.as_ref().unwrap().lines())
98 .chain(["", "Disassembled:"])
99 .chain(dis.lines()),
100 );
101
102 check_precise_output(&actual, context)
103 } else {
104 run_filecheck(&vcode, context)
105 }
106 }
107}