peepmatic: Be generic over the operator type
This lets us avoid the cost of `cranelift_codegen::ir::Opcode` to `peepmatic_runtime::Operator` conversion overhead, and paves the way for allowing Peepmatic to support non-clif optimizations (e.g. vcode optimizations). Rather than defining our own `peepmatic::Operator` type like we used to, now the whole `peepmatic` crate is effectively generic over a `TOperator` type parameter. For the Cranelift integration, we use `cranelift_codegen::ir::Opcode` as the concrete type for our `TOperator` type parameter. For testing, we also define a `TestOperator` type, so that we can test Peepmatic code without building all of Cranelift, and we can keep them somewhat isolated from each other. The methods that `peepmatic::Operator` had are now translated into trait bounds on the `TOperator` type. These traits need to be shared between all of `peepmatic`, `peepmatic-runtime`, and `cranelift-codegen`'s Peepmatic integration. Therefore, these new traits live in a new crate: `peepmatic-traits`. This crate acts as a header file of sorts for shared trait/type/macro definitions. Additionally, the `peepmatic-runtime` crate no longer depends on the `peepmatic-macro` procedural macro crate, which should lead to faster build times for Cranelift when it is using pre-built peephole optimizers.
This commit is contained in:
@@ -23,20 +23,25 @@ pub use self::{
|
||||
};
|
||||
|
||||
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
|
||||
///
|
||||
/// ```no_run
|
||||
/// ```ignore
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// let peep_opts = peepmatic::compile_file(Path::new(
|
||||
/// "path/to/optimizations.peepmatic"
|
||||
/// ))?;
|
||||
/// let peep_opts = peepmatic::compile_file::<cranelift_codegen::ir::Opcode>(
|
||||
/// Path::new("path/to/optimizations.peepmatic")
|
||||
/// )?;
|
||||
///
|
||||
/// // Use the peephole optimizations or serialize them into bytes here...
|
||||
/// # Ok(())
|
||||
@@ -49,9 +54,19 @@ use std::path::Path;
|
||||
/// `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> {
|
||||
pub fn compile_file<TOperator>(filename: &Path) -> anyhow::Result<PeepholeOptimizations<TOperator>>
|
||||
where
|
||||
TOperator: Copy
|
||||
+ Debug
|
||||
+ Eq
|
||||
+ Hash
|
||||
+ for<'a> wast::parser::Parse<'a>
|
||||
+ TypingRules
|
||||
+ Into<NonZeroU32>
|
||||
+ TryFrom<NonZeroU32>,
|
||||
{
|
||||
let source = fs::read_to_string(filename)?;
|
||||
compile_str(&source, filename)
|
||||
compile_str::<TOperator>(&source, filename)
|
||||
}
|
||||
|
||||
/// Compile the given DSL source text down into a compact peephole optimizations
|
||||
@@ -64,11 +79,11 @@ pub fn compile_file(filename: &Path) -> anyhow::Result<PeepholeOptimizations> {
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// ```ignore
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// let peep_opts = peepmatic::compile_str(
|
||||
/// let peep_opts = peepmatic::compile_str::<cranelift_codegen::ir::Opcode>(
|
||||
/// "
|
||||
/// (=> (iadd $x 0) $x)
|
||||
/// (=> (imul $x 0) 0)
|
||||
@@ -88,14 +103,27 @@ pub fn compile_file(filename: &Path) -> anyhow::Result<PeepholeOptimizations> {
|
||||
/// `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> {
|
||||
pub fn compile_str<TOperator>(
|
||||
source: &str,
|
||||
filename: &Path,
|
||||
) -> anyhow::Result<PeepholeOptimizations<TOperator>>
|
||||
where
|
||||
TOperator: Copy
|
||||
+ Debug
|
||||
+ Eq
|
||||
+ Hash
|
||||
+ for<'a> wast::parser::Parse<'a>
|
||||
+ TypingRules
|
||||
+ Into<NonZeroU32>
|
||||
+ TryFrom<NonZeroU32>,
|
||||
{
|
||||
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| {
|
||||
let opts = wast::parser::parse::<Optimizations<'_, TOperator>>(&buf).map_err(|mut e| {
|
||||
e.set_path(filename);
|
||||
e.set_text(source);
|
||||
e
|
||||
@@ -137,9 +165,10 @@ pub fn compile_str(source: &str, filename: &Path) -> anyhow::Result<PeepholeOpti
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use peepmatic_test_operator::TestOperator;
|
||||
|
||||
fn assert_compiles(path: &str) {
|
||||
match compile_file(Path::new(path)) {
|
||||
match compile_file::<TestOperator>(Path::new(path)) {
|
||||
Ok(_) => return,
|
||||
Err(e) => {
|
||||
eprintln!("error: {}", e);
|
||||
|
||||
Reference in New Issue
Block a user