From 15e951ec5678b42d4b59b7650c8d4d4a2adeeffa Mon Sep 17 00:00:00 2001 From: michelledaviest Date: Wed, 20 Nov 2024 10:26:47 -0500 Subject: [PATCH 1/9] added print decorator with hook to print after value --- src/backend/localify.rs | 2 +- src/backend/mod.rs | 5 ++- src/backend/reducify.rs | 20 ++++++++-- src/bin/waffle-util.rs | 9 +++-- src/interp.rs | 2 +- src/ir/display.rs | 71 +++++++++++++++++++++++------------ src/ir/func.rs | 35 +++++++++++++---- src/ir/module.rs | 16 ++++++-- src/passes/empty_blocks.rs | 4 +- src/passes/resolve_aliases.rs | 2 +- 10 files changed, 118 insertions(+), 48 deletions(-) diff --git a/src/backend/localify.rs b/src/backend/localify.rs index 82e9122..060b9d8 100644 --- a/src/backend/localify.rs +++ b/src/backend/localify.rs @@ -58,7 +58,7 @@ impl<'a, V: Visitor> BlockVisitor<'a, V> { fn new(body: &'a FunctionBody, trees: &'a Trees, visitor: V) -> Self { log::trace!( "localify: running on:\n{}", - body.display_verbose("| ", None) + body.display_verbose("| ", None, &crate::NOPPrintDecorator::default()) ); Self { body, diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 1875bda..6dd4309 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -37,7 +37,10 @@ macro_rules! op { impl<'a> WasmFuncBackend<'a> { pub fn compile(body: &'a FunctionBody) -> Result { body.validate()?; - log::debug!("Backend compiling:\n{}\n", body.display_verbose("| ", None)); + log::debug!( + "Backend compiling:\n{}\n", + body.display_verbose("| ", None, &crate::NOPPrintDecorator::default()) + ); // For ownership reasons (to avoid a self-referential struct // with the `Cow::Owned` case when the Reducifier modifies the // body), we have to run the Reducifier first, own its result diff --git a/src/backend/reducify.rs b/src/backend/reducify.rs index b522fb5..76aa7b6 100644 --- a/src/backend/reducify.rs +++ b/src/backend/reducify.rs @@ -295,7 +295,10 @@ impl<'a> Reducifier<'a> { crate::passes::maxssa::run(&mut new_body, Some(cut_blocks), &cfg); crate::passes::resolve_aliases::run(&mut new_body); - log::trace!("after max-SSA run:\n{}\n", new_body.display("| ", None)); + log::trace!( + "after max-SSA run:\n{}\n", + new_body.display("| ", None, &crate::NOPPrintDecorator::default()) + ); // Implicitly, context {} has an identity-map from old block // number to new block number. We use the map only for @@ -443,7 +446,10 @@ impl<'a> Reducifier<'a> { new_body.recompute_edges(); - log::trace!("After duplication:\n{}\n", new_body.display("| ", None)); + log::trace!( + "After duplication:\n{}\n", + new_body.display("| ", None, &crate::NOPPrintDecorator::default()) + ); new_body.validate().unwrap(); new_body.verify_reducible().unwrap(); @@ -542,7 +548,10 @@ mod test { }, ); - log::debug!("Body:\n{}", body.display("| ", Some(&module))); + log::debug!( + "Body:\n{}", + body.display("| ", Some(&module), &crate::NOPPrintDecorator::default()) + ); body.validate().unwrap(); @@ -551,7 +560,10 @@ mod test { new_body.validate().unwrap(); - log::debug!("Reducified body:\n{}", body.display("| ", Some(&module))); + log::debug!( + "Reducified body:\n{}", + body.display("| ", Some(&module), &crate::NOPPrintDecorator::default()) + ); let cfg = CFGInfo::new(&new_body); for (block, def) in new_body.blocks.entries() { diff --git a/src/bin/waffle-util.rs b/src/bin/waffle-util.rs index 759d26d..1ff05bf 100644 --- a/src/bin/waffle-util.rs +++ b/src/bin/waffle-util.rs @@ -2,9 +2,9 @@ use anyhow::Result; use log::debug; -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf}; use structopt::StructOpt; -use waffle::{entity::EntityRef, FrontendOptions, Func, Module, OptOptions}; +use waffle::{entity::EntityRef, FrontendOptions, Func, Module, NOPPrintDecorator, OptOptions}; #[derive(Debug, StructOpt)] #[structopt(name = "waffle-util", about = "WAFFLE utility.")] @@ -84,7 +84,8 @@ fn main() -> Result<()> { debug!("Loaded {} bytes of Wasm data", bytes.len()); let mut module = Module::from_wasm_bytes(&bytes[..], &options)?; apply_options(&opts, &mut module)?; - println!("{}", module.display()); + let empty_decorator_map: HashMap = HashMap::new(); + println!("{}", module.display(empty_decorator_map)); } Command::PrintFunc { wasm, func } => { let bytes = std::fs::read(wasm)?; @@ -96,7 +97,7 @@ fn main() -> Result<()> { module.funcs[Func::new(*func)] .body() .unwrap() - .display_verbose("", Some(&module)) + .display_verbose("", Some(&module), &waffle::NOPPrintDecorator::default()) ); } Command::RoundTrip { input, output } => { diff --git a/src/interp.rs b/src/interp.rs index 4952c78..985e5e6 100644 --- a/src/interp.rs +++ b/src/interp.rs @@ -149,7 +149,7 @@ impl InterpContext { log::trace!( "Interp: entering func {}:\n{}\n", func, - body.display_verbose("| ", Some(module)) + body.display_verbose("| ", Some(module), &NOPPrintDecorator::default()) ); log::trace!("args: {:?}", args); diff --git a/src/ir/display.rs b/src/ir/display.rs index 62506ab..3b927ee 100644 --- a/src/ir/display.rs +++ b/src/ir/display.rs @@ -3,18 +3,35 @@ use super::{FuncDecl, FunctionBody, Module, SourceLoc, ValueDef}; use crate::entity::EntityRef; use std::collections::HashMap; -use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::fmt::{self, Display, Formatter, Result as FmtResult}; + +pub trait PrintDecorator { + // TODO: Add functions for before inst, before block, after block as well. + fn after_inst( + &self, + func: &FunctionBody, + val: super::Value, + f: &mut fmt::Formatter, + ) -> fmt::Result { + Ok(()) + } +} + +#[derive(Default)] +pub struct NOPPrintDecorator(); +impl PrintDecorator for NOPPrintDecorator {} /// A wrapper around a `FunctionBody` together with some auxiliary /// information to perform a pretty-print of that function. -pub struct FunctionBodyDisplay<'a> { +pub struct FunctionBodyDisplay<'a, PD: PrintDecorator> { pub(crate) body: &'a FunctionBody, pub(crate) indent: &'a str, pub(crate) verbose: bool, pub(crate) module: Option<&'a Module<'a>>, + pub(crate) decorator: &'a PD, } -impl<'a> Display for FunctionBodyDisplay<'a> { +impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { fn fmt(&self, f: &mut Formatter) -> FmtResult { let arg_tys = self .body @@ -39,23 +56,26 @@ impl<'a> Display for FunctionBodyDisplay<'a> { for (value, value_def) in self.body.values.entries() { match value_def { - ValueDef::Operator(op, args, tys) if self.verbose => writeln!( - f, - "{} {} = {} {} # {}", - self.indent, - value, - op, - self.body.arg_pool[*args] - .iter() - .map(|arg| format!("{}", arg)) - .collect::>() - .join(", "), - self.body.type_pool[*tys] - .iter() - .map(|arg| format!("{}", arg)) - .collect::>() - .join(", ") - )?, + ValueDef::Operator(op, args, tys) if self.verbose => { + writeln!( + f, + "{} {} = {} {} # {}", + self.indent, + value, + op, + self.body.arg_pool[*args] + .iter() + .map(|arg| format!("{}", arg)) + .collect::>() + .join(", "), + self.body.type_pool[*tys] + .iter() + .map(|arg| format!("{}", arg)) + .collect::>() + .join(", "), + )?; + self.decorator.after_inst(self.body, value, f)?; + } ValueDef::BlockParam(block, idx, ty) if self.verbose => writeln!( f, "{} {} = blockparam {}, {} # {}", @@ -172,11 +192,12 @@ impl<'a> Display for FunctionBodyDisplay<'a> { } } -pub struct ModuleDisplay<'a> { +pub struct ModuleDisplay<'a, PD: PrintDecorator> { pub(crate) module: &'a Module<'a>, + pub(crate) decorators: HashMap, } -impl<'a> Display for ModuleDisplay<'a> { +impl<'a, PD: PrintDecorator> Display for ModuleDisplay<'a, PD> { fn fmt(&self, f: &mut Formatter) -> FmtResult { writeln!(f, "module {{")?; if let Some(func) = self.module.start_func { @@ -250,7 +271,11 @@ impl<'a> Display for ModuleDisplay<'a> { sig, sig_strs.get(&sig).unwrap() )?; - writeln!(f, "{}", body.display(" ", Some(self.module)))?; + writeln!( + f, + "{}", + body.display(" ", Some(self.module), self.decorators[&func]) + )?; } FuncDecl::Lazy(sig, name, reader) => { writeln!( diff --git a/src/ir/func.rs b/src/ir/func.rs index d62ddf8..26934da 100644 --- a/src/ir/func.rs +++ b/src/ir/func.rs @@ -1,4 +1,6 @@ -use super::{Block, FunctionBodyDisplay, Local, Module, Signature, Type, Value, ValueDef}; +use super::{ + Block, FunctionBodyDisplay, Local, Module, PrintDecorator, Signature, Type, Value, ValueDef, +}; use crate::backend::WasmFuncBackend; use crate::cfg::CFGInfo; use crate::entity::{EntityRef, EntityVec, PerEntity}; @@ -6,7 +8,7 @@ use crate::frontend::parse_body; use crate::ir::SourceLoc; use crate::passes::basic_opt::OptOptions; use crate::pool::{ListPool, ListRef}; -use crate::Operator; +use crate::{NOPPrintDecorator, Operator}; use anyhow::Result; use fxhash::FxHashMap; use std::collections::HashSet; @@ -443,35 +445,54 @@ impl FunctionBody { self.blocks[block].terminator = terminator; } + // In func.rs + // pub fn display<'a, PD: PrintDec>( + // &'a self, + // indent: &'a str, + // module: Option<&'a Module>, + // pd: &PD + // ) -> FunctionBodyDisplay<'_, PD> { // print decorator lifetime + // FunctionBodyDisplay { + // body: self, + // indent, + // verbose: false, + // module, + // } + // } + /// Prety-print this function body. `indent` is prepended to each /// line of output. `module`, if provided, allows printing source /// locations as comments at each operator. - pub fn display<'a>( + pub fn display<'a, PD: PrintDecorator>( &'a self, indent: &'a str, module: Option<&'a Module>, - ) -> FunctionBodyDisplay<'a> { + decorator: &'a PD, + ) -> FunctionBodyDisplay<'a, PD> { FunctionBodyDisplay { body: self, indent, verbose: false, module, + decorator, } } /// Pretty-print this function body, with "verbose" format: /// includes all value nodes, even those not listed in a block's /// instruction list. (Roughly doubles output size.) - pub fn display_verbose<'a>( + pub fn display_verbose<'a, PD: PrintDecorator>( &'a self, indent: &'a str, module: Option<&'a Module>, - ) -> FunctionBodyDisplay<'a> { + decorator: &'a PD, + ) -> FunctionBodyDisplay<'a, PD> { FunctionBodyDisplay { body: self, indent, verbose: true, module, + decorator, } } @@ -566,7 +587,7 @@ impl FunctionBody { if bad.len() > 0 { anyhow::bail!( "Body is:\n{}\nError(s) in SSA: {:?}", - self.display_verbose(" | ", None), + self.display_verbose(" | ", None, &NOPPrintDecorator::default()), bad ); } diff --git a/src/ir/module.rs b/src/ir/module.rs index 23d3d97..76b10dc 100644 --- a/src/ir/module.rs +++ b/src/ir/module.rs @@ -1,9 +1,11 @@ -use super::{Func, FuncDecl, Global, Memory, ModuleDisplay, Signature, Table, Type}; +use super::{ + Func, FuncDecl, Global, Memory, ModuleDisplay, PrintDecorator, Signature, Table, Type, +}; use crate::entity::{EntityRef, EntityVec}; use crate::ir::{Debug, DebugMap, FunctionBody}; use crate::{backend, frontend}; use anyhow::Result; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; pub use crate::frontend::FrontendOptions; @@ -327,11 +329,17 @@ impl<'a> Module<'a> { /// Return a wrapper that implements Display on this module, /// pretty-printing it as textual IR. - pub fn display<'b>(&'b self) -> ModuleDisplay<'b> + pub fn display<'b, PD: PrintDecorator>( + &'b self, + decorators: HashMap, + ) -> ModuleDisplay<'b, PD> where 'b: 'a, { - ModuleDisplay { module: self } + ModuleDisplay { + module: self, + decorators, + } } /// Internal (used during parsing): create an empty module, with diff --git a/src/passes/empty_blocks.rs b/src/passes/empty_blocks.rs index c9fb8cd..6939694 100644 --- a/src/passes/empty_blocks.rs +++ b/src/passes/empty_blocks.rs @@ -40,7 +40,7 @@ fn rewrite_target( pub(crate) fn run(body: &mut FunctionBody) { log::trace!( "empty_blocks: running on func:\n{}\n", - body.display_verbose("| ", None) + body.display_verbose("| ", None, &crate::NOPPrintDecorator::default()) ); // Identify empty blocks, and to where they should forward. @@ -72,6 +72,6 @@ pub(crate) fn run(body: &mut FunctionBody) { log::trace!( "empty_blocks: finished:\n{}\n", - body.display_verbose("| ", None) + body.display_verbose("| ", None, &crate::NOPPrintDecorator::default()) ); } diff --git a/src/passes/resolve_aliases.rs b/src/passes/resolve_aliases.rs index bf46570..9faac0a 100644 --- a/src/passes/resolve_aliases.rs +++ b/src/passes/resolve_aliases.rs @@ -5,7 +5,7 @@ use crate::{FunctionBody, ValueDef}; pub fn run(body: &mut FunctionBody) { log::debug!( "Resolve aliases: running on:\n{}\n", - body.display_verbose("| ", None), + body.display_verbose("| ", None, &crate::NOPPrintDecorator::default()), ); for value in body.values.iter() { let mut value_def = std::mem::take(&mut body.values[value]); From 27e458eb0723c0a968884a96e0ae4b9fe77bcc68 Mon Sep 17 00:00:00 2001 From: michelledaviest Date: Wed, 20 Nov 2024 11:40:45 -0500 Subject: [PATCH 2/9] add more hooks --- src/ir/display.rs | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/ir/display.rs b/src/ir/display.rs index 3b927ee..a88f896 100644 --- a/src/ir/display.rs +++ b/src/ir/display.rs @@ -6,13 +6,23 @@ use std::collections::HashMap; use std::fmt::{self, Display, Formatter, Result as FmtResult}; pub trait PrintDecorator { - // TODO: Add functions for before inst, before block, after block as well. - fn after_inst( - &self, - func: &FunctionBody, - val: super::Value, - f: &mut fmt::Formatter, - ) -> fmt::Result { + fn after_inst(&self, _value: super::Value, _f: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + + fn before_block(&self, _block: super::Block, _f: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + + fn after_block(&self, _block: super::Block, _f: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + + fn before_function_body(&self, _f: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + + fn after_function_body(&self, _f: &mut fmt::Formatter) -> fmt::Result { Ok(()) } } @@ -54,12 +64,14 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { ret_tys.join(", ") )?; + self.decorator.before_function_body(f)?; + for (value, value_def) in self.body.values.entries() { match value_def { ValueDef::Operator(op, args, tys) if self.verbose => { - writeln!( + write!( f, - "{} {} = {} {} # {}", + "{} {} = {} {} # {} ", self.indent, value, op, @@ -74,7 +86,7 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { .collect::>() .join(", "), )?; - self.decorator.after_inst(self.body, value, f)?; + writeln!(f, "")?; } ValueDef::BlockParam(block, idx, ty) if self.verbose => writeln!( f, @@ -111,6 +123,9 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { block_params.join(", "), block.desc )?; + + self.decorator.before_block(block_id, f)?; + writeln!( f, "{} # preds: {}", @@ -163,9 +178,9 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { } else { "".to_owned() }; - writeln!( + write!( f, - "{} {} = {} {} # {} {}", + "{} {} = {} {} # {} {} ", self.indent, inst, op, @@ -173,6 +188,8 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { tys.join(", "), loc, )?; + self.decorator.after_inst(inst, f)?; + writeln!(f, "")?; } ValueDef::PickOutput(val, idx, ty) => { writeln!(f, "{} {} = {}.{} # {}", self.indent, inst, val, idx, ty)?; @@ -182,10 +199,13 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { } _ => unreachable!(), } + self.decorator.after_block(block_id, f)?; } writeln!(f, "{} {}", self.indent, block.terminator)?; } + self.decorator.after_function_body(f)?; + writeln!(f, "{}}}", self.indent)?; Ok(()) From 1ddfb3df68a339814336ba752686e20cd3bd4942 Mon Sep 17 00:00:00 2001 From: michelledaviest Date: Wed, 20 Nov 2024 11:43:12 -0500 Subject: [PATCH 3/9] add comment --- src/ir/display.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ir/display.rs b/src/ir/display.rs index a88f896..a2b9c04 100644 --- a/src/ir/display.rs +++ b/src/ir/display.rs @@ -5,6 +5,8 @@ use crate::entity::EntityRef; use std::collections::HashMap; use std::fmt::{self, Display, Formatter, Result as FmtResult}; +/// Hooks to print information after inst, before and after blocks +/// and before and after functions. pub trait PrintDecorator { fn after_inst(&self, _value: super::Value, _f: &mut fmt::Formatter) -> fmt::Result { Ok(()) From 5586af56ecd4f39e43e5efc033b4a82735e97af8 Mon Sep 17 00:00:00 2001 From: michelledaviest Date: Wed, 20 Nov 2024 11:52:25 -0500 Subject: [PATCH 4/9] added nop print decorators for each func --- src/bin/waffle-util.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/bin/waffle-util.rs b/src/bin/waffle-util.rs index 1ff05bf..6738db8 100644 --- a/src/bin/waffle-util.rs +++ b/src/bin/waffle-util.rs @@ -84,8 +84,12 @@ fn main() -> Result<()> { debug!("Loaded {} bytes of Wasm data", bytes.len()); let mut module = Module::from_wasm_bytes(&bytes[..], &options)?; apply_options(&opts, &mut module)?; - let empty_decorator_map: HashMap = HashMap::new(); - println!("{}", module.display(empty_decorator_map)); + let mut nop_decorators = HashMap::new(); + let nop_decorator = NOPPrintDecorator::default(); + module.funcs.entries().into_iter().for_each(|(func, _)| { + nop_decorators.insert(func, &nop_decorator); + }); + println!("{}", module.display(nop_decorators)); } Command::PrintFunc { wasm, func } => { let bytes = std::fs::read(wasm)?; From 21b3cb85202bc5322d9378163ac982b073e3ebe0 Mon Sep 17 00:00:00 2001 From: michelledaviest Date: Fri, 22 Nov 2024 10:37:41 -0500 Subject: [PATCH 5/9] addressed comments --- src/backend/localify.rs | 2 +- src/backend/mod.rs | 5 +--- src/backend/reducify.rs | 20 +++---------- src/bin/waffle-util.rs | 2 +- src/interp.rs | 2 +- src/ir/display.rs | 54 +++++++++++++++++++++++++---------- src/ir/func.rs | 30 ++++++++++++++----- src/passes/empty_blocks.rs | 4 +-- src/passes/resolve_aliases.rs | 2 +- 9 files changed, 73 insertions(+), 48 deletions(-) diff --git a/src/backend/localify.rs b/src/backend/localify.rs index 060b9d8..82e9122 100644 --- a/src/backend/localify.rs +++ b/src/backend/localify.rs @@ -58,7 +58,7 @@ impl<'a, V: Visitor> BlockVisitor<'a, V> { fn new(body: &'a FunctionBody, trees: &'a Trees, visitor: V) -> Self { log::trace!( "localify: running on:\n{}", - body.display_verbose("| ", None, &crate::NOPPrintDecorator::default()) + body.display_verbose("| ", None) ); Self { body, diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 6dd4309..1875bda 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -37,10 +37,7 @@ macro_rules! op { impl<'a> WasmFuncBackend<'a> { pub fn compile(body: &'a FunctionBody) -> Result { body.validate()?; - log::debug!( - "Backend compiling:\n{}\n", - body.display_verbose("| ", None, &crate::NOPPrintDecorator::default()) - ); + log::debug!("Backend compiling:\n{}\n", body.display_verbose("| ", None)); // For ownership reasons (to avoid a self-referential struct // with the `Cow::Owned` case when the Reducifier modifies the // body), we have to run the Reducifier first, own its result diff --git a/src/backend/reducify.rs b/src/backend/reducify.rs index 76aa7b6..4054c23 100644 --- a/src/backend/reducify.rs +++ b/src/backend/reducify.rs @@ -295,10 +295,7 @@ impl<'a> Reducifier<'a> { crate::passes::maxssa::run(&mut new_body, Some(cut_blocks), &cfg); crate::passes::resolve_aliases::run(&mut new_body); - log::trace!( - "after max-SSA run:\n{}\n", - new_body.display("| ", None, &crate::NOPPrintDecorator::default()) - ); + log::trace!("after max-SSA run:\n{}\n", new_body.display("| ", None)); // Implicitly, context {} has an identity-map from old block // number to new block number. We use the map only for @@ -446,10 +443,7 @@ impl<'a> Reducifier<'a> { new_body.recompute_edges(); - log::trace!( - "After duplication:\n{}\n", - new_body.display("| ", None, &crate::NOPPrintDecorator::default()) - ); + log::trace!("After duplication:\n{}\n", new_body.display("| ", None,)); new_body.validate().unwrap(); new_body.verify_reducible().unwrap(); @@ -548,10 +542,7 @@ mod test { }, ); - log::debug!( - "Body:\n{}", - body.display("| ", Some(&module), &crate::NOPPrintDecorator::default()) - ); + log::debug!("Body:\n{}", body.display("| ", Some(&module))); body.validate().unwrap(); @@ -560,10 +551,7 @@ mod test { new_body.validate().unwrap(); - log::debug!( - "Reducified body:\n{}", - body.display("| ", Some(&module), &crate::NOPPrintDecorator::default()) - ); + log::debug!("Reducified body:\n{}", body.display("| ", Some(&module))); let cfg = CFGInfo::new(&new_body); for (block, def) in new_body.blocks.entries() { diff --git a/src/bin/waffle-util.rs b/src/bin/waffle-util.rs index 6738db8..9f215bf 100644 --- a/src/bin/waffle-util.rs +++ b/src/bin/waffle-util.rs @@ -101,7 +101,7 @@ fn main() -> Result<()> { module.funcs[Func::new(*func)] .body() .unwrap() - .display_verbose("", Some(&module), &waffle::NOPPrintDecorator::default()) + .display_verbose("", Some(&module)) ); } Command::RoundTrip { input, output } => { diff --git a/src/interp.rs b/src/interp.rs index 985e5e6..4952c78 100644 --- a/src/interp.rs +++ b/src/interp.rs @@ -149,7 +149,7 @@ impl InterpContext { log::trace!( "Interp: entering func {}:\n{}\n", func, - body.display_verbose("| ", Some(module), &NOPPrintDecorator::default()) + body.display_verbose("| ", Some(module)) ); log::trace!("args: {:?}", args); diff --git a/src/ir/display.rs b/src/ir/display.rs index a2b9c04..debf2f6 100644 --- a/src/ir/display.rs +++ b/src/ir/display.rs @@ -5,25 +5,45 @@ use crate::entity::EntityRef; use std::collections::HashMap; use std::fmt::{self, Display, Formatter, Result as FmtResult}; -/// Hooks to print information after inst, before and after blocks +/// Hooks to print information after instruction, before and after blocks /// and before and after functions. pub trait PrintDecorator { + /// Print arbitrary text after an instruction. + /// + /// Invoked after every instruction in a block. The instruction has already been printed on its own line; + /// this method can print content after the operator, if desired. fn after_inst(&self, _value: super::Value, _f: &mut fmt::Formatter) -> fmt::Result { Ok(()) } + /// Print arbitrary text before the body of a block. + /// + /// Invoked before the block body. The block id and parameters have already been printed on its own line; + /// this method can print content on the line below the block id, before the body of the block is printed, if desired. fn before_block(&self, _block: super::Block, _f: &mut fmt::Formatter) -> fmt::Result { Ok(()) } + /// Print arbitrary text after the body of a block. + /// + /// Invoked after the block body, before the terminator. The block body has already been printed on its own line(s); + /// this method can print content on the line after the last instruction in the block body, before the terminator is printed. fn after_block(&self, _block: super::Block, _f: &mut fmt::Formatter) -> fmt::Result { Ok(()) } + /// Print arbitrary text before the body of a function. + /// + /// Invoked before the function body is printed. The function id and signature have already been printed on its own line; + /// this method can print content on the line before the function signature line, before the function body is printed. fn before_function_body(&self, _f: &mut fmt::Formatter) -> fmt::Result { Ok(()) } + /// Print arbitrary text after the body of a function. + /// + /// Invoked after the function body is printed. The function body has already been printed; + /// this method can print content on the line after the return block of the function, before the last curly brace to end the function is printed. fn after_function_body(&self, _f: &mut fmt::Formatter) -> fmt::Result { Ok(()) } @@ -40,7 +60,7 @@ pub struct FunctionBodyDisplay<'a, PD: PrintDecorator> { pub(crate) indent: &'a str, pub(crate) verbose: bool, pub(crate) module: Option<&'a Module<'a>>, - pub(crate) decorator: &'a PD, + pub(crate) decorator: Option<&'a PD>, } impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { @@ -66,12 +86,14 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { ret_tys.join(", ") )?; - self.decorator.before_function_body(f)?; + if let Some(decorator) = self.decorator { + decorator.before_function_body(f)?; + } for (value, value_def) in self.body.values.entries() { match value_def { ValueDef::Operator(op, args, tys) if self.verbose => { - write!( + writeln!( f, "{} {} = {} {} # {} ", self.indent, @@ -88,7 +110,6 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { .collect::>() .join(", "), )?; - writeln!(f, "")?; } ValueDef::BlockParam(block, idx, ty) if self.verbose => writeln!( f, @@ -126,7 +147,9 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { block.desc )?; - self.decorator.before_block(block_id, f)?; + if let Some(decorator) = self.decorator { + decorator.before_block(block_id, f)? + }; writeln!( f, @@ -190,7 +213,9 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { tys.join(", "), loc, )?; - self.decorator.after_inst(inst, f)?; + if let Some(decorator) = self.decorator { + decorator.after_inst(inst, f)?; + } writeln!(f, "")?; } ValueDef::PickOutput(val, idx, ty) => { @@ -201,13 +226,16 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { } _ => unreachable!(), } - self.decorator.after_block(block_id, f)?; + } + if let Some(decorator) = self.decorator { + decorator.after_block(block_id, f)?; } writeln!(f, "{} {}", self.indent, block.terminator)?; } - self.decorator.after_function_body(f)?; - + if let Some(decorator) = self.decorator { + decorator.after_function_body(f)?; + } writeln!(f, "{}}}", self.indent)?; Ok(()) @@ -293,11 +321,7 @@ impl<'a, PD: PrintDecorator> Display for ModuleDisplay<'a, PD> { sig, sig_strs.get(&sig).unwrap() )?; - writeln!( - f, - "{}", - body.display(" ", Some(self.module), self.decorators[&func]) - )?; + writeln!(f, "{}", body.display(" ", Some(self.module)))?; } FuncDecl::Lazy(sig, name, reader) => { writeln!( diff --git a/src/ir/func.rs b/src/ir/func.rs index 26934da..3a62d29 100644 --- a/src/ir/func.rs +++ b/src/ir/func.rs @@ -463,7 +463,24 @@ impl FunctionBody { /// Prety-print this function body. `indent` is prepended to each /// line of output. `module`, if provided, allows printing source /// locations as comments at each operator. - pub fn display<'a, PD: PrintDecorator>( + pub fn display<'a>( + &'a self, + indent: &'a str, + module: Option<&'a Module>, + ) -> FunctionBodyDisplay<'a, NOPPrintDecorator> { + FunctionBodyDisplay { + body: self, + indent, + verbose: false, + module, + decorator: None, + } + } + + /// Prety-print this function body. `indent` is prepended to each + /// line of output. `module`, if provided, allows printing source + /// locations as comments at each operator. + pub fn display_with_decorator<'a, PD: PrintDecorator>( &'a self, indent: &'a str, module: Option<&'a Module>, @@ -474,25 +491,24 @@ impl FunctionBody { indent, verbose: false, module, - decorator, + decorator: Some(&decorator), } } /// Pretty-print this function body, with "verbose" format: /// includes all value nodes, even those not listed in a block's /// instruction list. (Roughly doubles output size.) - pub fn display_verbose<'a, PD: PrintDecorator>( + pub fn display_verbose<'a>( &'a self, indent: &'a str, module: Option<&'a Module>, - decorator: &'a PD, - ) -> FunctionBodyDisplay<'a, PD> { + ) -> FunctionBodyDisplay<'a, NOPPrintDecorator> { FunctionBodyDisplay { body: self, indent, verbose: true, module, - decorator, + decorator: None, } } @@ -587,7 +603,7 @@ impl FunctionBody { if bad.len() > 0 { anyhow::bail!( "Body is:\n{}\nError(s) in SSA: {:?}", - self.display_verbose(" | ", None, &NOPPrintDecorator::default()), + self.display_verbose(" | ", None), bad ); } diff --git a/src/passes/empty_blocks.rs b/src/passes/empty_blocks.rs index 6939694..c9fb8cd 100644 --- a/src/passes/empty_blocks.rs +++ b/src/passes/empty_blocks.rs @@ -40,7 +40,7 @@ fn rewrite_target( pub(crate) fn run(body: &mut FunctionBody) { log::trace!( "empty_blocks: running on func:\n{}\n", - body.display_verbose("| ", None, &crate::NOPPrintDecorator::default()) + body.display_verbose("| ", None) ); // Identify empty blocks, and to where they should forward. @@ -72,6 +72,6 @@ pub(crate) fn run(body: &mut FunctionBody) { log::trace!( "empty_blocks: finished:\n{}\n", - body.display_verbose("| ", None, &crate::NOPPrintDecorator::default()) + body.display_verbose("| ", None) ); } diff --git a/src/passes/resolve_aliases.rs b/src/passes/resolve_aliases.rs index 9faac0a..bf46570 100644 --- a/src/passes/resolve_aliases.rs +++ b/src/passes/resolve_aliases.rs @@ -5,7 +5,7 @@ use crate::{FunctionBody, ValueDef}; pub fn run(body: &mut FunctionBody) { log::debug!( "Resolve aliases: running on:\n{}\n", - body.display_verbose("| ", None, &crate::NOPPrintDecorator::default()), + body.display_verbose("| ", None), ); for value in body.values.iter() { let mut value_def = std::mem::take(&mut body.values[value]); From f24f307c651bd042955dee1d65aac9213132bca1 Mon Sep 17 00:00:00 2001 From: michelledaviest Date: Fri, 22 Nov 2024 10:45:14 -0500 Subject: [PATCH 6/9] add comments, made API level change for modules as well, removed commented out code --- src/bin/waffle-util.rs | 11 +++-------- src/ir/display.rs | 2 +- src/ir/func.rs | 28 +++++++--------------------- src/ir/module.rs | 20 +++++++++++++++++--- 4 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/bin/waffle-util.rs b/src/bin/waffle-util.rs index 9f215bf..759d26d 100644 --- a/src/bin/waffle-util.rs +++ b/src/bin/waffle-util.rs @@ -2,9 +2,9 @@ use anyhow::Result; use log::debug; -use std::{collections::HashMap, path::PathBuf}; +use std::path::PathBuf; use structopt::StructOpt; -use waffle::{entity::EntityRef, FrontendOptions, Func, Module, NOPPrintDecorator, OptOptions}; +use waffle::{entity::EntityRef, FrontendOptions, Func, Module, OptOptions}; #[derive(Debug, StructOpt)] #[structopt(name = "waffle-util", about = "WAFFLE utility.")] @@ -84,12 +84,7 @@ fn main() -> Result<()> { debug!("Loaded {} bytes of Wasm data", bytes.len()); let mut module = Module::from_wasm_bytes(&bytes[..], &options)?; apply_options(&opts, &mut module)?; - let mut nop_decorators = HashMap::new(); - let nop_decorator = NOPPrintDecorator::default(); - module.funcs.entries().into_iter().for_each(|(func, _)| { - nop_decorators.insert(func, &nop_decorator); - }); - println!("{}", module.display(nop_decorators)); + println!("{}", module.display()); } Command::PrintFunc { wasm, func } => { let bytes = std::fs::read(wasm)?; diff --git a/src/ir/display.rs b/src/ir/display.rs index debf2f6..f489996 100644 --- a/src/ir/display.rs +++ b/src/ir/display.rs @@ -244,7 +244,7 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { pub struct ModuleDisplay<'a, PD: PrintDecorator> { pub(crate) module: &'a Module<'a>, - pub(crate) decorators: HashMap, + pub(crate) decorators: Option>, } impl<'a, PD: PrintDecorator> Display for ModuleDisplay<'a, PD> { diff --git a/src/ir/func.rs b/src/ir/func.rs index 3a62d29..29ab73a 100644 --- a/src/ir/func.rs +++ b/src/ir/func.rs @@ -8,7 +8,7 @@ use crate::frontend::parse_body; use crate::ir::SourceLoc; use crate::passes::basic_opt::OptOptions; use crate::pool::{ListPool, ListRef}; -use crate::{NOPPrintDecorator, Operator}; +use crate::Operator; use anyhow::Result; use fxhash::FxHashMap; use std::collections::HashSet; @@ -445,21 +445,6 @@ impl FunctionBody { self.blocks[block].terminator = terminator; } - // In func.rs - // pub fn display<'a, PD: PrintDec>( - // &'a self, - // indent: &'a str, - // module: Option<&'a Module>, - // pd: &PD - // ) -> FunctionBodyDisplay<'_, PD> { // print decorator lifetime - // FunctionBodyDisplay { - // body: self, - // indent, - // verbose: false, - // module, - // } - // } - /// Prety-print this function body. `indent` is prepended to each /// line of output. `module`, if provided, allows printing source /// locations as comments at each operator. @@ -467,7 +452,7 @@ impl FunctionBody { &'a self, indent: &'a str, module: Option<&'a Module>, - ) -> FunctionBodyDisplay<'a, NOPPrintDecorator> { + ) -> FunctionBodyDisplay<'a, super::NOPPrintDecorator> { FunctionBodyDisplay { body: self, indent, @@ -477,9 +462,10 @@ impl FunctionBody { } } - /// Prety-print this function body. `indent` is prepended to each - /// line of output. `module`, if provided, allows printing source - /// locations as comments at each operator. + /// Prety-print this function body with some additional information. + /// `indent` is prepended to each line of output. + /// `module`, if provided, allows printing source locations as comments at each operator. + /// `decorator` describes how the additional information should be printed in the IR. pub fn display_with_decorator<'a, PD: PrintDecorator>( &'a self, indent: &'a str, @@ -502,7 +488,7 @@ impl FunctionBody { &'a self, indent: &'a str, module: Option<&'a Module>, - ) -> FunctionBodyDisplay<'a, NOPPrintDecorator> { + ) -> FunctionBodyDisplay<'a, super::NOPPrintDecorator> { FunctionBodyDisplay { body: self, indent, diff --git a/src/ir/module.rs b/src/ir/module.rs index 76b10dc..1ef1896 100644 --- a/src/ir/module.rs +++ b/src/ir/module.rs @@ -1,5 +1,6 @@ use super::{ - Func, FuncDecl, Global, Memory, ModuleDisplay, PrintDecorator, Signature, Table, Type, + Func, FuncDecl, Global, Memory, ModuleDisplay, NOPPrintDecorator, PrintDecorator, Signature, + Table, Type, }; use crate::entity::{EntityRef, EntityVec}; use crate::ir::{Debug, DebugMap, FunctionBody}; @@ -329,7 +330,20 @@ impl<'a> Module<'a> { /// Return a wrapper that implements Display on this module, /// pretty-printing it as textual IR. - pub fn display<'b, PD: PrintDecorator>( + pub fn display<'b>(&'b self) -> ModuleDisplay<'b, NOPPrintDecorator> + where + 'b: 'a, + { + ModuleDisplay { + module: self, + decorators: None, + } + } + + /// Return a wrapper that implements Display on this module, + /// pretty-printing it as textual IR with some additional text whose + /// printing is described in Decorator. + pub fn display_with_decorators<'b, PD: PrintDecorator>( &'b self, decorators: HashMap, ) -> ModuleDisplay<'b, PD> @@ -338,7 +352,7 @@ impl<'a> Module<'a> { { ModuleDisplay { module: self, - decorators, + decorators: Some(decorators), } } From bf7b4a6a1cb8d883bedc68cbdfc5b12ec70997dc Mon Sep 17 00:00:00 2001 From: michelledaviest Date: Fri, 22 Nov 2024 11:13:17 -0500 Subject: [PATCH 7/9] remove dangling comma --- src/backend/reducify.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/reducify.rs b/src/backend/reducify.rs index 4054c23..b522fb5 100644 --- a/src/backend/reducify.rs +++ b/src/backend/reducify.rs @@ -443,7 +443,7 @@ impl<'a> Reducifier<'a> { new_body.recompute_edges(); - log::trace!("After duplication:\n{}\n", new_body.display("| ", None,)); + log::trace!("After duplication:\n{}\n", new_body.display("| ", None)); new_body.validate().unwrap(); new_body.verify_reducible().unwrap(); From f892a15b6feae1121c4127d9443d412400abc750 Mon Sep 17 00:00:00 2001 From: michelledaviest Date: Fri, 22 Nov 2024 11:24:46 -0500 Subject: [PATCH 8/9] make NOPPrintDecorator non-pub --- src/ir/display.rs | 2 +- src/ir/func.rs | 11 ++++++----- src/ir/module.rs | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/ir/display.rs b/src/ir/display.rs index f489996..f8dc60d 100644 --- a/src/ir/display.rs +++ b/src/ir/display.rs @@ -50,7 +50,7 @@ pub trait PrintDecorator { } #[derive(Default)] -pub struct NOPPrintDecorator(); +pub(crate) struct NOPPrintDecorator(); impl PrintDecorator for NOPPrintDecorator {} /// A wrapper around a `FunctionBody` together with some auxiliary diff --git a/src/ir/func.rs b/src/ir/func.rs index 29ab73a..f2f769c 100644 --- a/src/ir/func.rs +++ b/src/ir/func.rs @@ -1,5 +1,6 @@ use super::{ - Block, FunctionBodyDisplay, Local, Module, PrintDecorator, Signature, Type, Value, ValueDef, + Block, FunctionBodyDisplay, Local, Module, NOPPrintDecorator, PrintDecorator, Signature, Type, + Value, ValueDef, }; use crate::backend::WasmFuncBackend; use crate::cfg::CFGInfo; @@ -452,8 +453,8 @@ impl FunctionBody { &'a self, indent: &'a str, module: Option<&'a Module>, - ) -> FunctionBodyDisplay<'a, super::NOPPrintDecorator> { - FunctionBodyDisplay { + ) -> FunctionBodyDisplay<'a, impl PrintDecorator> { + FunctionBodyDisplay:: { body: self, indent, verbose: false, @@ -488,8 +489,8 @@ impl FunctionBody { &'a self, indent: &'a str, module: Option<&'a Module>, - ) -> FunctionBodyDisplay<'a, super::NOPPrintDecorator> { - FunctionBodyDisplay { + ) -> FunctionBodyDisplay<'a, impl PrintDecorator> { + FunctionBodyDisplay:: { body: self, indent, verbose: true, diff --git a/src/ir/module.rs b/src/ir/module.rs index 1ef1896..8fe5bc9 100644 --- a/src/ir/module.rs +++ b/src/ir/module.rs @@ -330,11 +330,11 @@ impl<'a> Module<'a> { /// Return a wrapper that implements Display on this module, /// pretty-printing it as textual IR. - pub fn display<'b>(&'b self) -> ModuleDisplay<'b, NOPPrintDecorator> + pub fn display<'b>(&'b self) -> ModuleDisplay<'b, impl PrintDecorator> where 'b: 'a, { - ModuleDisplay { + ModuleDisplay:: { module: self, decorators: None, } From 549ac022401e7c5e7f56e197a0fab83b9f053614 Mon Sep 17 00:00:00 2001 From: michelledaviest Date: Mon, 25 Nov 2024 16:51:45 -0500 Subject: [PATCH 9/9] module display now takes in callback that provides decorator --- src/ir/display.rs | 14 +++++++++++--- src/ir/module.rs | 6 +++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/ir/display.rs b/src/ir/display.rs index f8dc60d..c5bfecd 100644 --- a/src/ir/display.rs +++ b/src/ir/display.rs @@ -1,6 +1,6 @@ //! Displaying IR. -use super::{FuncDecl, FunctionBody, Module, SourceLoc, ValueDef}; +use super::{Func, FuncDecl, FunctionBody, Module, SourceLoc, ValueDef}; use crate::entity::EntityRef; use std::collections::HashMap; use std::fmt::{self, Display, Formatter, Result as FmtResult}; @@ -244,7 +244,7 @@ impl<'a, PD: PrintDecorator> Display for FunctionBodyDisplay<'a, PD> { pub struct ModuleDisplay<'a, PD: PrintDecorator> { pub(crate) module: &'a Module<'a>, - pub(crate) decorators: Option>, + pub(crate) decorators: Option PD>>, } impl<'a, PD: PrintDecorator> Display for ModuleDisplay<'a, PD> { @@ -321,7 +321,15 @@ impl<'a, PD: PrintDecorator> Display for ModuleDisplay<'a, PD> { sig, sig_strs.get(&sig).unwrap() )?; - writeln!(f, "{}", body.display(" ", Some(self.module)))?; + + if let Some(decorator) = &self.decorators { + let decorator = &(*decorator)(func); + writeln!( + f, + "{}", + body.display_with_decorator(" ", Some(self.module), decorator) + )?; + } } FuncDecl::Lazy(sig, name, reader) => { writeln!( diff --git a/src/ir/module.rs b/src/ir/module.rs index 8fe5bc9..7f7cc3b 100644 --- a/src/ir/module.rs +++ b/src/ir/module.rs @@ -6,7 +6,7 @@ use crate::entity::{EntityRef, EntityVec}; use crate::ir::{Debug, DebugMap, FunctionBody}; use crate::{backend, frontend}; use anyhow::Result; -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; pub use crate::frontend::FrontendOptions; @@ -343,9 +343,9 @@ impl<'a> Module<'a> { /// Return a wrapper that implements Display on this module, /// pretty-printing it as textual IR with some additional text whose /// printing is described in Decorator. - pub fn display_with_decorators<'b, PD: PrintDecorator>( + pub fn display_with_decorator<'b, PD: PrintDecorator>( &'b self, - decorators: HashMap, + decorators: Box PD>, ) -> ModuleDisplay<'b, PD> where 'b: 'a,