Invalidate releases when optimizer inserts registers

This commit is contained in:
Andrew Morris
2024-07-25 11:27:07 +09:00
parent 77882f0d0a
commit ae82029f0d
3 changed files with 40 additions and 4 deletions

View File

@@ -1,4 +1,4 @@
// //! test_output(1)
//! test_output(1)
export default function main() {
return f([1]);

View File

@@ -363,6 +363,8 @@ pub struct FnState {
pub pointer_kals: HashMap<Pointer, Kal>,
pub mutable_this_established: bool,
pub registers: BTreeMap<String, Kal>,
pub register_releases: HashMap<String, Vec<usize>>,
pub invalidated_releases: Vec<usize>,
pub new_instructions: Vec<Instruction>,
}
@@ -404,6 +406,8 @@ impl FnState {
pointer_kals,
mutable_this_established: Default::default(),
registers: Default::default(),
register_releases: Default::default(),
invalidated_releases: Default::default(),
new_instructions: take(&mut self.new_instructions),
}
}
@@ -726,7 +730,17 @@ impl FnState {
| InstanceOf(_, _, dst)
| In(_, _, dst)
| Sub(_, _, dst) => {
if let Some(value) = self.get(dst.name.clone()).try_to_value() {
if let Some(mut value) = self.get(dst.name.clone()).try_to_value() {
value.visit_registers_mut_rev(&mut |rvm| {
if let Some(release_locations) = self.register_releases.get(&rvm.register.name) {
self
.invalidated_releases
.append(&mut release_locations.clone());
self.register_releases.remove(&rvm.register.name);
}
});
*instr = Instruction::Mov(value, dst.clone())
}
}

View File

@@ -37,6 +37,15 @@ pub fn simplify(module: &mut Module, take_registers: bool) {
}
}
/**
* Handle releases due to mutation.
*
* When you write to a register:
* mov 123 %reg
*
* The content of that register at that point is unused, so we treat it as a
* release.
*/
fn handle_mutation_releases(body: &mut [FnLine], i: usize, take_registers: bool) {
let mut calls = Vec::<(Register, usize)>::new();
@@ -145,7 +154,12 @@ fn simplify_fn(mut state: FnState, fn_: &mut Function, take_registers: bool) {
FnLine::Instruction(instr) => {
state.eval_instruction(instr);
// FIXME: Hacky side effect mechanism (eval_instruction populates new_instructions)
// FIXME: Hacky side effect mechanisms (eval_instruction populates things to do up here)
for invalid_release_i in take(&mut state.invalidated_releases) {
fn_.body[invalid_release_i] = FnLine::Comment("invalidated release".into())
}
for instr in take(&mut state.new_instructions) {
fn_.body.insert(i, FnLine::Instruction(instr));
i += 1;
@@ -153,7 +167,15 @@ fn simplify_fn(mut state: FnState, fn_: &mut Function, take_registers: bool) {
}
FnLine::Label(_) => state.clear_local(),
FnLine::Empty | FnLine::Comment(_) => {}
FnLine::Release(reg) => pending_releases.push(reg.clone()),
FnLine::Release(reg) => {
pending_releases.push(reg.clone());
state
.register_releases
.entry(reg.name.clone())
.or_default()
.push(i);
}
}
handle_mutation_releases(&mut fn_.body, i, take_registers);