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,21 @@ use peepmatic_runtime::{
cc::ConditionCode,
integer_interner::{IntegerId, IntegerInterner},
linear,
operator::Operator,
paths::{PathId, PathInterner},
};
use std::convert::{TryFrom, TryInto};
use std::fmt::Debug;
use std::io::{self, Write};
use std::num::NonZeroU16;
use std::num::{NonZeroU16, NonZeroU32};
#[derive(Debug)]
pub(crate) struct PeepholeDotFmt<'a>(pub(crate) &'a PathInterner, pub(crate) &'a IntegerInterner);
impl DotFmt<linear::MatchResult, linear::MatchOp, Box<[linear::Action]>> for PeepholeDotFmt<'_> {
impl<TOperator> DotFmt<linear::MatchResult, linear::MatchOp, Box<[linear::Action<TOperator>]>>
for PeepholeDotFmt<'_>
where
TOperator: Debug + TryFrom<NonZeroU32>,
{
fn fmt_transition(
&self,
w: &mut impl Write,
@@ -26,22 +30,23 @@ impl DotFmt<linear::MatchResult, linear::MatchOp, Box<[linear::Action]>> for Pee
_to: Option<&linear::MatchOp>,
) -> io::Result<()> {
let from = from.expect("we should have match op for every state");
if let Some(x) = input.ok().map(|x| x.get()) {
if let Some(x) = input.ok() {
match from {
linear::MatchOp::Opcode { .. } => {
let opcode =
Operator::try_from(x).expect("we shouldn't generate non-opcode edges");
write!(w, "{}", opcode)
let opcode = TOperator::try_from(x)
.map_err(|_| ())
.expect("we shouldn't generate non-opcode edges");
write!(w, "{:?}", opcode)
}
linear::MatchOp::ConditionCode { .. } => {
let cc =
ConditionCode::try_from(x).expect("we shouldn't generate non-CC edges");
let cc = ConditionCode::try_from(x.get())
.expect("we shouldn't generate non-CC edges");
write!(w, "{}", cc)
}
linear::MatchOp::IntegerValue { .. } => {
let x = self
.1
.lookup(IntegerId(NonZeroU16::new(x.try_into().unwrap()).unwrap()));
let x = self.1.lookup(IntegerId(
NonZeroU16::new(x.get().try_into().unwrap()).unwrap(),
));
write!(w, "{}", x)
}
_ => write!(w, "Ok({})", x),
@@ -73,7 +78,11 @@ impl DotFmt<linear::MatchResult, linear::MatchOp, Box<[linear::Action]>> for Pee
writeln!(w, "</font>")
}
fn fmt_output(&self, w: &mut impl Write, actions: &Box<[linear::Action]>) -> io::Result<()> {
fn fmt_output(
&self,
w: &mut impl Write,
actions: &Box<[linear::Action<TOperator>]>,
) -> io::Result<()> {
use linear::Action::*;
if actions.is_empty() {
@@ -88,11 +97,11 @@ impl DotFmt<linear::MatchResult, linear::MatchOp, Box<[linear::Action]>> for Pee
match a {
GetLhs { path } => write!(w, "get-lhs @ {}<br/>", p(path))?,
UnaryUnquote { operator, operand } => {
write!(w, "eval {} $rhs{}<br/>", operator, operand.0)?
write!(w, "eval {:?} $rhs{}<br/>", operator, operand.0)?
}
BinaryUnquote { operator, operands } => write!(
w,
"eval {} $rhs{}, $rhs{}<br/>",
"eval {:?} $rhs{}, $rhs{}<br/>",
operator, operands[0].0, operands[1].0,
)?,
MakeIntegerConst {
@@ -108,14 +117,14 @@ impl DotFmt<linear::MatchResult, linear::MatchOp, Box<[linear::Action]>> for Pee
operand,
operator,
r#type: _,
} => write!(w, "make {} $rhs{}<br/>", operator, operand.0,)?,
} => write!(w, "make {:?} $rhs{}<br/>", operator, operand.0,)?,
MakeBinaryInst {
operator,
operands,
r#type: _,
} => write!(
w,
"make {} $rhs{}, $rhs{}<br/>",
"make {:?} $rhs{}, $rhs{}<br/>",
operator, operands[0].0, operands[1].0,
)?,
MakeTernaryInst {
@@ -124,7 +133,7 @@ impl DotFmt<linear::MatchResult, linear::MatchOp, Box<[linear::Action]>> for Pee
r#type: _,
} => write!(
w,
"make {} $rhs{}, $rhs{}, $rhs{}<br/>",
"make {:?} $rhs{}, $rhs{}, $rhs{}<br/>",
operator, operands[0].0, operands[1].0, operands[2].0,
)?,
}