Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/fuzzgen/src/print.rs
1692 views
1
use cranelift::codegen::data_value::DataValue;
2
use cranelift::codegen::ir::Function;
3
use cranelift::prelude::settings::SettingKind;
4
use cranelift::prelude::*;
5
use std::fmt;
6
7
use crate::TestCaseInput;
8
9
#[derive(Debug)]
10
enum TestCaseKind {
11
Compile,
12
Run,
13
}
14
15
/// Provides a way to format a `TestCase` in the .clif format.
16
pub 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
24
impl<'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
57
impl<'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.
124
fn 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.
138
fn 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
}
166
167