cranelift_fuzzgen/
print.rs

1use cranelift::codegen::data_value::DataValue;
2use cranelift::codegen::ir::Function;
3use cranelift::prelude::settings::SettingKind;
4use cranelift::prelude::*;
5use std::fmt;
6
7use crate::TestCaseInput;
8
9#[derive(Debug)]
10enum TestCaseKind {
11    Compile,
12    Run,
13}
14
15/// Provides a way to format a `TestCase` in the .clif format.
16pub struct PrintableTestCase<'a> {
17    kind: TestCaseKind,
18    isa: &'a isa::OwnedTargetIsa,
19    functions: &'a [Function],
20    // Only applicable for run test cases
21    inputs: &'a [TestCaseInput],
22}
23
24impl<'a> PrintableTestCase<'a> {
25    /// Emits a `test compile` test case.
26    pub fn compile(isa: &'a isa::OwnedTargetIsa, functions: &'a [Function]) -> Self {
27        Self {
28            kind: TestCaseKind::Compile,
29            isa,
30            functions,
31            inputs: &[],
32        }
33    }
34
35    /// Emits a `test run` test case. These also include a `test interpret`.
36    ///
37    /// By convention the first function in `functions` will be considered the main function.
38    pub fn run(
39        isa: &'a isa::OwnedTargetIsa,
40        functions: &'a [Function],
41        inputs: &'a [TestCaseInput],
42    ) -> Self {
43        Self {
44            kind: TestCaseKind::Run,
45            isa,
46            functions,
47            inputs,
48        }
49    }
50
51    /// Returns the main function of this test case.
52    pub fn main(&self) -> &Function {
53        &self.functions[0]
54    }
55}
56
57impl<'a> fmt::Debug for PrintableTestCase<'a> {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        match self.kind {
60            TestCaseKind::Compile => {
61                writeln!(f, ";; Compile test case\n")?;
62                writeln!(f, "test compile")?;
63            }
64            TestCaseKind::Run => {
65                writeln!(f, ";; Run test case\n")?;
66                writeln!(f, "test interpret")?;
67                writeln!(f, "test run")?;
68            }
69        };
70
71        write_non_default_flags(f, self.isa.flags())?;
72
73        write!(f, "target {} ", self.isa.triple().architecture)?;
74        write_non_default_isa_flags(f, &self.isa)?;
75        write!(f, "\n\n")?;
76
77        // Print the functions backwards, so that the main function is printed last
78        // and near the test inputs for run test cases.
79        for func in self.functions.iter().rev() {
80            writeln!(f, "{func}\n")?;
81        }
82
83        if !self.inputs.is_empty() {
84            writeln!(
85                f,
86                "; Note: the results in the below test cases are simply a placeholder and probably will be wrong\n"
87            )?;
88        }
89
90        for input in self.inputs.iter() {
91            // TODO: We don't know the expected outputs, maybe we can run the interpreter
92            // here to figure them out? Should work, however we need to be careful to catch
93            // panics in case its the interpreter that is failing.
94            // For now create a placeholder output consisting of the zero value for the type
95            let returns = &self.main().signature.returns;
96            let placeholder_output = returns
97                .iter()
98                .map(|param| DataValue::read_from_slice_ne(&[0; 16][..], param.value_type))
99                .map(|val| format!("{val}"))
100                .collect::<Vec<_>>()
101                .join(", ");
102
103            // If we have no output, we don't need the == condition
104            let test_condition = match returns.len() {
105                0 => String::new(),
106                1 => format!(" == {placeholder_output}"),
107                _ => format!(" == [{placeholder_output}]"),
108            };
109
110            let args = input
111                .iter()
112                .map(|val| format!("{val}"))
113                .collect::<Vec<_>>()
114                .join(", ");
115
116            writeln!(f, "; run: {}({}){}", self.main().name, args, test_condition)?;
117        }
118
119        Ok(())
120    }
121}
122
123/// Print only non default flags.
124fn write_non_default_flags(f: &mut fmt::Formatter<'_>, flags: &settings::Flags) -> fmt::Result {
125    let default_flags = settings::Flags::new(settings::builder());
126    for (default, flag) in default_flags.iter().zip(flags.iter()) {
127        assert_eq!(default.name, flag.name);
128
129        if default.value_string() != flag.value_string() {
130            writeln!(f, "set {}={}", flag.name, flag.value_string())?;
131        }
132    }
133
134    Ok(())
135}
136
137/// Print non default ISA flags in a single line, as used in `target` declarations.
138fn write_non_default_isa_flags(
139    f: &mut fmt::Formatter<'_>,
140    isa: &isa::OwnedTargetIsa,
141) -> fmt::Result {
142    let default_isa = isa::lookup(isa.triple().clone())
143        .unwrap()
144        .finish(isa.flags().clone())
145        .unwrap();
146
147    for (default, flag) in default_isa.isa_flags().iter().zip(isa.isa_flags()) {
148        assert_eq!(default.name, flag.name);
149
150        // Skip default flags, putting them all out there is too verbose.
151        if default.value_string() == flag.value_string() {
152            continue;
153        }
154
155        // On boolean flags we can use the shorthand syntax instead of just specifying the flag name.
156        // This is slightly neater than the full syntax.
157        if flag.kind() == SettingKind::Bool && flag.value_string() == "true" {
158            write!(f, "{} ", flag.name)?;
159        } else {
160            write!(f, "{}={} ", flag.name, flag.value_string())?;
161        }
162    }
163
164    Ok(())
165}