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:
Nick Fitzgerald
2020-06-30 11:50:10 -07:00
parent ae95ad8733
commit ee5982fd16
46 changed files with 1945 additions and 1387 deletions

View File

@@ -7,17 +7,22 @@
use crate::cc::ConditionCode;
use crate::integer_interner::{IntegerId, IntegerInterner};
use crate::operator::{Operator, UnquoteOperator};
use crate::paths::{PathId, PathInterner};
use crate::r#type::{BitWidth, Type};
use crate::unquote::UnquoteOperator;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::hash::Hash;
use std::num::NonZeroU32;
/// A set of linear optimizations.
#[derive(Debug)]
pub struct Optimizations {
pub struct Optimizations<TOperator>
where
TOperator: 'static + Copy + Debug + Eq + Hash,
{
/// The linear optimizations.
pub optimizations: Vec<Optimization>,
pub optimizations: Vec<Optimization<TOperator>>,
/// The de-duplicated paths referenced by these optimizations.
pub paths: PathInterner,
@@ -28,9 +33,12 @@ pub struct Optimizations {
/// A linearized optimization.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Optimization {
pub struct Optimization<TOperator>
where
TOperator: 'static + Copy + Debug + Eq + Hash,
{
/// The chain of increments for this optimization.
pub increments: Vec<Increment>,
pub increments: Vec<Increment<TOperator>>,
}
/// Match any value.
@@ -63,7 +71,10 @@ pub fn bool_to_match_result(b: bool) -> MatchResult {
/// basically become a state and a transition edge out of that state in the
/// final automata.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Increment {
pub struct Increment<TOperator>
where
TOperator: 'static + Copy + Debug + Eq + Hash,
{
/// The matching operation to perform.
pub operation: MatchOp,
@@ -74,7 +85,7 @@ pub struct Increment {
/// Actions to perform, given that the operation resulted in the expected
/// value.
pub actions: Vec<Action>,
pub actions: Vec<Action<TOperator>>,
}
/// A matching operation to be performed on some Cranelift instruction as part
@@ -163,7 +174,7 @@ pub struct RhsId(pub u16);
/// When evaluating actions, the `i^th` action implicitly defines the
/// `RhsId(i)`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Action {
pub enum Action<TOperator> {
/// Reuse something from the left-hand side.
GetLhs {
/// The path to the instruction or value.
@@ -215,13 +226,13 @@ pub enum Action {
/// The type of this instruction's result.
r#type: Type,
/// The operator for this instruction.
operator: Operator,
operator: TOperator,
},
/// Make a binary instruction.
MakeBinaryInst {
/// The opcode for this instruction.
operator: Operator,
operator: TOperator,
/// The type of this instruction's result.
r#type: Type,
/// The operands for this instruction.
@@ -231,7 +242,7 @@ pub enum Action {
/// Make a ternary instruction.
MakeTernaryInst {
/// The opcode for this instruction.
operator: Operator,
operator: TOperator,
/// The type of this instruction's result.
r#type: Type,
/// The operands for this instruction.
@@ -242,6 +253,7 @@ pub enum Action {
#[cfg(test)]
mod tests {
use super::*;
use peepmatic_test_operator::TestOperator;
// These types all end up in the automaton, so we should take care that they
// are small and don't fill up the data cache (or take up too much
@@ -259,6 +271,6 @@ mod tests {
#[test]
fn action_size() {
assert_eq!(std::mem::size_of::<Action>(), 16);
assert_eq!(std::mem::size_of::<Action<TestOperator>>(), 16);
}
}