From ae82029f0d5b147c057b02acd7076d38446e88aa Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Thu, 25 Jul 2024 11:27:07 +0900 Subject: [PATCH] Invalidate releases when optimizer inserts registers --- inputs/{failing => passing}/optimizerBug.ts | 2 +- valuescript_compiler/src/optimization/kal.rs | 16 +++++++++++- .../src/optimization/simplify.rs | 26 +++++++++++++++++-- 3 files changed, 40 insertions(+), 4 deletions(-) rename inputs/{failing => passing}/optimizerBug.ts (89%) diff --git a/inputs/failing/optimizerBug.ts b/inputs/passing/optimizerBug.ts similarity index 89% rename from inputs/failing/optimizerBug.ts rename to inputs/passing/optimizerBug.ts index 71fc4bd..6d08211 100644 --- a/inputs/failing/optimizerBug.ts +++ b/inputs/passing/optimizerBug.ts @@ -1,4 +1,4 @@ -// //! test_output(1) +//! test_output(1) export default function main() { return f([1]); diff --git a/valuescript_compiler/src/optimization/kal.rs b/valuescript_compiler/src/optimization/kal.rs index baa2b95..e6bd709 100644 --- a/valuescript_compiler/src/optimization/kal.rs +++ b/valuescript_compiler/src/optimization/kal.rs @@ -363,6 +363,8 @@ pub struct FnState { pub pointer_kals: HashMap, pub mutable_this_established: bool, pub registers: BTreeMap, + pub register_releases: HashMap>, + pub invalidated_releases: Vec, pub new_instructions: Vec, } @@ -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()) } } diff --git a/valuescript_compiler/src/optimization/simplify.rs b/valuescript_compiler/src/optimization/simplify.rs index ceb81f7..9083e2d 100644 --- a/valuescript_compiler/src/optimization/simplify.rs +++ b/valuescript_compiler/src/optimization/simplify.rs @@ -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);