diff --git a/rust2/hanoi.bf b/rust2/benches/hanoi.bf similarity index 100% rename from rust2/hanoi.bf rename to rust2/benches/hanoi.bf diff --git a/rust2/benches/opts.rs b/rust2/benches/opts.rs index 97e3fa2..6f487ef 100644 --- a/rust2/benches/opts.rs +++ b/rust2/benches/opts.rs @@ -35,12 +35,14 @@ fn optimized(c: &mut Criterion) { let loopremove = include_str!("loopremove.bf"); let twinkle = include_str!("twinkle.bf"); let bottles = include_str!("bottles.bf"); + let hanoi = include_str!("hanoi.bf"); c.bench_function("fizzbuzz", |b| b.iter(|| run_bf(black_box(fizzbuzz)))); c.bench_function("bench", |b| b.iter(|| run_bf(black_box(bench)))); c.bench_function("loopremove", |b| b.iter(|| run_bf(black_box(loopremove)))); c.bench_function("twinkle", |b| b.iter(|| run_bf(black_box(twinkle)))); c.bench_function("bottles", |b| b.iter(|| run_bf(black_box(bottles)))); + c.bench_function("hanoi", |b| b.iter(|| run_bf(black_box(hanoi)))); } criterion_group!(benches, optimized); diff --git a/rust2/src/codegen.rs b/rust2/src/codegen.rs index 9be18e7..68fbbf6 100644 --- a/rust2/src/codegen.rs +++ b/rust2/src/codegen.rs @@ -25,16 +25,18 @@ use bumpalo::Bump; pub enum Stmt { Add(u8), Sub(u8), - Right(usize), - Left(usize), + Right(u32), + Left(u32), Out, In, SetNull, - JmpIfZero(usize), - JmpIfNonZero(usize), + JmpIfZero(u32), + JmpIfNonZero(u32), End, } +const _: [(); 8] = [(); std::mem::size_of::()]; + #[derive(Debug, Clone)] pub struct Code<'c> { stmts: Vec, @@ -76,8 +78,8 @@ 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::Right(n) => Stmt::Right(*n), - StmtKind::Left(n) => Stmt::Left(*n), + StmtKind::Right(n) => Stmt::Right(u32::try_from(*n).unwrap()), + StmtKind::Left(n) => Stmt::Left(u32::try_from(*n).unwrap()), StmtKind::Out => Stmt::Out, StmtKind::In => Stmt::In, StmtKind::SetNull => Stmt::SetNull, @@ -90,14 +92,15 @@ fn ir_to_stmt<'c>(code: &mut Code<'c>, ir_stmt: &IrStmt<'_>) { generate_stmts(code, &instr.stmts); // if the loop body is empty, we jmp to ourselves, which is an infinite loop - as expected let first_loop_body_idx = skip_jmp_idx + 1; - code.stmts.push(Stmt::JmpIfNonZero(first_loop_body_idx)); + code.stmts + .push(Stmt::JmpIfNonZero(first_loop_body_idx.try_into().unwrap())); code.debug.push(ir_stmt.span); // there will always at least be an `End` instruction after the loop let after_loop_idx = code.stmts.len(); // fix the placeholder with the actual index - code.stmts[skip_jmp_idx] = Stmt::JmpIfZero(after_loop_idx); + code.stmts[skip_jmp_idx] = Stmt::JmpIfZero(after_loop_idx.try_into().unwrap()); return; } diff --git a/rust2/src/codegen_interpreter.rs b/rust2/src/codegen_interpreter.rs index 10cfa15..c44bc99 100644 --- a/rust2/src/codegen_interpreter.rs +++ b/rust2/src/codegen_interpreter.rs @@ -2,15 +2,15 @@ use crate::codegen::{Code, Stmt}; use std::io::{Read, Write}; use std::num::Wrapping; -const MEM_SIZE: usize = 32_000; +const MEM_SIZE: u32 = 32_000; -type Memory = [Wrapping; MEM_SIZE]; +type Memory = [Wrapping; MEM_SIZE as usize]; // TODO maybe repr(C) to prevent field reordering? struct Interpreter<'c, W, R> { code: &'c Code<'c>, - ip: usize, - ptr: usize, + ip: u32, + ptr: u32, stdout: W, stdin: R, mem: Memory, @@ -27,7 +27,7 @@ where ptr: 0, stdout, stdin, - mem: [Wrapping(0u8); MEM_SIZE], + mem: [Wrapping(0u8); MEM_SIZE as usize], }; // SAFETY: `Code` can only be produced by the `crate::codegen` module, which is trusted to not @@ -44,8 +44,8 @@ impl<'c, W: Write, R: Read> Interpreter<'c, W, R> { // SAFETY: If the code ends with an `End` and there are no out of bounds jumps, // `self.ip` will never be out of bounds // Removing this bounds check speeds up execution by about 40% - debug_assert!(self.ip < stmts.len()); - let instr = unsafe { *stmts.get_unchecked(self.ip) }; + debug_assert!((self.ip as usize) < stmts.len()); + let instr = unsafe { *stmts.get_unchecked(self.ip as usize) }; self.ip += 1; match instr { Stmt::Add(n) => { @@ -97,10 +97,10 @@ impl<'c, W: Write, R: Read> Interpreter<'c, W, R> { } fn elem_mut(&mut self) -> &mut Wrapping { - &mut self.mem[self.ptr] + &mut self.mem[self.ptr as usize] } fn elem(&self) -> u8 { - self.mem[self.ptr].0 + self.mem[self.ptr as usize].0 } }