Files
wasmtime/cranelift/codegen/src/cfg_printer.rs
Ryan Hunt 4aa8776a9b Skip non-branching blocks now that we're using basic blocks
This is a rebase of [1]. In the long term, we'll want to simplify these
analysis passes. For now, this is simple and will reduce the number of
instructions processed in certain cases.

[1] https://github.com/bytecodealliance/cranelift/pull/866
2020-03-05 16:11:13 +01:00

84 lines
2.5 KiB
Rust

//! The `CFGPrinter` utility.
use alloc::vec::Vec;
use core::fmt::{Display, Formatter, Result, Write};
use crate::entity::SecondaryMap;
use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
use crate::ir::Function;
use crate::write::{FuncWriter, PlainWriter};
/// A utility for pretty-printing the CFG of a `Function`.
pub struct CFGPrinter<'a> {
func: &'a Function,
cfg: ControlFlowGraph,
}
/// A utility for pretty-printing the CFG of a `Function`.
impl<'a> CFGPrinter<'a> {
/// Create a new CFGPrinter.
pub fn new(func: &'a Function) -> Self {
Self {
func,
cfg: ControlFlowGraph::with_function(func),
}
}
/// Write the CFG for this function to `w`.
pub fn write(&self, w: &mut dyn Write) -> Result {
self.header(w)?;
self.block_nodes(w)?;
self.cfg_connections(w)?;
writeln!(w, "}}")
}
fn header(&self, w: &mut dyn Write) -> Result {
writeln!(w, "digraph \"{}\" {{", self.func.name)?;
if let Some(entry) = self.func.layout.entry_block() {
writeln!(w, " {{rank=min; {}}}", entry)?;
}
Ok(())
}
fn block_nodes(&self, w: &mut dyn Write) -> Result {
let mut aliases = SecondaryMap::<_, Vec<_>>::new();
for v in self.func.dfg.values() {
// VADFS returns the immediate target of an alias
if let Some(k) = self.func.dfg.value_alias_dest_for_serialization(v) {
aliases[k].push(v);
}
}
for block in &self.func.layout {
write!(w, " {} [shape=record, label=\"{{", block)?;
crate::write::write_block_header(w, self.func, None, block, 4)?;
// Add all outgoing branch instructions to the label.
for inst in self.func.layout.block_likely_branches(block) {
write!(w, " | <{}>", inst)?;
PlainWriter.write_instruction(w, self.func, &aliases, None, inst, 0)?;
}
writeln!(w, "}}\"]")?
}
Ok(())
}
fn cfg_connections(&self, w: &mut dyn Write) -> Result {
for block in &self.func.layout {
for BlockPredecessor {
block: parent,
inst,
} in self.cfg.pred_iter(block)
{
writeln!(w, " {}:{} -> {}", parent, inst, block)?;
}
}
Ok(())
}
}
impl<'a> Display for CFGPrinter<'a> {
fn fmt(&self, f: &mut Formatter) -> Result {
self.write(f)
}
}