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

@@ -407,7 +407,11 @@ fn gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter) {
All instructions from all supported ISAs are present.
"#,
);
fmt.line("#[repr(u16)]");
fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]");
fmt.line(
r#"#[cfg_attr(feature = "enable-peepmatic", derive(serde::Serialize, serde::Deserialize))]"#
);
// We explicitly set the discriminant of the first variant to 1, which allows us to take
// advantage of the NonZero optimization, meaning that wrapping enums can use the 0
@@ -589,6 +593,24 @@ fn gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter) {
fmt.empty_line();
}
fn gen_try_from(all_inst: &AllInstructions, fmt: &mut Formatter) {
fmt.line("impl core::convert::TryFrom<u16> for Opcode {");
fmt.indent(|fmt| {
fmt.line("type Error = ();");
fmt.line("#[inline]");
fmt.line("fn try_from(x: u16) -> Result<Self, ()> {");
fmt.indent(|fmt| {
fmtln!(fmt, "if 0 < x && x <= {} {{", all_inst.len());
fmt.indent(|fmt| fmt.line("Ok(unsafe { core::mem::transmute(x) })"));
fmt.line("} else {");
fmt.indent(|fmt| fmt.line("Err(())"));
fmt.line("}");
});
fmt.line("}");
});
fmt.line("}");
}
/// Get the value type constraint for an SSA value operand, where
/// `ctrl_typevar` is the controlling type variable.
///
@@ -1147,7 +1169,10 @@ pub(crate) fn generate(
gen_instruction_data_impl(&formats, &mut fmt);
fmt.empty_line();
gen_opcodes(all_inst, &mut fmt);
fmt.empty_line();
gen_type_constraints(all_inst, &mut fmt);
fmt.empty_line();
gen_try_from(all_inst, &mut fmt);
fmt.update_file(opcode_filename, out_dir)?;
// Instruction builder.