peepmatic: Do not use paths in linear IR
Rather than using paths from the root instruction to the instruction we are matching against or checking if it is constant or whatever, use temporary variables. When we successfully match an instruction's opcode, we simultaneously define these temporaries for the instruction's operands. This is similar to how open-coding these matches in Rust would use `match` expressions with pattern matching to bind the operands to variables at the same time. This saves about 1.8% of instructions retired when Peepmatic is enabled.
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
|
||||
use crate::cc::ConditionCode;
|
||||
use crate::integer_interner::{IntegerId, IntegerInterner};
|
||||
use crate::paths::{PathId, PathInterner};
|
||||
use crate::r#type::{BitWidth, Type};
|
||||
use crate::unquote::UnquoteOperator;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -24,9 +23,6 @@ where
|
||||
/// The linear optimizations.
|
||||
pub optimizations: Vec<Optimization<TOperator>>,
|
||||
|
||||
/// The de-duplicated paths referenced by these optimizations.
|
||||
pub paths: PathInterner,
|
||||
|
||||
/// The integer literals referenced by these optimizations.
|
||||
pub integers: IntegerInterner,
|
||||
}
|
||||
@@ -87,79 +83,54 @@ pub struct Match {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum MatchOp {
|
||||
/// Switch on the opcode of an instruction.
|
||||
Opcode {
|
||||
/// The path to the instruction whose opcode we're switching on.
|
||||
path: PathId,
|
||||
},
|
||||
///
|
||||
/// Upon successfully matching an instruction's opcode, bind each of its
|
||||
/// operands to a LHS temporary.
|
||||
Opcode(LhsId),
|
||||
|
||||
/// Does an instruction have a constant value?
|
||||
IsConst {
|
||||
/// The path to the instruction (or immediate) that we're checking
|
||||
/// whether it is constant or not.
|
||||
path: PathId,
|
||||
},
|
||||
IsConst(LhsId),
|
||||
|
||||
/// Is the constant value a power of two?
|
||||
IsPowerOfTwo {
|
||||
/// The path to the instruction (or immediate) that we are checking
|
||||
/// whether it is a constant power of two or not.
|
||||
path: PathId,
|
||||
},
|
||||
IsPowerOfTwo(LhsId),
|
||||
|
||||
/// Switch on the bit width of a value.
|
||||
BitWidth {
|
||||
/// The path to the instruction (or immediate) whose result's bit width
|
||||
/// we are checking.
|
||||
path: PathId,
|
||||
},
|
||||
BitWidth(LhsId),
|
||||
|
||||
/// Does the value fit in our target architecture's native word size?
|
||||
FitsInNativeWord {
|
||||
/// The path to the instruction (or immediate) whose result we are
|
||||
/// checking whether it fits in a native word or not.
|
||||
path: PathId,
|
||||
},
|
||||
FitsInNativeWord(LhsId),
|
||||
|
||||
/// Are the instructions (or immediates) at the given paths the same?
|
||||
Eq {
|
||||
/// The path to the first instruction (or immediate).
|
||||
path_a: PathId,
|
||||
/// The path to the second instruction (or immediate).
|
||||
path_b: PathId,
|
||||
},
|
||||
/// Are the instructions (or immediates) the same?
|
||||
Eq(LhsId, LhsId),
|
||||
|
||||
/// Switch on the constant integer value of an instruction.
|
||||
IntegerValue {
|
||||
/// The path to the instruction.
|
||||
path: PathId,
|
||||
},
|
||||
IntegerValue(LhsId),
|
||||
|
||||
/// Switch on the constant boolean value of an instruction.
|
||||
BooleanValue {
|
||||
/// The path to the instruction.
|
||||
path: PathId,
|
||||
},
|
||||
BooleanValue(LhsId),
|
||||
|
||||
/// Switch on a condition code.
|
||||
ConditionCode {
|
||||
/// The path to the condition code.
|
||||
path: PathId,
|
||||
},
|
||||
ConditionCode(LhsId),
|
||||
|
||||
/// No operation. Always evaluates to `None`.
|
||||
/// No operation. Always evaluates to `Else`.
|
||||
///
|
||||
/// Exceedingly rare in real optimizations; nonetheless required to support
|
||||
/// Never appears in real optimizations; nonetheless required to support
|
||||
/// corner cases of the DSL, such as a LHS pattern that is nothing but a
|
||||
/// variable pattern.
|
||||
/// variable.
|
||||
Nop,
|
||||
}
|
||||
|
||||
/// A canonicalized identifier for a left-hand side value that was bound in a
|
||||
/// pattern.
|
||||
///
|
||||
/// These are defined in a pre-order traversal of the LHS pattern by successful
|
||||
/// `MatchOp::Opcode` matches.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct LhsId(pub u16);
|
||||
|
||||
/// A canonicalized identifier for a right-hand side value.
|
||||
///
|
||||
/// These are defined by RHS actions.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct RhsId(pub u16);
|
||||
|
||||
@@ -171,8 +142,8 @@ pub struct RhsId(pub u16);
|
||||
pub enum Action<TOperator> {
|
||||
/// Reuse something from the left-hand side.
|
||||
GetLhs {
|
||||
/// The path to the instruction or value.
|
||||
path: PathId,
|
||||
/// The left-hand side instruction or value.
|
||||
lhs: LhsId,
|
||||
},
|
||||
|
||||
/// Perform compile-time evaluation.
|
||||
|
||||
Reference in New Issue
Block a user