//! Formatting a peephole optimizer's automata for GraphViz Dot. //! //! See also `crates/automata/src/dot.rs`. use peepmatic_automata::dot::DotFmt; use peepmatic_runtime::{ cc::ConditionCode, integer_interner::{IntegerId, IntegerInterner}, linear, }; use std::convert::{TryFrom, TryInto}; use std::fmt::Debug; use std::io::{self, Write}; use std::num::{NonZeroU16, NonZeroU32}; #[derive(Debug)] pub(crate) struct PeepholeDotFmt<'a>(pub(crate) &'a IntegerInterner); impl DotFmt]>> for PeepholeDotFmt<'_> where TOperator: Debug + TryFrom, { fn fmt_transition( &self, w: &mut impl Write, from: Option<&linear::MatchOp>, input: &linear::MatchResult, _to: Option<&linear::MatchOp>, ) -> io::Result<()> { let from = from.expect("we should have match op for every state"); if let Some(x) = input.ok() { match from { linear::MatchOp::Opcode { .. } => { let opcode = TOperator::try_from(x) .map_err(|_| ()) .expect("we shouldn't generate non-opcode edges"); write!(w, "{:?}", opcode) } linear::MatchOp::ConditionCode { .. } => { let cc = ConditionCode::try_from(x.get()) .expect("we shouldn't generate non-CC edges"); write!(w, "{}", cc) } linear::MatchOp::IntegerValue { .. } => { let x = self.0.lookup(IntegerId( NonZeroU16::new(x.get().try_into().unwrap()).unwrap(), )); write!(w, "{}", x) } _ => write!(w, "Ok({})", x), } } else { write!(w, "(else)") } } fn fmt_state(&self, w: &mut impl Write, op: &linear::MatchOp) -> io::Result<()> { use linear::MatchOp::*; write!(w, r#""#)?; match op { Opcode(id) => write!(w, "opcode $lhs{}", id.0)?, IsConst(id) => write!(w, "is-const? $lhs{}", id.0)?, IsPowerOfTwo(id) => write!(w, "is-power-of-two? $lhs{}", id.0)?, BitWidth(id) => write!(w, "bit-width $lhs{}", id.0)?, FitsInNativeWord(id) => write!(w, "fits-in-native-word $lhs{}", id.0)?, Eq(a, b) => write!(w, "$lhs{} == $lhs{}", a.0, b.0)?, IntegerValue(id) => write!(w, "integer-value $lhs{}", id.0)?, BooleanValue(id) => write!(w, "boolean-value $lhs{}", id.0)?, ConditionCode(id) => write!(w, "condition-code $lhs{}", id.0)?, Nop => write!(w, "nop")?, } writeln!(w, "") } fn fmt_output( &self, w: &mut impl Write, actions: &Box<[linear::Action]>, ) -> io::Result<()> { use linear::Action::*; if actions.is_empty() { return writeln!(w, "(no output)"); } write!(w, r#""#)?; for a in actions.iter() { match a { GetLhs { lhs } => write!(w, "get-lhs $lhs{}
", lhs.0)?, UnaryUnquote { operator, operand } => { write!(w, "eval {:?} $rhs{}
", operator, operand.0)? } BinaryUnquote { operator, operands } => write!( w, "eval {:?} $rhs{}, $rhs{}
", operator, operands[0].0, operands[1].0, )?, MakeIntegerConst { value, bit_width: _, } => write!(w, "make {}
", self.0.lookup(*value))?, MakeBooleanConst { value, bit_width: _, } => write!(w, "make {}
", value)?, MakeConditionCode { cc } => write!(w, "{}
", cc)?, MakeUnaryInst { operand, operator, r#type: _, } => write!(w, "make {:?} $rhs{}
", operator, operand.0,)?, MakeBinaryInst { operator, operands, r#type: _, } => write!( w, "make {:?} $rhs{}, $rhs{}
", operator, operands[0].0, operands[1].0, )?, MakeTernaryInst { operator, operands, r#type: _, } => write!( w, "make {:?} $rhs{}, $rhs{}, $rhs{}
", operator, operands[0].0, operands[1].0, operands[2].0, )?, } } writeln!(w, "
") } }