mirror of
https://github.com/RustPython/Parser.git
synced 2025-07-21 20:15:26 +00:00
Add optimization to remove unused LoadConst operations
This commit is contained in:
parent
65c98069db
commit
e5f6d11a12
2 changed files with 125 additions and 97 deletions
112
src/peephole.rs
112
src/peephole.rs
|
@ -1,6 +1,8 @@
|
||||||
use crate::output_stream::OutputStream;
|
use crate::output_stream::OutputStream;
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use rustpython_bytecode::bytecode::{self, CodeObject, Instruction, Label, Location};
|
use rustpython_bytecode::bytecode::{CodeObject, Instruction, Label, Location};
|
||||||
|
|
||||||
|
pub mod optimizations;
|
||||||
|
|
||||||
const PEEPHOLE_BUFFER_SIZE: usize = 20;
|
const PEEPHOLE_BUFFER_SIZE: usize = 20;
|
||||||
|
|
||||||
|
@ -47,6 +49,13 @@ impl<O: OutputStream> From<PeepholeOptimizer<O>> for CodeObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! apply_optimizations {
|
||||||
|
($buf:expr, $($opt:ident),*$(,)?) => {{
|
||||||
|
$($crate::peephole::optimizations::$opt($buf);)*
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
impl<O: OutputStream> PeepholeOptimizer<O> {
|
impl<O: OutputStream> PeepholeOptimizer<O> {
|
||||||
pub fn new(inner: O) -> Self {
|
pub fn new(inner: O) -> Self {
|
||||||
PeepholeOptimizer {
|
PeepholeOptimizer {
|
||||||
|
@ -81,6 +90,10 @@ impl<O: OutputStream> PeepholeOptimizer<O> {
|
||||||
Self::inner_emit(&mut self.inner, instruction, meta);
|
Self::inner_emit(&mut self.inner, instruction, meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn optimize(&mut self) {
|
||||||
|
apply_optimizations!(self, operator, unpack, useless_const);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<O> OutputStream for PeepholeOptimizer<O>
|
impl<O> OutputStream for PeepholeOptimizer<O>
|
||||||
|
@ -89,7 +102,7 @@ where
|
||||||
{
|
{
|
||||||
fn emit(&mut self, instruction: Instruction, loc: Location) {
|
fn emit(&mut self, instruction: Instruction, loc: Location) {
|
||||||
self.push(instruction, loc.into());
|
self.push(instruction, loc.into());
|
||||||
optimize(self);
|
self.optimize();
|
||||||
}
|
}
|
||||||
fn set_label(&mut self, label: Label) {
|
fn set_label(&mut self, label: Label) {
|
||||||
if let Some(instr) = self.buffer.last_mut() {
|
if let Some(instr) = self.buffer.last_mut() {
|
||||||
|
@ -116,98 +129,3 @@ pub trait OptimizationBuffer {
|
||||||
fn emit(&mut self, instruction: Instruction, meta: InstructionMetadata);
|
fn emit(&mut self, instruction: Instruction, meta: InstructionMetadata);
|
||||||
fn pop(&mut self) -> (Instruction, InstructionMetadata);
|
fn pop(&mut self) -> (Instruction, InstructionMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! lc {
|
|
||||||
($name:ident {$($field:tt)*}) => {
|
|
||||||
Instruction::LoadConst {
|
|
||||||
value: bytecode::Constant::$name {$($field)*},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
($name:ident, $($value:tt)*) => {
|
|
||||||
lc!($name { value: $($value)* })
|
|
||||||
};
|
|
||||||
}
|
|
||||||
macro_rules! emitconst {
|
|
||||||
($buf:expr, [$($metas:expr),*], $($arg:tt)*) => {
|
|
||||||
$buf.emit(
|
|
||||||
lc!($($arg)*),
|
|
||||||
InstructionMetadata::from(vec![$($metas),*]),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn optimize(buf: &mut impl OptimizationBuffer) {
|
|
||||||
optimize_operator(buf);
|
|
||||||
optimize_unpack(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn optimize_operator(buf: &mut impl OptimizationBuffer) {
|
|
||||||
let (instruction, meta) = buf.pop();
|
|
||||||
if let Instruction::BinaryOperation { op, inplace } = instruction {
|
|
||||||
let (rhs, rhs_meta) = buf.pop();
|
|
||||||
let (lhs, lhs_meta) = buf.pop();
|
|
||||||
macro_rules! op {
|
|
||||||
($op:ident) => {
|
|
||||||
bytecode::BinaryOperator::$op
|
|
||||||
};
|
|
||||||
}
|
|
||||||
match (op, lhs, rhs) {
|
|
||||||
(op!(Add), lc!(Integer, lhs), lc!(Integer, rhs)) => {
|
|
||||||
emitconst!(buf, [lhs_meta, rhs_meta], Integer, lhs + rhs)
|
|
||||||
}
|
|
||||||
(op!(Subtract), lc!(Integer, lhs), lc!(Integer, rhs)) => {
|
|
||||||
emitconst!(buf, [lhs_meta, rhs_meta], Integer, lhs - rhs)
|
|
||||||
}
|
|
||||||
(op!(Add), lc!(Float, lhs), lc!(Float, rhs)) => {
|
|
||||||
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs + rhs)
|
|
||||||
}
|
|
||||||
(op!(Subtract), lc!(Float, lhs), lc!(Float, rhs)) => {
|
|
||||||
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs - rhs)
|
|
||||||
}
|
|
||||||
(op!(Multiply), lc!(Float, lhs), lc!(Float, rhs)) => {
|
|
||||||
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs * rhs)
|
|
||||||
}
|
|
||||||
(op!(Divide), lc!(Float, lhs), lc!(Float, rhs)) => {
|
|
||||||
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs / rhs)
|
|
||||||
}
|
|
||||||
(op!(Power), lc!(Float, lhs), lc!(Float, rhs)) => {
|
|
||||||
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs.powf(rhs))
|
|
||||||
}
|
|
||||||
(op!(Add), lc!(String, mut lhs), lc!(String, rhs)) => {
|
|
||||||
lhs.push_str(&rhs);
|
|
||||||
emitconst!(buf, [lhs_meta, rhs_meta], String, lhs);
|
|
||||||
}
|
|
||||||
(op, lhs, rhs) => {
|
|
||||||
buf.emit(lhs, lhs_meta);
|
|
||||||
buf.emit(rhs, rhs_meta);
|
|
||||||
buf.emit(Instruction::BinaryOperation { op, inplace }, meta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
buf.emit(instruction, meta)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn optimize_unpack(buf: &mut impl OptimizationBuffer) {
|
|
||||||
let (instruction, meta) = buf.pop();
|
|
||||||
if let Instruction::UnpackSequence { size } = instruction {
|
|
||||||
let (arg, arg_meta) = buf.pop();
|
|
||||||
match arg {
|
|
||||||
Instruction::BuildTuple {
|
|
||||||
size: tup_size,
|
|
||||||
unpack,
|
|
||||||
} if !unpack && tup_size == size => {
|
|
||||||
buf.emit(
|
|
||||||
Instruction::Reverse { amount: size },
|
|
||||||
vec![arg_meta, meta].into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
arg => {
|
|
||||||
buf.emit(arg, arg_meta);
|
|
||||||
buf.emit(instruction, meta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
buf.emit(instruction, meta)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
110
src/peephole/optimizations.rs
Normal file
110
src/peephole/optimizations.rs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
use rustpython_bytecode::bytecode::{self, Instruction};
|
||||||
|
|
||||||
|
use super::{InstructionMetadata, OptimizationBuffer};
|
||||||
|
|
||||||
|
macro_rules! lc {
|
||||||
|
($name:ident {$($field:tt)*}) => {
|
||||||
|
Instruction::LoadConst {
|
||||||
|
value: bytecode::Constant::$name {$($field)*},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($name:ident, $($value:tt)*) => {
|
||||||
|
lc!($name { value: $($value)* })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! emitconst {
|
||||||
|
($buf:expr, [$($metas:expr),*], $($arg:tt)*) => {
|
||||||
|
$buf.emit(
|
||||||
|
lc!($($arg)*),
|
||||||
|
InstructionMetadata::from(vec![$($metas),*]),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn operator(buf: &mut impl OptimizationBuffer) {
|
||||||
|
let (instruction, meta) = buf.pop();
|
||||||
|
if let Instruction::BinaryOperation { op, inplace } = instruction {
|
||||||
|
let (rhs, rhs_meta) = buf.pop();
|
||||||
|
let (lhs, lhs_meta) = buf.pop();
|
||||||
|
macro_rules! op {
|
||||||
|
($op:ident) => {
|
||||||
|
bytecode::BinaryOperator::$op
|
||||||
|
};
|
||||||
|
}
|
||||||
|
match (op, lhs, rhs) {
|
||||||
|
(op!(Add), lc!(Integer, lhs), lc!(Integer, rhs)) => {
|
||||||
|
emitconst!(buf, [lhs_meta, rhs_meta], Integer, lhs + rhs)
|
||||||
|
}
|
||||||
|
(op!(Subtract), lc!(Integer, lhs), lc!(Integer, rhs)) => {
|
||||||
|
emitconst!(buf, [lhs_meta, rhs_meta], Integer, lhs - rhs)
|
||||||
|
}
|
||||||
|
(op!(Add), lc!(Float, lhs), lc!(Float, rhs)) => {
|
||||||
|
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs + rhs)
|
||||||
|
}
|
||||||
|
(op!(Subtract), lc!(Float, lhs), lc!(Float, rhs)) => {
|
||||||
|
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs - rhs)
|
||||||
|
}
|
||||||
|
(op!(Multiply), lc!(Float, lhs), lc!(Float, rhs)) => {
|
||||||
|
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs * rhs)
|
||||||
|
}
|
||||||
|
(op!(Divide), lc!(Float, lhs), lc!(Float, rhs)) => {
|
||||||
|
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs / rhs)
|
||||||
|
}
|
||||||
|
(op!(Power), lc!(Float, lhs), lc!(Float, rhs)) => {
|
||||||
|
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs.powf(rhs))
|
||||||
|
}
|
||||||
|
(op!(Add), lc!(String, mut lhs), lc!(String, rhs)) => {
|
||||||
|
lhs.push_str(&rhs);
|
||||||
|
emitconst!(buf, [lhs_meta, rhs_meta], String, lhs);
|
||||||
|
}
|
||||||
|
(op, lhs, rhs) => {
|
||||||
|
buf.emit(lhs, lhs_meta);
|
||||||
|
buf.emit(rhs, rhs_meta);
|
||||||
|
buf.emit(Instruction::BinaryOperation { op, inplace }, meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf.emit(instruction, meta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unpack(buf: &mut impl OptimizationBuffer) {
|
||||||
|
let (instruction, meta) = buf.pop();
|
||||||
|
if let Instruction::UnpackSequence { size } = instruction {
|
||||||
|
let (arg, arg_meta) = buf.pop();
|
||||||
|
match arg {
|
||||||
|
Instruction::BuildTuple {
|
||||||
|
size: tup_size,
|
||||||
|
unpack,
|
||||||
|
} if !unpack && tup_size == size => {
|
||||||
|
buf.emit(
|
||||||
|
Instruction::Reverse { amount: size },
|
||||||
|
vec![arg_meta, meta].into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
arg => {
|
||||||
|
buf.emit(arg, arg_meta);
|
||||||
|
buf.emit(instruction, meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf.emit(instruction, meta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn useless_const(buf: &mut impl OptimizationBuffer) {
|
||||||
|
let (instruction, meta) = buf.pop();
|
||||||
|
if instruction == Instruction::Pop {
|
||||||
|
let (arg, arg_meta) = buf.pop();
|
||||||
|
if let Instruction::LoadConst { .. } = arg {
|
||||||
|
// just ignore it all
|
||||||
|
drop(arg);
|
||||||
|
drop(instruction);
|
||||||
|
} else {
|
||||||
|
buf.emit(arg, arg_meta);
|
||||||
|
buf.emit(instruction, meta);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf.emit(instruction, meta);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue