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

@@ -5,11 +5,12 @@
use peepmatic_runtime::{
cc::ConditionCode,
instruction_set::InstructionSet,
operator::Operator,
part::{Constant, Part},
paths::Path,
r#type::{BitWidth, Kind, Type},
};
use peepmatic_test_operator::TestOperator;
use peepmatic_traits::TypingRules;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::convert::TryFrom;
@@ -19,7 +20,7 @@ pub struct Instruction(pub usize);
#[derive(Debug)]
pub struct InstructionData {
pub operator: Operator,
pub operator: TestOperator,
pub r#type: Type,
pub immediates: Vec<Immediate>,
pub arguments: Vec<Instruction>,
@@ -174,7 +175,7 @@ impl Program {
pub fn new_instruction(
&mut self,
operator: Operator,
operator: TestOperator,
r#type: Type,
immediates: Vec<Immediate>,
arguments: Vec<Instruction>,
@@ -188,11 +189,11 @@ impl Program {
immediates.len(),
);
assert_eq!(
operator.params_arity() as usize,
operator.parameters_arity() as usize,
arguments.len(),
"wrong number of arguments for {:?}: expected {}, found {}",
operator,
operator.params_arity(),
operator.parameters_arity(),
arguments.len(),
);
@@ -222,7 +223,7 @@ impl Program {
assert!(!root_bit_width.is_polymorphic());
match c {
Constant::Bool(_, bit_width) => self.new_instruction(
Operator::Bconst,
TestOperator::Bconst,
if bit_width.is_polymorphic() {
Type {
kind: Kind::Bool,
@@ -238,7 +239,7 @@ impl Program {
vec![],
),
Constant::Int(_, bit_width) => self.new_instruction(
Operator::Iconst,
TestOperator::Iconst,
if bit_width.is_polymorphic() {
Type {
kind: Kind::Int,
@@ -259,12 +260,12 @@ impl Program {
fn instruction_to_constant(&mut self, inst: Instruction) -> Option<Constant> {
match self.data(inst) {
InstructionData {
operator: Operator::Iconst,
operator: TestOperator::Iconst,
immediates,
..
} => Some(immediates[0].unwrap_constant()),
InstructionData {
operator: Operator::Bconst,
operator: TestOperator::Bconst,
immediates,
..
} => Some(immediates[0].unwrap_constant()),
@@ -310,6 +311,8 @@ pub struct TestIsa {
// Unsafe because we must ensure that `instruction_result_bit_width` never
// returns zero.
unsafe impl<'a> InstructionSet<'a> for TestIsa {
type Operator = TestOperator;
type Context = Program;
type Instruction = Instruction;
@@ -360,7 +363,7 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
Some(part)
}
fn operator(&self, program: &mut Program, instr: Instruction) -> Option<Operator> {
fn operator(&self, program: &mut Program, instr: Instruction) -> Option<TestOperator> {
log::debug!("operator({:?})", instr);
let data = program.data(instr);
Some(data.operator)
@@ -370,7 +373,7 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
&self,
program: &mut Program,
root: Instruction,
operator: Operator,
operator: TestOperator,
r#type: Type,
a: Part<Instruction>,
) -> Instruction {
@@ -383,11 +386,11 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
let (imms, args) = match operator.immediates_arity() {
0 => {
assert_eq!(operator.params_arity(), 1);
assert_eq!(operator.parameters_arity(), 1);
(vec![], vec![program.part_to_instruction(root, a).unwrap()])
}
1 => {
assert_eq!(operator.params_arity(), 0);
assert_eq!(operator.parameters_arity(), 0);
(vec![program.part_to_immediate(a).unwrap()], vec![])
}
_ => unreachable!(),
@@ -399,7 +402,7 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
&self,
program: &mut Program,
root: Instruction,
operator: Operator,
operator: TestOperator,
r#type: Type,
a: Part<Instruction>,
b: Part<Instruction>,
@@ -414,7 +417,7 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
let (imms, args) = match operator.immediates_arity() {
0 => {
assert_eq!(operator.params_arity(), 2);
assert_eq!(operator.parameters_arity(), 2);
(
vec![],
vec![
@@ -424,14 +427,14 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
)
}
1 => {
assert_eq!(operator.params_arity(), 1);
assert_eq!(operator.parameters_arity(), 1);
(
vec![program.part_to_immediate(a).unwrap()],
vec![program.part_to_instruction(root, b).unwrap()],
)
}
2 => {
assert_eq!(operator.params_arity(), 0);
assert_eq!(operator.parameters_arity(), 0);
(
vec![
program.part_to_immediate(a).unwrap(),
@@ -449,7 +452,7 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
&self,
program: &mut Program,
root: Instruction,
operator: Operator,
operator: TestOperator,
r#type: Type,
a: Part<Instruction>,
b: Part<Instruction>,
@@ -465,7 +468,7 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
);
let (imms, args) = match operator.immediates_arity() {
0 => {
assert_eq!(operator.params_arity(), 3);
assert_eq!(operator.parameters_arity(), 3);
(
vec![],
vec![
@@ -476,7 +479,7 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
)
}
1 => {
assert_eq!(operator.params_arity(), 2);
assert_eq!(operator.parameters_arity(), 2);
(
vec![program.part_to_immediate(a).unwrap()],
vec![
@@ -486,7 +489,7 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
)
}
2 => {
assert_eq!(operator.params_arity(), 1);
assert_eq!(operator.parameters_arity(), 1);
(
vec![
program.part_to_immediate(a).unwrap(),
@@ -496,7 +499,7 @@ unsafe impl<'a> InstructionSet<'a> for TestIsa {
)
}
3 => {
assert_eq!(operator.params_arity(), 0);
assert_eq!(operator.parameters_arity(), 0);
(
vec![
program.part_to_immediate(a).unwrap(),