Path: blob/main/cranelift/filetests/src/test_compile.rs
1691 views
//! Test command for testing the code generator pipeline1//!2//! The `compile` test command runs each function through the full code generator pipeline34use crate::subtest::{Context, SubTest, check_precise_output, run_filecheck};5use anyhow::Result;6use cranelift_codegen::ir;7use cranelift_reader::{TestCommand, TestOption};8use log::info;9use std::borrow::Cow;1011struct TestCompile {12/// Flag indicating that the text expectation, comments after the function,13/// must be a precise 100% match on the compiled output of the function.14/// This test assertion is also automatically-update-able to allow tweaking15/// the code generator and easily updating all affected tests.16precise_output: bool,17/// Flag indicating that we expect compilation to fail, not succeed.18expect_fail: bool,19}2021pub fn subtest(parsed: &TestCommand) -> Result<Box<dyn SubTest>> {22assert_eq!(parsed.command, "compile");23let mut test = TestCompile {24precise_output: false,25expect_fail: false,26};27for option in parsed.options.iter() {28match option {29TestOption::Flag("precise-output") => test.precise_output = true,30TestOption::Flag("expect-fail") => test.expect_fail = true,31_ => anyhow::bail!("unknown option on {}", parsed),32}33}34Ok(Box::new(test))35}3637impl SubTest for TestCompile {38fn name(&self) -> &'static str {39"compile"40}4142fn is_mutating(&self) -> bool {43true44}4546fn needs_isa(&self) -> bool {47true48}4950fn run(&self, func: Cow<ir::Function>, context: &Context) -> Result<()> {51let isa = context.isa.expect("compile needs an ISA");52let params = func.params.clone();53let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned());5455// With `MachBackend`s, we need to explicitly request disassembly results.56comp_ctx.set_disasm(true);5758let compiled_code = comp_ctx.compile(isa, &mut Default::default());5960let compiled_code = if self.expect_fail {61if compiled_code.is_ok() {62anyhow::bail!("Expected compilation failure but compilation succeeded");63}64return Ok(());65} else {66compiled_code.map_err(|e| crate::pretty_anyhow_error(&e.func, e.inner))?67};68let total_size = compiled_code.code_info().total_size;6970let vcode = compiled_code.vcode.as_ref().unwrap();7172info!("Generated {total_size} bytes of code:\n{vcode}");7374if self.precise_output {75let dis = match isa.triple().architecture {76target_lexicon::Architecture::Pulley32 | target_lexicon::Architecture::Pulley64 => {77// Disable hexdumps/offsets to reduce the churn in these78// tests as instructions are encoded differently and/or79// their immediates change.80let mut disas =81pulley_interpreter::disas::Disassembler::new(compiled_code.buffer.data());82disas.hexdump(false).offsets(false);83pulley_interpreter::decode::Decoder::decode_all(&mut disas)?;84disas.disas().to_string()85}86_ => {87let cs = isa88.to_capstone()89.map_err(|e| anyhow::format_err!("{}", e))?;90compiled_code.disassemble(Some(¶ms), &cs)?91}92};9394let actual = Vec::from_iter(95std::iter::once("VCode:")96.chain(compiled_code.vcode.as_ref().unwrap().lines())97.chain(["", "Disassembled:"])98.chain(dis.lines()),99);100101check_precise_output(&actual, context)102} else {103run_filecheck(&vcode, context)104}105}106}107108109