mirror of
https://github.com/Noratrieb/brainfuck.git
synced 2026-01-16 22:35:03 +01:00
make stmt a single word big
This commit is contained in:
parent
1e1a2a277b
commit
7dd2c82fa4
4 changed files with 22 additions and 17 deletions
|
|
@ -35,12 +35,14 @@ fn optimized(c: &mut Criterion) {
|
||||||
let loopremove = include_str!("loopremove.bf");
|
let loopremove = include_str!("loopremove.bf");
|
||||||
let twinkle = include_str!("twinkle.bf");
|
let twinkle = include_str!("twinkle.bf");
|
||||||
let bottles = include_str!("bottles.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("fizzbuzz", |b| b.iter(|| run_bf(black_box(fizzbuzz))));
|
||||||
c.bench_function("bench", |b| b.iter(|| run_bf(black_box(bench))));
|
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("loopremove", |b| b.iter(|| run_bf(black_box(loopremove))));
|
||||||
c.bench_function("twinkle", |b| b.iter(|| run_bf(black_box(twinkle))));
|
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("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);
|
criterion_group!(benches, optimized);
|
||||||
|
|
|
||||||
|
|
@ -25,16 +25,18 @@ use bumpalo::Bump;
|
||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
Add(u8),
|
Add(u8),
|
||||||
Sub(u8),
|
Sub(u8),
|
||||||
Right(usize),
|
Right(u32),
|
||||||
Left(usize),
|
Left(u32),
|
||||||
Out,
|
Out,
|
||||||
In,
|
In,
|
||||||
SetNull,
|
SetNull,
|
||||||
JmpIfZero(usize),
|
JmpIfZero(u32),
|
||||||
JmpIfNonZero(usize),
|
JmpIfNonZero(u32),
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _: [(); 8] = [(); std::mem::size_of::<Stmt>()];
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Code<'c> {
|
pub struct Code<'c> {
|
||||||
stmts: Vec<Stmt, &'c Bump>,
|
stmts: Vec<Stmt, &'c Bump>,
|
||||||
|
|
@ -76,8 +78,8 @@ fn ir_to_stmt<'c>(code: &mut Code<'c>, ir_stmt: &IrStmt<'_>) {
|
||||||
let stmt = match &ir_stmt.kind {
|
let stmt = match &ir_stmt.kind {
|
||||||
StmtKind::Add(n) => Stmt::Add(*n),
|
StmtKind::Add(n) => Stmt::Add(*n),
|
||||||
StmtKind::Sub(n) => Stmt::Sub(*n),
|
StmtKind::Sub(n) => Stmt::Sub(*n),
|
||||||
StmtKind::Right(n) => Stmt::Right(*n),
|
StmtKind::Right(n) => Stmt::Right(u32::try_from(*n).unwrap()),
|
||||||
StmtKind::Left(n) => Stmt::Left(*n),
|
StmtKind::Left(n) => Stmt::Left(u32::try_from(*n).unwrap()),
|
||||||
StmtKind::Out => Stmt::Out,
|
StmtKind::Out => Stmt::Out,
|
||||||
StmtKind::In => Stmt::In,
|
StmtKind::In => Stmt::In,
|
||||||
StmtKind::SetNull => Stmt::SetNull,
|
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);
|
generate_stmts(code, &instr.stmts);
|
||||||
// if the loop body is empty, we jmp to ourselves, which is an infinite loop - as expected
|
// 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;
|
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);
|
code.debug.push(ir_stmt.span);
|
||||||
|
|
||||||
// there will always at least be an `End` instruction after the loop
|
// there will always at least be an `End` instruction after the loop
|
||||||
let after_loop_idx = code.stmts.len();
|
let after_loop_idx = code.stmts.len();
|
||||||
|
|
||||||
// fix the placeholder with the actual index
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@ use crate::codegen::{Code, Stmt};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
|
|
||||||
const MEM_SIZE: usize = 32_000;
|
const MEM_SIZE: u32 = 32_000;
|
||||||
|
|
||||||
type Memory = [Wrapping<u8>; MEM_SIZE];
|
type Memory = [Wrapping<u8>; MEM_SIZE as usize];
|
||||||
|
|
||||||
// TODO maybe repr(C) to prevent field reordering?
|
// TODO maybe repr(C) to prevent field reordering?
|
||||||
struct Interpreter<'c, W, R> {
|
struct Interpreter<'c, W, R> {
|
||||||
code: &'c Code<'c>,
|
code: &'c Code<'c>,
|
||||||
ip: usize,
|
ip: u32,
|
||||||
ptr: usize,
|
ptr: u32,
|
||||||
stdout: W,
|
stdout: W,
|
||||||
stdin: R,
|
stdin: R,
|
||||||
mem: Memory,
|
mem: Memory,
|
||||||
|
|
@ -27,7 +27,7 @@ where
|
||||||
ptr: 0,
|
ptr: 0,
|
||||||
stdout,
|
stdout,
|
||||||
stdin,
|
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
|
// 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,
|
// SAFETY: If the code ends with an `End` and there are no out of bounds jumps,
|
||||||
// `self.ip` will never be out of bounds
|
// `self.ip` will never be out of bounds
|
||||||
// Removing this bounds check speeds up execution by about 40%
|
// Removing this bounds check speeds up execution by about 40%
|
||||||
debug_assert!(self.ip < stmts.len());
|
debug_assert!((self.ip as usize) < stmts.len());
|
||||||
let instr = unsafe { *stmts.get_unchecked(self.ip) };
|
let instr = unsafe { *stmts.get_unchecked(self.ip as usize) };
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
match instr {
|
match instr {
|
||||||
Stmt::Add(n) => {
|
Stmt::Add(n) => {
|
||||||
|
|
@ -97,10 +97,10 @@ impl<'c, W: Write, R: Read> Interpreter<'c, W, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn elem_mut(&mut self) -> &mut Wrapping<u8> {
|
fn elem_mut(&mut self) -> &mut Wrapping<u8> {
|
||||||
&mut self.mem[self.ptr]
|
&mut self.mem[self.ptr as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn elem(&self) -> u8 {
|
fn elem(&self) -> u8 {
|
||||||
self.mem[self.ptr].0
|
self.mem[self.ptr as usize].0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue