cranelift_filetests/
test_interpret.rs1use crate::runone::FileUpdate;
7use crate::subtest::SubTest;
8use anyhow::Context;
9use cranelift_codegen::data_value::DataValue;
10use cranelift_codegen::ir;
11use cranelift_codegen::ir::{Function, LibCall};
12use cranelift_codegen::isa::TargetIsa;
13use cranelift_codegen::settings::Flags;
14use cranelift_interpreter::environment::FunctionStore;
15use cranelift_interpreter::interpreter::{Interpreter, InterpreterState, LibCallValues};
16use cranelift_interpreter::step::ControlFlow;
17use cranelift_reader::{parse_run_command, Details, TestCommand, TestFile};
18use log::{info, trace};
19use smallvec::smallvec;
20use std::borrow::Cow;
21
22struct TestInterpret;
23
24pub fn subtest(parsed: &TestCommand) -> anyhow::Result<Box<dyn SubTest>> {
25 assert_eq!(parsed.command, "interpret");
26 if !parsed.options.is_empty() {
27 anyhow::bail!("No options allowed on {}", parsed);
28 }
29 Ok(Box::new(TestInterpret))
30}
31
32impl SubTest for TestInterpret {
33 fn name(&self) -> &'static str {
34 "interpret"
35 }
36
37 fn is_mutating(&self) -> bool {
38 false
39 }
40
41 fn needs_isa(&self) -> bool {
42 false
43 }
44
45 fn run_target<'a>(
48 &self,
49 testfile: &TestFile,
50 _: &mut FileUpdate,
51 _: &'a str,
52 _: &'a Flags,
53 _: Option<&'a dyn TargetIsa>,
54 ) -> anyhow::Result<()> {
55 let mut func_store = FunctionStore::default();
57 for (func, _) in &testfile.functions {
58 func_store.add(func.name.to_string(), &func);
59 }
60
61 for (func, details) in &testfile.functions {
62 info!("Test: {}({}) interpreter", self.name(), func.name);
63
64 run_test(&func_store, func, details).context(self.name())?;
65 }
66
67 Ok(())
68 }
69
70 fn run(
71 &self,
72 _func: Cow<ir::Function>,
73 _context: &crate::subtest::Context,
74 ) -> anyhow::Result<()> {
75 unreachable!()
76 }
77}
78
79fn run_test(func_store: &FunctionStore, func: &Function, details: &Details) -> anyhow::Result<()> {
80 for comment in details.comments.iter() {
81 if let Some(command) = parse_run_command(comment.text, &func.signature)? {
82 trace!("Parsed run command: {}", command);
83
84 command
85 .run(|func_name, run_args| {
86 let state = InterpreterState::default()
89 .with_function_store(func_store.clone())
90 .with_libcall_handler(|libcall: LibCall, args: LibCallValues| {
91 use LibCall::*;
92 Ok(smallvec![match (libcall, &args[..]) {
93 (CeilF32, [DataValue::F32(a)]) => DataValue::F32(a.ceil()),
94 (CeilF64, [DataValue::F64(a)]) => DataValue::F64(a.ceil()),
95 (FloorF32, [DataValue::F32(a)]) => DataValue::F32(a.floor()),
96 (FloorF64, [DataValue::F64(a)]) => DataValue::F64(a.floor()),
97 (TruncF32, [DataValue::F32(a)]) => DataValue::F32(a.trunc()),
98 (TruncF64, [DataValue::F64(a)]) => DataValue::F64(a.trunc()),
99 _ => unreachable!(),
100 }])
101 });
102
103 let mut args = Vec::with_capacity(run_args.len());
104 args.extend_from_slice(run_args);
105
106 let func_name = &format!("%{func_name}");
108 match Interpreter::new(state).call_by_name(func_name, &args) {
109 Ok(ControlFlow::Return(results)) => Ok(results.to_vec()),
110 Ok(e) => {
111 panic!("Unexpected returned control flow: {e:?}")
112 }
113 Err(t) => Err(format!("unexpected trap: {t:?}")),
114 }
115 })
116 .map_err(|e| anyhow::anyhow!("{}", e))?;
117 }
118 }
119 Ok(())
120}