diff --git a/rust2/src/codegen.rs b/rust2/src/codegen.rs index 6157673..0ac0653 100644 --- a/rust2/src/codegen.rs +++ b/rust2/src/codegen.rs @@ -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, diff --git a/rust2/src/codegen_interpreter.rs b/rust2/src/codegen_interpreter.rs index 0e5941e..a7f2f6e 100644 --- a/rust2/src/codegen_interpreter.rs +++ b/rust2/src/codegen_interpreter.rs @@ -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 { + 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 { // 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 } } } diff --git a/rust2/src/opts.rs b/rust2/src/opts.rs index 6bb58d8..1e42893 100644 --- a/rust2/src/opts.rs +++ b/rust2/src/opts.rs @@ -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>), diff --git a/rust2/test.bf b/rust2/test.bf index 0f7a16a..7ad68db 100644 --- a/rust2/test.bf +++ b/rust2/test.bf @@ -1 +1 @@ -<<<<->>>> \ No newline at end of file +[->>>>>>>>>+<<<<<<<<<] \ No newline at end of file