Path: blob/main/cranelift/fuzzgen/src/print.rs
1692 views
use cranelift::codegen::data_value::DataValue;1use cranelift::codegen::ir::Function;2use cranelift::prelude::settings::SettingKind;3use cranelift::prelude::*;4use std::fmt;56use crate::TestCaseInput;78#[derive(Debug)]9enum TestCaseKind {10Compile,11Run,12}1314/// Provides a way to format a `TestCase` in the .clif format.15pub struct PrintableTestCase<'a> {16kind: TestCaseKind,17isa: &'a isa::OwnedTargetIsa,18functions: &'a [Function],19// Only applicable for run test cases20inputs: &'a [TestCaseInput],21}2223impl<'a> PrintableTestCase<'a> {24/// Emits a `test compile` test case.25pub fn compile(isa: &'a isa::OwnedTargetIsa, functions: &'a [Function]) -> Self {26Self {27kind: TestCaseKind::Compile,28isa,29functions,30inputs: &[],31}32}3334/// Emits a `test run` test case. These also include a `test interpret`.35///36/// By convention the first function in `functions` will be considered the main function.37pub fn run(38isa: &'a isa::OwnedTargetIsa,39functions: &'a [Function],40inputs: &'a [TestCaseInput],41) -> Self {42Self {43kind: TestCaseKind::Run,44isa,45functions,46inputs,47}48}4950/// Returns the main function of this test case.51pub fn main(&self) -> &Function {52&self.functions[0]53}54}5556impl<'a> fmt::Debug for PrintableTestCase<'a> {57fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {58match self.kind {59TestCaseKind::Compile => {60writeln!(f, ";; Compile test case\n")?;61writeln!(f, "test compile")?;62}63TestCaseKind::Run => {64writeln!(f, ";; Run test case\n")?;65writeln!(f, "test interpret")?;66writeln!(f, "test run")?;67}68};6970write_non_default_flags(f, self.isa.flags())?;7172write!(f, "target {} ", self.isa.triple().architecture)?;73write_non_default_isa_flags(f, &self.isa)?;74write!(f, "\n\n")?;7576// Print the functions backwards, so that the main function is printed last77// and near the test inputs for run test cases.78for func in self.functions.iter().rev() {79writeln!(f, "{func}\n")?;80}8182if !self.inputs.is_empty() {83writeln!(84f,85"; Note: the results in the below test cases are simply a placeholder and probably will be wrong\n"86)?;87}8889for input in self.inputs.iter() {90// TODO: We don't know the expected outputs, maybe we can run the interpreter91// here to figure them out? Should work, however we need to be careful to catch92// panics in case its the interpreter that is failing.93// For now create a placeholder output consisting of the zero value for the type94let returns = &self.main().signature.returns;95let placeholder_output = returns96.iter()97.map(|param| DataValue::read_from_slice_ne(&[0; 16][..], param.value_type))98.map(|val| format!("{val}"))99.collect::<Vec<_>>()100.join(", ");101102// If we have no output, we don't need the == condition103let test_condition = match returns.len() {1040 => String::new(),1051 => format!(" == {placeholder_output}"),106_ => format!(" == [{placeholder_output}]"),107};108109let args = input110.iter()111.map(|val| format!("{val}"))112.collect::<Vec<_>>()113.join(", ");114115writeln!(f, "; run: {}({}){}", self.main().name, args, test_condition)?;116}117118Ok(())119}120}121122/// Print only non default flags.123fn write_non_default_flags(f: &mut fmt::Formatter<'_>, flags: &settings::Flags) -> fmt::Result {124let default_flags = settings::Flags::new(settings::builder());125for (default, flag) in default_flags.iter().zip(flags.iter()) {126assert_eq!(default.name, flag.name);127128if default.value_string() != flag.value_string() {129writeln!(f, "set {}={}", flag.name, flag.value_string())?;130}131}132133Ok(())134}135136/// Print non default ISA flags in a single line, as used in `target` declarations.137fn write_non_default_isa_flags(138f: &mut fmt::Formatter<'_>,139isa: &isa::OwnedTargetIsa,140) -> fmt::Result {141let default_isa = isa::lookup(isa.triple().clone())142.unwrap()143.finish(isa.flags().clone())144.unwrap();145146for (default, flag) in default_isa.isa_flags().iter().zip(isa.isa_flags()) {147assert_eq!(default.name, flag.name);148149// Skip default flags, putting them all out there is too verbose.150if default.value_string() == flag.value_string() {151continue;152}153154// On boolean flags we can use the shorthand syntax instead of just specifying the flag name.155// This is slightly neater than the full syntax.156if flag.kind() == SettingKind::Bool && flag.value_string() == "true" {157write!(f, "{} ", flag.name)?;158} else {159write!(f, "{}={} ", flag.name, flag.value_string())?;160}161}162163Ok(())164}165166167