//! Test command for interpreting CLIF files and verifying their results //! //! The `interpret` test command interprets each function on the host machine //! using [RunCommand](cranelift_reader::RunCommand)s. use crate::runone::FileUpdate; use crate::subtest::SubTest; use anyhow::Context; use cranelift_codegen::ir::Function; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::Flags; use cranelift_codegen::{self, ir}; use cranelift_interpreter::environment::FunctionStore; use cranelift_interpreter::interpreter::{Interpreter, InterpreterState}; use cranelift_interpreter::step::ControlFlow; use cranelift_reader::{parse_run_command, Details, TestCommand, TestFile}; use log::{info, trace}; use std::borrow::Cow; struct TestInterpret; pub fn subtest(parsed: &TestCommand) -> anyhow::Result> { assert_eq!(parsed.command, "interpret"); if !parsed.options.is_empty() { anyhow::bail!("No options allowed on {}", parsed); } Ok(Box::new(TestInterpret)) } impl SubTest for TestInterpret { fn name(&self) -> &'static str { "interpret" } fn is_mutating(&self) -> bool { false } fn needs_isa(&self) -> bool { false } /// Runs the entire subtest for a given target, invokes [Self::run] for running /// individual tests. fn run_target<'a>( &self, testfile: &TestFile, _: &mut FileUpdate, _: &'a str, _: &'a Flags, _: Option<&'a dyn TargetIsa>, ) -> anyhow::Result<()> { // We can build the FunctionStore once and reuse it let mut func_store = FunctionStore::default(); for (func, _) in &testfile.functions { func_store.add(func.name.to_string(), &func); } for (func, details) in &testfile.functions { info!("Test: {}({}) interpreter", self.name(), func.name); run_test(&func_store, func, details).context(self.name())?; } Ok(()) } fn run( &self, _func: Cow, _context: &crate::subtest::Context, ) -> anyhow::Result<()> { unreachable!() } } fn run_test(func_store: &FunctionStore, func: &Function, details: &Details) -> anyhow::Result<()> { for comment in details.comments.iter() { if let Some(command) = parse_run_command(comment.text, &func.signature)? { trace!("Parsed run command: {}", command); command .run(|func_name, run_args| { // Rebuild the interpreter state on every run to ensure that we don't accidentally depend on // some leftover state let state = InterpreterState::default().with_function_store(func_store.clone()); let mut args = Vec::with_capacity(run_args.len()); args.extend_from_slice(run_args); // Because we have stored function names with a leading %, we need to re-add it. let func_name = &format!("%{}", func_name); match Interpreter::new(state).call_by_name(func_name, &args) { Ok(ControlFlow::Return(results)) => Ok(results.to_vec()), Ok(e) => { panic!("Unexpected returned control flow: {:?}", e) } Err(t) => Err(format!("unexpected trap: {:?}", t)), } }) .map_err(|e| anyhow::anyhow!("{}", e))?; } } Ok(()) }