Fix label issue

This commit is contained in:
coolreader18 2019-08-03 23:30:14 -05:00
parent a01853fad5
commit 347d6c006a
2 changed files with 73 additions and 34 deletions

View file

@ -8,6 +8,6 @@ extern crate log;
pub mod compile; pub mod compile;
pub mod error; pub mod error;
pub mod symboltable;
pub mod output_stream; pub mod output_stream;
pub mod peephole; pub mod peephole;
pub mod symboltable;

View file

@ -1,12 +1,31 @@
use crate::compile::Label;
use crate::output_stream::OutputStream; use crate::output_stream::OutputStream;
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use rustpython_bytecode::bytecode::{self, CodeObject, Instruction, Location}; use rustpython_bytecode::bytecode::{self, CodeObject, Instruction, Location};
const PEEPHOLE_BUFFER_SIZE: usize = 10; const PEEPHOLE_BUFFER_SIZE: usize = 20;
struct InstructionMetadata {
loc: Location,
labels: Vec<Label>,
}
impl InstructionMetadata {
fn from_multiple(metas: Vec<Self>) -> Self {
debug_assert!(!metas.is_empty(), "`metas` must not be empty");
InstructionMetadata {
loc: metas[0].loc.clone(),
labels: metas
.into_iter()
.flat_map(|meta| meta.labels.into_iter())
.collect(),
}
}
}
pub struct PeepholeOptimizer<O: OutputStream> { pub struct PeepholeOptimizer<O: OutputStream> {
inner: O, inner: O,
buffer: ArrayVec<[(Instruction, Location); PEEPHOLE_BUFFER_SIZE]>, buffer: ArrayVec<[(Instruction, InstructionMetadata); PEEPHOLE_BUFFER_SIZE]>,
} }
impl<O: OutputStream> From<CodeObject> for PeepholeOptimizer<O> { impl<O: OutputStream> From<CodeObject> for PeepholeOptimizer<O> {
@ -29,25 +48,31 @@ impl<O: OutputStream> PeepholeOptimizer<O> {
} }
} }
fn emit(&mut self, instruction: Instruction, loc: Location) { fn inner_emit(inner: &mut O, instruction: Instruction, meta: InstructionMetadata) {
if self.buffer.is_full() { inner.emit(instruction, meta.loc);
let (instr, loc) = self.buffer.remove(0); for label in meta.labels {
self.inner.emit(instr, loc); inner.set_label(label);
assert_eq!(self.buffer.len(), PEEPHOLE_BUFFER_SIZE - 1)
} }
// safe because we just checked that: if full then remove one element from it
unsafe { self.buffer.push_unchecked((instruction, loc)) };
} }
fn pop(&mut self) -> (Instruction, Location) { fn emit(&mut self, instruction: Instruction, meta: InstructionMetadata) {
if self.buffer.is_full() {
let (instr, meta) = self.buffer.remove(0);
Self::inner_emit(&mut self.inner, instr, meta);
}
// safe because we just checked that: if full then remove one element from it
unsafe { self.buffer.push_unchecked((instruction, meta)) };
}
fn pop(&mut self) -> (Instruction, InstructionMetadata) {
self.buffer.pop().unwrap() self.buffer.pop().unwrap()
} }
fn optimize(&mut self, instruction: Instruction, loc: Location) { fn optimize(&mut self, instruction: Instruction, meta: InstructionMetadata) {
match instruction { match instruction {
Instruction::BinaryOperation { op, inplace } => { Instruction::BinaryOperation { op, inplace } => {
let (rhs, rhs_loc) = self.pop(); let (rhs, rhs_meta) = self.pop();
let (lhs, lhs_loc) = self.pop(); let (lhs, lhs_meta) = self.pop();
macro_rules! lc { macro_rules! lc {
($name:ident {$($field:tt)*}) => { ($name:ident {$($field:tt)*}) => {
Instruction::LoadConst { Instruction::LoadConst {
@ -59,8 +84,11 @@ impl<O: OutputStream> PeepholeOptimizer<O> {
}; };
} }
macro_rules! emitconst { macro_rules! emitconst {
($($arg:tt)*) => { ([$($metas:expr),*], $($arg:tt)*) => {
self.emit(lc!($($arg)*), lhs_loc) self.emit(
lc!($($arg)*),
InstructionMetadata::from_multiple(vec![$($metas),*]),
)
}; };
} }
macro_rules! op { macro_rules! op {
@ -70,40 +98,44 @@ impl<O: OutputStream> PeepholeOptimizer<O> {
} }
match (op, lhs, rhs) { match (op, lhs, rhs) {
(op!(Add), lc!(Integer, lhs), lc!(Integer, rhs)) => { (op!(Add), lc!(Integer, lhs), lc!(Integer, rhs)) => {
emitconst!(Integer, lhs + rhs) emitconst!([lhs_meta, rhs_meta], Integer, lhs + rhs)
} }
(op!(Subtract), lc!(Integer, lhs), lc!(Integer, rhs)) => { (op!(Subtract), lc!(Integer, lhs), lc!(Integer, rhs)) => {
emitconst!(Integer, lhs - rhs) emitconst!([lhs_meta, rhs_meta], Integer, lhs - rhs)
}
(op!(Add), lc!(Float, lhs), lc!(Float, rhs)) => {
emitconst!([lhs_meta, rhs_meta], Float, lhs + rhs)
} }
(op!(Add), lc!(Float, lhs), lc!(Float, rhs)) => emitconst!(Float, lhs + rhs),
(op!(Subtract), lc!(Float, lhs), lc!(Float, rhs)) => { (op!(Subtract), lc!(Float, lhs), lc!(Float, rhs)) => {
emitconst!(Float, lhs - rhs) emitconst!([lhs_meta, rhs_meta], Float, lhs - rhs)
} }
(op!(Multiply), lc!(Float, lhs), lc!(Float, rhs)) => { (op!(Multiply), lc!(Float, lhs), lc!(Float, rhs)) => {
emitconst!(Float, lhs * rhs) emitconst!([lhs_meta, rhs_meta], Float, lhs * rhs)
}
(op!(Divide), lc!(Float, lhs), lc!(Float, rhs)) => {
emitconst!([lhs_meta, rhs_meta], Float, lhs / rhs)
} }
(op!(Divide), lc!(Float, lhs), lc!(Float, rhs)) => emitconst!(Float, lhs / rhs),
(op!(Power), lc!(Float, lhs), lc!(Float, rhs)) => { (op!(Power), lc!(Float, lhs), lc!(Float, rhs)) => {
emitconst!(Float, lhs.powf(rhs)) emitconst!([lhs_meta, rhs_meta], Float, lhs.powf(rhs))
} }
(op!(Add), lc!(String, mut lhs), lc!(String, rhs)) => { (op!(Add), lc!(String, mut lhs), lc!(String, rhs)) => {
lhs.push_str(&rhs); lhs.push_str(&rhs);
emitconst!(String, lhs); emitconst!([lhs_meta, rhs_meta], String, lhs);
} }
(op, lhs, rhs) => { (op, lhs, rhs) => {
self.emit(lhs, lhs_loc); self.emit(lhs, lhs_meta);
self.emit(rhs, rhs_loc); self.emit(rhs, rhs_meta);
self.emit(Instruction::BinaryOperation { op, inplace }, loc); self.emit(Instruction::BinaryOperation { op, inplace }, meta);
} }
} }
} }
other => self.emit(other, loc), other => self.emit(other, meta),
} }
} }
fn flush(&mut self) { fn flush(&mut self) {
for (instruction, location) in self.buffer.drain(..) { for (instruction, meta) in self.buffer.drain(..) {
self.inner.emit(instruction, location); Self::inner_emit(&mut self.inner, instruction, meta);
} }
} }
} }
@ -112,12 +144,19 @@ impl<O> OutputStream for PeepholeOptimizer<O>
where where
O: OutputStream, O: OutputStream,
{ {
fn emit(&mut self, instruction: Instruction, location: Location) { fn emit(&mut self, instruction: Instruction, loc: Location) {
self.optimize(instruction, location); self.optimize(
instruction,
InstructionMetadata {
loc,
labels: Vec::new(),
},
);
} }
fn set_label(&mut self, label: crate::compile::Label) { fn set_label(&mut self, label: crate::compile::Label) {
self.flush(); if let Some(instr) = self.buffer.last_mut() {
self.inner.set_label(label); instr.1.labels.push(label)
}
} }
fn mark_generator(&mut self) { fn mark_generator(&mut self) {
self.inner.mark_generator() self.inner.mark_generator()