mirror of
https://github.com/Noratrieb/brainfuck.git
synced 2026-01-16 14:25:03 +01:00
start with finding dead stores
This commit is contained in:
parent
039b5ea9c7
commit
d5d80f79b7
8 changed files with 181 additions and 56 deletions
|
|
@ -1,9 +1,11 @@
|
|||
use std::collections::{hash_map::Entry, HashMap};
|
||||
|
||||
use bumpalo::Bump;
|
||||
use tracing::info;
|
||||
|
||||
use crate::mir::{
|
||||
state::{CellState, MemoryState, MemoryStateChange},
|
||||
Mir, StmtKind,
|
||||
state::{CellState, MemoryState, MemoryStateChange, Store},
|
||||
Mir, Offset, StmtKind,
|
||||
};
|
||||
|
||||
/// this pass fills out as much state info for all statements as possible
|
||||
|
|
@ -11,6 +13,7 @@ use crate::mir::{
|
|||
pub fn passes<'mir>(alloc: &'mir Bump, mir: &mut Mir<'mir>) {
|
||||
pass_fill_state_info(alloc, mir);
|
||||
pass_const_propagation(mir);
|
||||
pass_dead_store_elimination(mir);
|
||||
}
|
||||
/// this pass fills out as much state info for all statements as possible
|
||||
#[tracing::instrument(skip(alloc, mir))]
|
||||
|
|
@ -27,7 +30,7 @@ fn pass_fill_state_info_inner<'mir>(
|
|||
) {
|
||||
for stmt in &mut mir.stmts {
|
||||
let state = match &mut stmt.kind {
|
||||
StmtKind::AddSub(offset, n, store) => {
|
||||
StmtKind::AddSub { offset, n, store } => {
|
||||
let prev_state = outer.state_for_offset(*offset);
|
||||
let new_state = match prev_state {
|
||||
CellState::WrittenToKnown(_, prev_n) => {
|
||||
|
|
@ -65,7 +68,7 @@ fn pass_fill_state_info_inner<'mir>(
|
|||
StmtKind::PointerMove(n) => {
|
||||
MemoryState::single(alloc, outer, MemoryStateChange::Move(*n))
|
||||
}
|
||||
StmtKind::Loop(body, _) => {
|
||||
StmtKind::Loop(body) => {
|
||||
// TODO: we can get a lot smarter here and get huge benefits; we don't yet
|
||||
pass_fill_state_info_inner(alloc, body, MemoryState::empty(alloc));
|
||||
MemoryState::double(
|
||||
|
|
@ -80,7 +83,7 @@ fn pass_fill_state_info_inner<'mir>(
|
|||
},
|
||||
)
|
||||
}
|
||||
StmtKind::Out(_) => outer,
|
||||
StmtKind::Out => outer,
|
||||
StmtKind::In(store) => MemoryState::single(
|
||||
alloc,
|
||||
outer,
|
||||
|
|
@ -103,6 +106,82 @@ fn pass_fill_state_info_inner<'mir>(
|
|||
}
|
||||
}
|
||||
|
||||
/// This pass eliminates dead stores. It should probably be run multiple times between other passes
|
||||
/// for cleanup
|
||||
#[tracing::instrument(skip(mir))]
|
||||
fn pass_dead_store_elimination(mir: &mut Mir<'_>) {
|
||||
pass_dead_store_elimination_mark_dead_stores(mir)
|
||||
}
|
||||
|
||||
fn pass_dead_store_elimination_mark_dead_stores(mir: &mut Mir<'_>) {
|
||||
fn mark_store(
|
||||
potential_dead_stores: &mut HashMap<Offset, Store>,
|
||||
offset: Offset,
|
||||
store: &Store,
|
||||
) {
|
||||
match potential_dead_stores.entry(offset) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
let old = entry.insert(store.clone());
|
||||
if old.is_maybe_dead() {
|
||||
// it's certainly dead
|
||||
info!("We have a dead one!!!");
|
||||
old.mark_dead();
|
||||
} else {
|
||||
// it's alive and well, drop it and keep it marked alive
|
||||
drop(old);
|
||||
}
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(store.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut potential_dead_stores = HashMap::new();
|
||||
let mut current_offset = 0;
|
||||
|
||||
for stmt in &mir.stmts {
|
||||
match &stmt.kind {
|
||||
StmtKind::AddSub { store, offset, .. } => {
|
||||
mark_store(&mut potential_dead_stores, current_offset + offset, store);
|
||||
}
|
||||
StmtKind::MoveAddTo {
|
||||
offset,
|
||||
store_move,
|
||||
store_set_null,
|
||||
} => {
|
||||
mark_store(&mut potential_dead_stores, current_offset, store_set_null);
|
||||
mark_store(
|
||||
&mut potential_dead_stores,
|
||||
current_offset + offset,
|
||||
store_move,
|
||||
);
|
||||
}
|
||||
StmtKind::PointerMove(offset) => {
|
||||
current_offset -= offset; // ???
|
||||
}
|
||||
StmtKind::Loop(_) | StmtKind::Out => {
|
||||
let store = potential_dead_stores.get(¤t_offset);
|
||||
if let Some(store) = store {
|
||||
store.add_load();
|
||||
}
|
||||
}
|
||||
StmtKind::In(store) | StmtKind::SetN(_, store) => {
|
||||
mark_store(&mut potential_dead_stores, current_offset, store);
|
||||
}
|
||||
}
|
||||
|
||||
if stmt.state.has_forget_delta() {
|
||||
// they might all have loads now
|
||||
for store in potential_dead_stores.values_mut() {
|
||||
// TODO STOP: WE MUTATE THE STATE HERE!!! ALL COOL DEAD STORES WILL BE CLOBBERED
|
||||
store.clobber();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test pass
|
||||
#[tracing::instrument(skip(mir))]
|
||||
fn pass_const_propagation(mir: &mut Mir<'_>) {
|
||||
pass_const_propagation_inner(mir)
|
||||
|
|
@ -111,15 +190,13 @@ fn pass_const_propagation(mir: &mut Mir<'_>) {
|
|||
fn pass_const_propagation_inner(mir: &mut Mir<'_>) {
|
||||
for stmt in &mut mir.stmts {
|
||||
match &mut stmt.kind {
|
||||
StmtKind::Out(_) => {
|
||||
StmtKind::Out => {
|
||||
let state = stmt.state.state_for_offset(0);
|
||||
info!(?state, "We got the state of the output 😳😳😳");
|
||||
// we could now insert a `SetN` before the `Out`, to mark the previous store
|
||||
// as dead.
|
||||
}
|
||||
StmtKind::Loop(body, _) => {
|
||||
StmtKind::Loop(body) => {
|
||||
let state = stmt.state.state_for_offset(0);
|
||||
info!(?state, "We got the state of the output 😳😳😳");
|
||||
// we could now insert a `SetN` before the `Loop`, to mark the previous store
|
||||
// as dead.
|
||||
pass_const_propagation_inner(body);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue