Files
wasmtime/cranelift/peepmatic/crates/runtime/src/instruction_set.rs
Nick Fitzgerald ee5982fd16 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.
2020-07-17 16:16:49 -07:00

150 lines
5.2 KiB
Rust

//! Interfacing with actual instructions.
use crate::part::{Constant, Part};
use crate::paths::Path;
use crate::r#type::Type;
use std::fmt::Debug;
use std::hash::Hash;
use std::num::NonZeroU32;
/// A trait for interfacing with actual instruction sequences.
///
/// This trait enables both:
///
/// * `peepmatic-runtime` to be used by `cranelift-codegen` without a circular
/// dependency from `peepmatic-runtime` to `cranelift-codegen` to get access
/// to Cranelift's IR types, and
///
/// * enables us to write local tests that exercise peephole optimizers on a
/// simple, testing-only instruction set without pulling in all of Cranelift.
///
/// Finally, this should also make the task of adding support for Cranelift's
/// new `MachInst` and vcode backend easier, since all that needs to be done is
/// "just" implementing this trait. (And probably add/modify some
/// `peepmatic_runtime::operation::Operation`s as well).
///
/// ## Safety
///
/// See doc comment for `instruction_result_bit_width`.
pub unsafe trait InstructionSet<'a> {
/// Mutable context passed into all trait methods. Can be whatever you want!
///
/// In practice, this is a `FuncCursor` for `cranelift-codegen`'s trait
/// implementation.
type Context;
/// An operator.
type Operator: 'static + Copy + Debug + Eq + Hash + Into<NonZeroU32>;
/// An instruction (or identifier for an instruction).
type Instruction: Copy + Debug + Eq;
/// Replace the `old` instruction with `new`.
///
/// `new` is either a `Part::Instruction` or a constant `Part::Boolean` or
/// `Part::Integer`. In the former case, it can directly replace `old`. In
/// the latter case, implementations of this trait should transparently
/// create an `iconst` or `bconst` instruction to wrap the given constant.
///
/// `new` will never be `Part::ConditionCode`.
fn replace_instruction(
&self,
context: &mut Self::Context,
old: Self::Instruction,
new: Part<Self::Instruction>,
) -> Self::Instruction;
/// Get the instruction, constant, or condition code at the given path.
///
/// If there is no such entity at the given path (e.g. we run into a
/// function parameter and can't traverse the path any further) then `None`
/// should be returned.
fn get_part_at_path(
&self,
context: &mut Self::Context,
root: Self::Instruction,
path: Path,
) -> Option<Part<Self::Instruction>>;
/// Get the given instruction's operator.
///
/// If the instruction isn't supported, then `None` should be returned.
fn operator(
&self,
context: &mut Self::Context,
instr: Self::Instruction,
) -> Option<Self::Operator>;
/// Make a unary instruction.
///
/// If the type is not given, then it should be inferred.
fn make_inst_1(
&self,
context: &mut Self::Context,
root: Self::Instruction,
operator: Self::Operator,
r#type: Type,
a: Part<Self::Instruction>,
) -> Self::Instruction;
/// Make a binary instruction.
///
/// Operands are given as immediates first and arguments following
/// them. Condition codes are treated as immediates. So if we are creating
/// an `iadd_imm` instruction, then `a` will be the constant integer
/// immediate and `b` will be the instruction whose result is the dynamic
/// argument.
fn make_inst_2(
&self,
context: &mut Self::Context,
root: Self::Instruction,
operator: Self::Operator,
r#type: Type,
a: Part<Self::Instruction>,
b: Part<Self::Instruction>,
) -> Self::Instruction;
/// Make a ternary instruction.
///
/// Operands are given as immediates first and arguments following
/// them. Condition codes are treated as immediates. So if we are creating
/// an `icmp` instruction, then `a` will be the condition code, and `b` and
/// `c` will be instructions whose results are the dynamic arguments.
fn make_inst_3(
&self,
context: &mut Self::Context,
root: Self::Instruction,
operator: Self::Operator,
r#type: Type,
a: Part<Self::Instruction>,
b: Part<Self::Instruction>,
c: Part<Self::Instruction>,
) -> Self::Instruction;
/// Try to resolve the given instruction into a constant value.
///
/// If we can tell that the instruction returns a constant value, then
/// return that constant value as either a `Part::Boolean` or
/// `Part::Integer`. Otherwise, return `None`.
fn instruction_to_constant(
&self,
context: &mut Self::Context,
inst: Self::Instruction,
) -> Option<Constant>;
/// Get the bit width of the given instruction's result.
///
/// ## Safety
///
/// There is code that makes memory-safety assumptions that the result is
/// always one of 1, 8, 16, 32, 64, or 128. Implementors must uphold this.
fn instruction_result_bit_width(
&self,
context: &mut Self::Context,
inst: Self::Instruction,
) -> u8;
/// Get the size of a native word in bits.
fn native_word_size_in_bits(&self, context: &mut Self::Context) -> u8;
}