peepmatic: Introduce the main peepmatic crate
Peepmatic is a DSL for peephole optimizations and compiler for generating peephole optimizers from them. The user writes a set of optimizations in the DSL, and then `peepmatic` compiles the set of optimizations into an efficient peephole optimizer: ``` DSL ----peepmatic----> Peephole Optimizer ``` The generated peephole optimizer has all of its optimizations' left-hand sides collapsed into a compact automata that makes matching candidate instruction sequences fast. The DSL's optimizations may be written by hand or discovered mechanically with a superoptimizer like [Souper][]. Eventually, `peepmatic` should have a verifier that ensures that the DSL's optimizations are sound, similar to what [Alive][] does for LLVM optimizations. [Souper]: https://github.com/google/souper [Alive]: https://github.com/AliveToolkit/alive2
This commit is contained in:
165
cranelift/peepmatic/src/lib.rs
Executable file
165
cranelift/peepmatic/src/lib.rs
Executable file
@@ -0,0 +1,165 @@
|
||||
/*!
|
||||
|
||||
`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 std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
/// Compile the given DSL file into a compact peephole optimizations automaton!
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # 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<PeepholeOptimizations> {
|
||||
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
|
||||
///
|
||||
/// ```no_run
|
||||
/// # 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<PeepholeOptimizations> {
|
||||
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::<Optimizations>(&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::*;
|
||||
|
||||
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("examples/preopt.peepmatic");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user