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:
@@ -1,6 +1,8 @@
|
||||
//! Traversals over the AST.
|
||||
|
||||
use crate::ast::*;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
||||
/// A low-level DFS traversal event: either entering or exiting the traversal of
|
||||
/// an AST node.
|
||||
@@ -32,13 +34,16 @@ pub enum TraversalEvent {
|
||||
/// the AST, because the `new` constructor takes anything that can convert into
|
||||
/// a `DynAstRef`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Dfs<'a> {
|
||||
stack: Vec<(TraversalEvent, DynAstRef<'a>)>,
|
||||
pub struct Dfs<'a, TOperator> {
|
||||
stack: Vec<(TraversalEvent, DynAstRef<'a, TOperator>)>,
|
||||
}
|
||||
|
||||
impl<'a> Dfs<'a> {
|
||||
impl<'a, TOperator> Dfs<'a, TOperator>
|
||||
where
|
||||
TOperator: Copy + Debug + Eq + Hash,
|
||||
{
|
||||
/// Construct a new `Dfs` traversal starting at the given `start` AST node.
|
||||
pub fn new(start: impl Into<DynAstRef<'a>>) -> Self {
|
||||
pub fn new(start: impl Into<DynAstRef<'a, TOperator>>) -> Self {
|
||||
let start = start.into();
|
||||
Dfs {
|
||||
stack: vec![
|
||||
@@ -49,15 +54,18 @@ impl<'a> Dfs<'a> {
|
||||
}
|
||||
|
||||
/// Peek at the next traversal event and AST node pair, if any.
|
||||
pub fn peek(&self) -> Option<(TraversalEvent, DynAstRef<'a>)> {
|
||||
self.stack.last().cloned()
|
||||
pub fn peek(&self) -> Option<(TraversalEvent, DynAstRef<'a, TOperator>)> {
|
||||
self.stack.last().copied()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Dfs<'a> {
|
||||
type Item = (TraversalEvent, DynAstRef<'a>);
|
||||
impl<'a, TOperator> Iterator for Dfs<'a, TOperator>
|
||||
where
|
||||
TOperator: Copy,
|
||||
{
|
||||
type Item = (TraversalEvent, DynAstRef<'a, TOperator>);
|
||||
|
||||
fn next(&mut self) -> Option<(TraversalEvent, DynAstRef<'a>)> {
|
||||
fn next(&mut self) -> Option<(TraversalEvent, DynAstRef<'a, TOperator>)> {
|
||||
let (event, node) = self.stack.pop()?;
|
||||
if let TraversalEvent::Enter = event {
|
||||
let mut enqueue_children = EnqueueChildren(self);
|
||||
@@ -65,15 +73,16 @@ impl<'a> Iterator for Dfs<'a> {
|
||||
}
|
||||
return Some((event, node));
|
||||
|
||||
struct EnqueueChildren<'a, 'b>(&'b mut Dfs<'a>)
|
||||
struct EnqueueChildren<'a, 'b, TOperator>(&'b mut Dfs<'a, TOperator>)
|
||||
where
|
||||
'a: 'b;
|
||||
|
||||
impl<'a, 'b> Extend<DynAstRef<'a>> for EnqueueChildren<'a, 'b>
|
||||
impl<'a, 'b, TOperator> Extend<DynAstRef<'a, TOperator>> for EnqueueChildren<'a, 'b, TOperator>
|
||||
where
|
||||
'a: 'b,
|
||||
TOperator: Copy,
|
||||
{
|
||||
fn extend<T: IntoIterator<Item = DynAstRef<'a>>>(&mut self, iter: T) {
|
||||
fn extend<T: IntoIterator<Item = DynAstRef<'a, TOperator>>>(&mut self, iter: T) {
|
||||
let iter = iter.into_iter();
|
||||
|
||||
let (min, max) = iter.size_hint();
|
||||
@@ -97,6 +106,7 @@ impl<'a> Iterator for Dfs<'a> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use peepmatic_test_operator::TestOperator;
|
||||
use DynAstRef::*;
|
||||
|
||||
#[test]
|
||||
@@ -107,7 +117,7 @@ mod tests {
|
||||
(ishl $x $(log2 $C)))
|
||||
";
|
||||
let buf = wast::parser::ParseBuffer::new(input).expect("input should lex OK");
|
||||
let ast = match wast::parser::parse::<crate::ast::Optimizations>(&buf) {
|
||||
let ast = match wast::parser::parse::<crate::ast::Optimizations<TestOperator>>(&buf) {
|
||||
Ok(ast) => ast,
|
||||
Err(e) => panic!("expected to parse OK, got error:\n\n{}", e),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user