add pass_move_add_to

This commit is contained in:
nora 2022-04-16 14:35:56 +02:00
parent 014770b6fe
commit 93f97e9a08
4 changed files with 95 additions and 25 deletions

View file

@ -27,8 +27,9 @@ use std::fmt::{Debug, Formatter};
pub enum Stmt {
Add(u8),
Sub(u8),
AddOffset(i32, u8),
SubOffset(i32, u8),
AddOffset { offset: i32, n: u8 },
SubOffset { offset: i32, n: u8 },
MoveAddTo { offset: i32 },
Right(u32),
Left(u32),
Out,
@ -88,8 +89,15 @@ fn ir_to_stmt<'c>(code: &mut Code<'c>, ir_stmt: &IrStmt<'_>) {
let stmt = match &ir_stmt.kind {
StmtKind::Add(n) => Stmt::Add(*n),
StmtKind::Sub(n) => Stmt::Sub(*n),
StmtKind::AddOffset(o, n) => Stmt::AddOffset(*o, *n),
StmtKind::SubOffset(o, n) => Stmt::SubOffset(*o, *n),
StmtKind::AddOffset { offset, n } => Stmt::AddOffset {
offset: *offset,
n: *n,
},
StmtKind::SubOffset { offset, n } => Stmt::SubOffset {
offset: *offset,
n: *n,
},
StmtKind::MoveAddTo { offset } => Stmt::MoveAddTo { offset: *offset },
StmtKind::Right(n) => Stmt::Right(u32::try_from(*n).unwrap()),
StmtKind::Left(n) => Stmt::Left(u32::try_from(*n).unwrap()),
StmtKind::Out => Stmt::Out,

View file

@ -62,16 +62,13 @@ where
Stmt::Sub(n) => {
*self.elem_mut() -= n;
}
Stmt::AddOffset(o, n) => unsafe {
*self
.mem
.get_unchecked_mut((self.ptr as isize + (o as isize)) as usize) += n;
},
Stmt::SubOffset(o, n) => unsafe {
*self
.mem
.get_unchecked_mut((self.ptr as isize + (o as isize)) as usize) -= n;
},
Stmt::AddOffset { offset, n } => *self.elem_mut_offset(offset) += n,
Stmt::SubOffset { offset, n } => *self.elem_mut_offset(offset) -= n,
Stmt::MoveAddTo { offset } => {
let value = self.elem();
*self.elem_mut() = Wrapping(0);
*self.elem_mut_offset(offset) += value;
}
Stmt::Right(n) => {
self.ptr += n as usize;
if self.ptr >= MEM_SIZE {
@ -116,15 +113,24 @@ where
(self.profile_collector)(self.ip);
}
}
fn elem_mut_offset(&mut self, offset: i32) -> &mut Wrapping<u8> {
let ptr = self.ptr as isize;
let offset = offset as isize;
// SAFETY: `self.ptr` is never out of bounds
debug_assert!(self.ptr < self.mem.len());
unsafe { self.mem.get_unchecked_mut((ptr + offset) as usize) }
}
fn elem_mut(&mut self) -> &mut Wrapping<u8> {
// SAFETY: `self.ptr` is never out of bounds
//debug_assert!(self.ptr < self.mem.len());
debug_assert!(self.ptr < self.mem.len());
unsafe { self.mem.get_unchecked_mut(self.ptr) }
}
fn elem(&self) -> u8 {
// SAFETY: `self.ptr` is never out of bounds
//debug_assert!(self.ptr < self.mem.len());
debug_assert!(self.ptr < self.mem.len());
unsafe { self.mem.get_unchecked(self.ptr).0 }
}
}

View file

@ -40,10 +40,20 @@ impl Debug for Stmt<'_> {
#[derive(Debug, Clone)]
pub enum StmtKind<'ir> {
Add(u8),
Sub(u8),
AddOffset(i32, u8),
SubOffset(i32, u8),
Add(u8), // todo: we probably want to remove this
Sub(u8), // todo: we probably want to remove this
AddOffset {
offset: i32,
n: u8,
},
SubOffset {
offset: i32,
n: u8,
},
/// Sets the current cell to 0 and adds that value of the cell to another cell at `offset`
MoveAddTo {
offset: i32,
},
Right(usize),
Left(usize),
Loop(Ir<'ir>),
@ -59,6 +69,7 @@ pub fn optimize<'ir>(alloc: &'ir Bump, instrs: &[(Instr<'_>, Span)]) -> Ir<'ir>
pass_set_n(&mut ir);
pass_cancel_left_right_add_sub(&mut ir);
pass_add_sub_offset(&mut ir);
pass_move_add_to(&mut ir);
ir
}
@ -219,22 +230,67 @@ fn pass_add_sub_offset(ir: &mut Ir<'_>) {
window_pass(ir, pass_add_sub_offset, |[a, b, c]| {
match (a.kind(), b.kind(), c.kind()) {
(StmtKind::Right(r), StmtKind::Add(n), StmtKind::Left(l)) if r == l => {
WindowPassAction::Merge(StmtKind::AddOffset(i32::try_from(*r).unwrap(), *n))
WindowPassAction::Merge(StmtKind::AddOffset {
offset: i32::try_from(*r).unwrap(),
n: *n,
})
}
(StmtKind::Left(l), StmtKind::Add(n), StmtKind::Right(r)) if r == l => {
WindowPassAction::Merge(StmtKind::AddOffset(-i32::try_from(*r).unwrap(), *n))
WindowPassAction::Merge(StmtKind::AddOffset {
offset: -i32::try_from(*r).unwrap(),
n: *n,
})
}
(StmtKind::Right(r), StmtKind::Sub(n), StmtKind::Left(l)) if r == l => {
WindowPassAction::Merge(StmtKind::SubOffset(i32::try_from(*r).unwrap(), *n))
WindowPassAction::Merge(StmtKind::SubOffset {
offset: i32::try_from(*r).unwrap(),
n: *n,
})
}
(StmtKind::Left(l), StmtKind::Sub(n), StmtKind::Right(r)) if r == l => {
WindowPassAction::Merge(StmtKind::SubOffset(-i32::try_from(*r).unwrap(), *n))
WindowPassAction::Merge(StmtKind::SubOffset {
offset: -i32::try_from(*r).unwrap(),
n: *n,
})
}
_ => WindowPassAction::None,
}
})
}
/// pass that replaces `Loop([Sub(1) AddOffset(o, 1)])` with `MoveAddTo(o)`
#[tracing::instrument]
fn pass_move_add_to(ir: &mut Ir<'_>) {
for stmt in &mut ir.stmts {
if let Stmt {
kind: StmtKind::Loop(body),
span,
} = stmt
{
if let [Stmt {
kind: StmtKind::Sub(1),
..
}, Stmt {
kind: StmtKind::AddOffset { offset, n: 1 },
..
}]
| [Stmt {
kind: StmtKind::AddOffset { offset, n: 1 },
..
}, Stmt {
kind: StmtKind::Sub(1),
..
}] = body.stmts.as_slice()
{
trace!(?span, ?offset, "Replacing Statement with MoveAddTo");
*stmt = Stmt::new(StmtKind::MoveAddTo { offset: *offset }, *span);
} else {
pass_move_add_to(body);
}
}
}
}
enum WindowPassAction<'ir> {
None,
Merge(StmtKind<'ir>),

View file

@ -1 +1 @@
<<<<->>>>
[->>>>>>>>>+<<<<<<<<<]