/*! `peepmatic` is a DSL and compiler for generating peephole optimizers. The user writes a set of optimizations in the DSL, and then `peepmatic` compiles the set of optimizations into an efficient peephole optimizer. */ #![deny(missing_docs)] #![deny(missing_debug_implementations)] mod ast; mod automatize; mod dot_fmt; mod linear_passes; mod linearize; mod parser; mod traversals; mod verify; pub use self::{ ast::*, automatize::*, linear_passes::*, linearize::*, parser::*, traversals::*, verify::*, }; use peepmatic_runtime::PeepholeOptimizations; use peepmatic_traits::TypingRules; use std::convert::TryFrom; use std::fmt::Debug; use std::fs; use std::hash::Hash; use std::num::NonZeroU32; use std::path::Path; /// Compile the given DSL file into a compact peephole optimizations automaton! /// /// ## Example /// /// ```ignore /// # fn main() -> anyhow::Result<()> { /// use std::path::Path; /// /// let peep_opts = peepmatic::compile_file::( /// Path::new("path/to/optimizations.peepmatic") /// )?; /// /// // Use the peephole optimizations or serialize them into bytes here... /// # Ok(()) /// # } /// ``` /// /// ## Visualizing the Peephole Optimizer's Automaton /// /// To visualize (or debug) the peephole optimizer's automaton, set the /// `PEEPMATIC_DOT` environment variable to a file path. A [GraphViz /// Dot]((https://graphviz.gitlab.io/_pages/pdf/dotguide.pdf)) file showing the /// peephole optimizer's automaton will be written to that file path. pub fn compile_file(filename: &Path) -> anyhow::Result> where TOperator: Copy + Debug + Eq + Hash + for<'a> wast::parser::Parse<'a> + TypingRules + Into + TryFrom, { let source = fs::read_to_string(filename)?; compile_str::(&source, filename) } /// Compile the given DSL source text down into a compact peephole optimizations /// automaton. /// /// This is like [compile_file][crate::compile_file] but you bring your own file /// I/O. /// /// The `filename` parameter is used to provide better error messages. /// /// ## Example /// /// ```ignore /// # fn main() -> anyhow::Result<()> { /// use std::path::Path; /// /// let peep_opts = peepmatic::compile_str::( /// " /// (=> (iadd $x 0) $x) /// (=> (imul $x 0) 0) /// (=> (imul $x 1) $x) /// ", /// Path::new("my-optimizations"), /// )?; /// /// // Use the peephole optimizations or serialize them into bytes here... /// # Ok(()) /// # } /// ``` /// /// ## Visualizing the Peephole Optimizer's Automaton /// /// To visualize (or debug) the peephole optimizer's automaton, set the /// `PEEPMATIC_DOT` environment variable to a file path. A [GraphViz /// Dot]((https://graphviz.gitlab.io/_pages/pdf/dotguide.pdf)) file showing the /// peephole optimizer's automaton will be written to that file path. pub fn compile_str( source: &str, filename: &Path, ) -> anyhow::Result> where TOperator: Copy + Debug + Eq + Hash + for<'a> wast::parser::Parse<'a> + TypingRules + Into + TryFrom, { let buf = wast::parser::ParseBuffer::new(source).map_err(|mut e| { e.set_path(filename); e.set_text(source); e })?; let opts = wast::parser::parse::>(&buf).map_err(|mut e| { e.set_path(filename); e.set_text(source); e })?; verify(&opts).map_err(|mut e| { e.set_path(filename); e.set_text(source); e })?; let mut opts = crate::linearize(&opts); sort_least_to_most_general(&mut opts); remove_unnecessary_nops(&mut opts); match_in_same_order(&mut opts); sort_lexicographically(&mut opts); let automata = automatize(&opts); let paths = opts.paths; let integers = opts.integers; if let Ok(path) = std::env::var("PEEPMATIC_DOT") { let f = dot_fmt::PeepholeDotFmt(&paths, &integers); if let Err(e) = automata.write_dot_file(&f, &path) { panic!( "failed to write GraphViz Dot file to PEEPMATIC_DOT={}; error: {}", path, e ); } } Ok(PeepholeOptimizations { paths, integers, automata, }) } #[cfg(test)] mod tests { use super::*; use peepmatic_test_operator::TestOperator; fn assert_compiles(path: &str) { match compile_file::(Path::new(path)) { Ok(_) => return, Err(e) => { eprintln!("error: {}", e); panic!("error: {}", e); } } } #[test] fn compile_redundant_bor() { assert_compiles("examples/redundant-bor.peepmatic"); } #[test] fn mul_by_pow2() { assert_compiles("examples/mul-by-pow2.peepmatic"); } #[test] fn compile_preopt() { assert_compiles("../codegen/src/preopt.peepmatic"); } }