Split out optimization dir

This commit is contained in:
Andrew Morris
2023-06-29 15:22:06 +10:00
parent f5fa17ed25
commit 76995eaf2d
7 changed files with 187 additions and 161 deletions

View File

@@ -12,7 +12,7 @@ mod instruction_mutates_this;
mod link_module;
mod module_compiler;
mod name_allocator;
mod optimize;
mod optimization;
mod resolve_path;
mod scope;
mod scope_analysis;

View File

@@ -4,10 +4,11 @@ use crate::asm::{Definition, DefinitionContent, FnLine, Instruction, Object, Poi
use crate::gather_modules::PathAndModule;
use crate::import_pattern::{ImportKind, ImportPattern};
use crate::name_allocator::NameAllocator;
use crate::optimization::optimize;
use crate::resolve_path::{resolve_path, ResolvedPath};
use crate::visit_pointers::{visit_pointers, PointerVisitation};
use crate::DiagnosticLevel;
use crate::{asm::Module, Diagnostic};
use crate::{optimize::optimize, DiagnosticLevel};
pub struct LinkModuleResult {
pub module: Option<Module>,

View File

@@ -0,0 +1,37 @@
use std::collections::HashMap;
use crate::{
asm::{DefinitionContent, Module, Pointer, Value},
visit_pointers::{visit_pointers, PointerVisitation},
};
pub fn collapse_pointers_of_pointers(module: &mut Module) {
let mut double_pointer_map = HashMap::<Pointer, Pointer>::new();
for definition in &mut module.definitions {
let pointer = match &definition.content {
DefinitionContent::Value(Value::Pointer(pointer)) => pointer,
_ => continue,
};
double_pointer_map.insert(definition.pointer.clone(), pointer.clone());
}
visit_pointers(module, |visitation| match visitation {
PointerVisitation::Definition(_) => {}
PointerVisitation::Export(pointer) | PointerVisitation::Reference(_, pointer) => {
let mut mapped_pointer: &Pointer = pointer;
loop {
if let Some(new_pointer) = double_pointer_map.get(mapped_pointer) {
mapped_pointer = new_pointer;
continue;
}
break;
}
*pointer = mapped_pointer.clone();
}
});
}

View File

@@ -0,0 +1,126 @@
use std::{collections::HashMap, mem::take};
use crate::{
asm::{
Definition, DefinitionContent, FnLine, InstructionFieldMut, Module, Number, Pointer, Value,
},
name_allocator::NameAllocator,
};
pub fn extract_constants(module: &mut Module, pointer_allocator: &mut NameAllocator) {
let mut constants = HashMap::<Value, Pointer>::new();
for defn in &mut module.definitions {
if let DefinitionContent::Function(f) = &mut defn.content {
for line in &mut f.body {
if let FnLine::Instruction(instr) = line {
instr.visit_fields_mut(&mut |field| match field {
InstructionFieldMut::Value(value) => {
value.visit_values_mut(&mut |sub_value| {
if let Some(p) = constants.get(&sub_value) {
*sub_value = Value::Pointer(p.clone());
return;
}
if let Some(name) = should_extract_value_as_constant(&sub_value) {
let p = Pointer {
name: pointer_allocator.allocate(&name),
};
let existing_p = constants.insert(take(sub_value), p.clone());
assert!(existing_p.is_none());
*sub_value = Value::Pointer(p);
}
});
}
InstructionFieldMut::Register(_) | InstructionFieldMut::LabelRef(_) => {}
});
}
}
}
}
for (value, pointer) in constants {
module.definitions.push(Definition {
pointer,
content: DefinitionContent::Value(value),
});
}
}
fn should_extract_value_as_constant(value: &Value) -> Option<String> {
if !is_constant(value) {
return None;
}
match value {
Value::Void
| Value::Undefined
| Value::Null
| Value::Bool(..)
| Value::Number(Number(..))
| Value::BigInt(..)
| Value::Pointer(..)
| Value::Builtin(..)
| Value::Register(..) => None,
Value::String(s) => {
if s.len() >= 4 {
Some(mangle_string(s))
} else {
None
}
}
Value::Array(array) => {
if array.values.iter().all(is_constant) {
Some("array".to_string())
} else {
None
}
}
Value::Object(object) => {
if object
.properties
.iter()
.all(|(k, v)| is_constant(k) && is_constant(v))
{
Some("object".to_string())
} else {
None
}
}
}
}
fn is_constant(value: &Value) -> bool {
match value {
Value::Void
| Value::Undefined
| Value::Null
| Value::Bool(..)
| Value::Number(Number(..))
| Value::BigInt(..)
| Value::String(..)
| Value::Pointer(..)
| Value::Builtin(..) => true,
Value::Register(..) => false,
Value::Array(array) => array.values.iter().all(is_constant),
Value::Object(object) => object
.properties
.iter()
.all(|(k, v)| is_constant(k) && is_constant(v)),
}
}
fn mangle_string(s: &String) -> String {
let mut res = "s_".to_string();
for c in s.chars() {
if c.is_ascii_alphanumeric() {
res.push(c);
} else {
res.push('_');
}
}
res
}

View File

@@ -0,0 +1,6 @@
mod collapse_pointers_of_pointers;
mod extract_constants;
mod optimize;
mod shake_tree;
pub use optimize::optimize;

View File

@@ -0,0 +1,12 @@
use crate::asm::Module;
use crate::name_allocator::NameAllocator;
use super::collapse_pointers_of_pointers::collapse_pointers_of_pointers;
use super::extract_constants::extract_constants;
use super::shake_tree::shake_tree;
pub fn optimize(module: &mut Module, pointer_allocator: &mut NameAllocator) {
collapse_pointers_of_pointers(module);
extract_constants(module, pointer_allocator);
shake_tree(module);
}

View File

@@ -1,49 +1,11 @@
use std::collections::{HashMap, HashSet};
use std::mem::take;
use crate::asm::{Definition, DefinitionContent, FnLine, InstructionFieldMut, Pointer, Value};
use crate::asm::{Module, Number};
use crate::name_allocator::NameAllocator;
use crate::asm::Module;
use crate::asm::{Definition, DefinitionContent, Pointer};
use crate::visit_pointers::{visit_pointers, PointerVisitation};
pub fn optimize(module: &mut Module, pointer_allocator: &mut NameAllocator) {
collapse_pointers_of_pointers(module);
extract_constants(module, pointer_allocator);
shake_tree(module);
}
fn collapse_pointers_of_pointers(module: &mut Module) {
let mut double_pointer_map = HashMap::<Pointer, Pointer>::new();
for definition in &mut module.definitions {
let pointer = match &definition.content {
DefinitionContent::Value(Value::Pointer(pointer)) => pointer,
_ => continue,
};
double_pointer_map.insert(definition.pointer.clone(), pointer.clone());
}
visit_pointers(module, |visitation| match visitation {
PointerVisitation::Definition(_) => {}
PointerVisitation::Export(pointer) | PointerVisitation::Reference(_, pointer) => {
let mut mapped_pointer: &Pointer = pointer;
loop {
if let Some(new_pointer) = double_pointer_map.get(mapped_pointer) {
mapped_pointer = new_pointer;
continue;
}
break;
}
*pointer = mapped_pointer.clone();
}
});
}
fn shake_tree(module: &mut Module) {
pub fn shake_tree(module: &mut Module) {
let mut dependency_graph = HashMap::<Pointer, HashSet<Pointer>>::new();
let mut reverse_dependency_graph = HashMap::<Pointer, HashSet<Pointer>>::new();
let mut pointers_to_include = Vec::<Pointer>::new();
@@ -195,121 +157,3 @@ fn gather_required_pointers(
}
}
}
fn extract_constants(module: &mut Module, pointer_allocator: &mut NameAllocator) {
let mut constants = HashMap::<Value, Pointer>::new();
for defn in &mut module.definitions {
if let DefinitionContent::Function(f) = &mut defn.content {
for line in &mut f.body {
if let FnLine::Instruction(instr) = line {
instr.visit_fields_mut(&mut |field| match field {
InstructionFieldMut::Value(value) => {
value.visit_values_mut(&mut |sub_value| {
if let Some(p) = constants.get(&sub_value) {
*sub_value = Value::Pointer(p.clone());
return;
}
if let Some(name) = should_extract_value_as_constant(&sub_value) {
let p = Pointer {
name: pointer_allocator.allocate(&name),
};
let existing_p = constants.insert(take(sub_value), p.clone());
assert!(existing_p.is_none());
*sub_value = Value::Pointer(p);
}
});
}
InstructionFieldMut::Register(_) | InstructionFieldMut::LabelRef(_) => {}
});
}
}
}
}
for (value, pointer) in constants {
module.definitions.push(Definition {
pointer,
content: DefinitionContent::Value(value),
});
}
}
fn should_extract_value_as_constant(value: &Value) -> Option<String> {
if !is_constant(value) {
return None;
}
match value {
Value::Void
| Value::Undefined
| Value::Null
| Value::Bool(..)
| Value::Number(Number(..))
| Value::BigInt(..)
| Value::Pointer(..)
| Value::Builtin(..)
| Value::Register(..) => None,
Value::String(s) => {
if s.len() >= 4 {
Some(mangle_string(s))
} else {
None
}
}
Value::Array(array) => {
if array.values.iter().all(is_constant) {
Some("array".to_string())
} else {
None
}
}
Value::Object(object) => {
if object
.properties
.iter()
.all(|(k, v)| is_constant(k) && is_constant(v))
{
Some("object".to_string())
} else {
None
}
}
}
}
fn is_constant(value: &Value) -> bool {
match value {
Value::Void
| Value::Undefined
| Value::Null
| Value::Bool(..)
| Value::Number(Number(..))
| Value::BigInt(..)
| Value::String(..)
| Value::Pointer(..)
| Value::Builtin(..) => true,
Value::Register(..) => false,
Value::Array(array) => array.values.iter().all(is_constant),
Value::Object(object) => object
.properties
.iter()
.all(|(k, v)| is_constant(k) && is_constant(v)),
}
}
fn mangle_string(s: &String) -> String {
let mut res = "s_".to_string();
for c in s.chars() {
if c.is_ascii_alphanumeric() {
res.push(c);
} else {
res.push('_');
}
}
res
}