From 063ab365a7c929fc803c9a6897a170b3731ee2ce Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Tue, 4 Jul 2023 11:01:07 +1000 Subject: [PATCH] Remove unused registers --- concept-code/modules/src/main.ts | 4 +- valuescript_compiler/src/optimization/mod.rs | 1 + .../src/optimization/optimize.rs | 2 + .../optimization/remove_unused_registers.rs | 184 ++++++++++++++++++ 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 valuescript_compiler/src/optimization/remove_unused_registers.rs diff --git a/concept-code/modules/src/main.ts b/concept-code/modules/src/main.ts index 70f6335..4d1cf5e 100644 --- a/concept-code/modules/src/main.ts +++ b/concept-code/modules/src/main.ts @@ -6,5 +6,7 @@ export default function main() { let x = f1(1, 2, 3); x = f2(x); - return [x, util.dist(3, 4)]; + const dist = util.dist; + + return [x, dist(3, 4)]; } diff --git a/valuescript_compiler/src/optimization/mod.rs b/valuescript_compiler/src/optimization/mod.rs index d54b67e..1d71ae2 100644 --- a/valuescript_compiler/src/optimization/mod.rs +++ b/valuescript_compiler/src/optimization/mod.rs @@ -5,6 +5,7 @@ mod optimize; mod reduce_instructions; mod remove_meta_lines; mod remove_unused_labels; +mod remove_unused_registers; mod shake_tree; mod simplify; mod simplify_jumps; diff --git a/valuescript_compiler/src/optimization/optimize.rs b/valuescript_compiler/src/optimization/optimize.rs index 2e6c813..38292b1 100644 --- a/valuescript_compiler/src/optimization/optimize.rs +++ b/valuescript_compiler/src/optimization/optimize.rs @@ -6,6 +6,7 @@ use super::extract_constants::extract_constants; use super::reduce_instructions::reduce_instructions; use super::remove_meta_lines::remove_meta_lines; use super::remove_unused_labels::remove_unused_labels; +use super::remove_unused_registers::remove_unused_registers; use super::shake_tree::shake_tree; use super::simplify::simplify; use super::simplify_jumps::simplify_jumps; @@ -18,6 +19,7 @@ pub fn optimize(module: &mut Module, pointer_allocator: &mut NameAllocator) { simplify(module); reduce_instructions(module); remove_unused_labels(module); + remove_unused_registers(module); simplify_jumps(module); } diff --git a/valuescript_compiler/src/optimization/remove_unused_registers.rs b/valuescript_compiler/src/optimization/remove_unused_registers.rs new file mode 100644 index 0000000..e4272d2 --- /dev/null +++ b/valuescript_compiler/src/optimization/remove_unused_registers.rs @@ -0,0 +1,184 @@ +use std::collections::{HashMap, HashSet}; + +use crate::{ + asm::{DefinitionContent, FnLine, Function, Module, Register}, + instruction::Instruction, +}; + +pub fn remove_unused_registers(module: &mut Module) { + for defn in &mut module.definitions { + if let DefinitionContent::Function(fn_) = &mut defn.content { + remove_unused_registers_fn(fn_); + } + } +} + +fn remove_unused_registers_fn(fn_: &mut Function) { + let dependency_tree = build_dependency_tree(fn_); + let primary_registers = identify_primary_registers(fn_); + let used_registers = gather_used_registers(&primary_registers, &dependency_tree); + + for line in &mut fn_.body { + let instr = match line { + FnLine::Instruction(instr) => instr, + _ => continue, + }; + + let mut comment_out = false; + + instr.visit_registers_mut_rev(&mut |rvm| { + if !used_registers.contains(&rvm.register.name) { + if rvm.read { + comment_out = true; + } else if rvm.write { + *rvm.register = Register::ignore(); + } + } + }); + + if comment_out { + *line = FnLine::Comment(line.to_string()); + } + } +} + +fn gather_used_registers( + primary_registers: &HashSet, + dependency_tree: &HashMap>, +) -> HashSet { + let mut used_registers = HashSet::::new(); + + for reg in primary_registers { + add_used_register(&mut used_registers, reg, dependency_tree); + } + + used_registers +} + +fn add_used_register( + used_registers: &mut HashSet, + reg: &String, + dependency_tree: &HashMap>, +) { + if used_registers.contains(reg) { + return; + } + + used_registers.insert(reg.clone()); + + if let Some(deps) = dependency_tree.get(reg) { + for dep in deps { + add_used_register(used_registers, dep, dependency_tree); + } + } +} + +fn build_dependency_tree(fn_: &mut Function) -> HashMap> { + let mut dependency_tree = HashMap::>::new(); + + for line in &mut fn_.body { + let instr = match line { + FnLine::Instruction(instr) => instr, + _ => continue, + }; + + let mut reads = HashSet::::new(); + let mut writes = HashSet::::new(); + + instr.visit_registers_mut_rev(&mut |rvm| { + if rvm.read { + reads.insert(rvm.register.name.clone()); + } + + if rvm.write { + writes.insert(rvm.register.name.clone()); + } + }); + + for write in &writes { + let dependents = dependency_tree.entry(write.clone()).or_default(); + for read in &reads { + dependents.insert(read.clone()); + } + } + } + + dependency_tree +} + +fn identify_primary_registers(fn_: &mut Function) -> HashSet { + let mut primary_registers = HashSet::::new(); + primary_registers.insert("return".to_string()); + primary_registers.insert("this".to_string()); + + for line in &mut fn_.body { + let instr = match line { + FnLine::Instruction(instr) => instr, + _ => continue, + }; + + match instr { + Instruction::Call(fn_, args, _) => { + fn_.visit_registers_mut_rev(&mut |rvm| { + primary_registers.insert(rvm.register.name.clone()); + }); + + args.visit_registers_mut_rev(&mut |rvm| { + primary_registers.insert(rvm.register.name.clone()); + }); + } + Instruction::Apply(fn_, ctx, args, _) => { + fn_.visit_registers_mut_rev(&mut |rvm| { + primary_registers.insert(rvm.register.name.clone()); + }); + + primary_registers.insert(ctx.name.clone()); + + args.visit_registers_mut_rev(&mut |rvm| { + primary_registers.insert(rvm.register.name.clone()); + }); + } + Instruction::SubCall(obj, key, args, _) | Instruction::ThisSubCall(obj, key, args, _) => { + primary_registers.insert(obj.name.clone()); + + key.visit_registers_mut_rev(&mut |rvm| { + primary_registers.insert(rvm.register.name.clone()); + }); + + args.visit_registers_mut_rev(&mut |rvm| { + primary_registers.insert(rvm.register.name.clone()); + }); + } + Instruction::ConstSubCall(obj, key, args, _) => { + obj.visit_registers_mut_rev(&mut |rvm| { + primary_registers.insert(rvm.register.name.clone()); + }); + + key.visit_registers_mut_rev(&mut |rvm| { + primary_registers.insert(rvm.register.name.clone()); + }); + + args.visit_registers_mut_rev(&mut |rvm| { + primary_registers.insert(rvm.register.name.clone()); + }); + } + Instruction::Next(reg, _) => { + primary_registers.insert(reg.name.clone()); + } + Instruction::Cat(value, _) + | Instruction::Yield(value, _) + | Instruction::YieldStar(value, _) + | Instruction::JmpIf(value, _) + | Instruction::JmpIfNot(value, _) + | Instruction::Throw(value) => { + value.visit_registers_mut_rev(&mut |rvm| { + primary_registers.insert(rvm.register.name.clone()); + }); + } + + _ => {} + } + } + + primary_registers +}