Add compiler improvement

This commit is contained in:
Jan-Niclas Loosen
2026-03-12 11:32:41 +01:00
parent 438447e6de
commit 9462ccd3ed
10 changed files with 108 additions and 1 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View File

@@ -17,6 +17,7 @@ from cfa.to_dot import analysis_to_dot
from cfg.CFG import CFG
from vistram.tram import *
from vistram.vistram import MachineUI
from optimizations.optimize import optimize
matplotlib.use("TkAgg")
@@ -129,6 +130,9 @@ if __name__ == "__main__":
ast = yacc.parser.parse(source)
if mode == 0:
if cnsl.prompt_confirmation("\nOptimize AST?", default="y"):
ast = optimize(ast)
# Pretty print
if cnsl.prompt_confirmation("\nPretty-print AST?"):
print("")
@@ -156,6 +160,9 @@ if __name__ == "__main__":
print("Rendered AST diagram.")
elif mode == 1:
if cnsl.prompt_confirmation("\nOptimize AST?", default="y"):
ast = optimize(ast)
tram_code = assemble(ast)
# Print TRAM code

View File

@@ -0,0 +1,46 @@
from __future__ import annotations
import cfg_build
from cfg.CFG import CFG
from cfg.CFG_Node import CFG_Node
from cfa.ReachedUses import ReachedUses
from syntax import EXPRESSION, ASSIGN
from optimizations.Optimization import Optimization
class DeadAssignmentElimination(Optimization):
def __init__(self) -> None:
self._node_by_ast_id: dict[int, CFG_Node] = {}
self.__ru: ReachedUses | None = None
def setup(self, ast: EXPRESSION) -> None:
cfg_build.FUNCTIONS.clear()
cfg_build.CURRENT_FUNCTION = None
cfg = CFG(ast)
self.__ru = ReachedUses(cfg)
self._node_by_ast_id = {id(n.ast_node): n for n in self.__ru.cfg.nodes() if n.ast_node is not None}
def apply(self, node: EXPRESSION) -> EXPRESSION:
# Only ASSIGN nodes can be dead assignments.
if not isinstance(node, ASSIGN):
return node
# Find the CFG node corresponding to this AST node.
# If none is found, the node was not analyzed — leave it unchanged.
cfg_node = self._node_by_ast_id.get(id(node))
if cfg_node is None:
return node
ru = self.__ru
nid = cfg_node.id
defined_vars = ru.defs.get(nid, set())
out = ru.out_sets.get(nid, set())
# Check if any use-fact in OUT(n) belongs to a variable defined at n.
# If so, the assignment is live — at least one use is reachable from here.
for (_, var) in out:
if var in defined_vars:
return node
# No reached use found for the assigned variable — the assignment is dead.
# Replace ASSIGN(var, expr) with expr to preserve side effects on the RHS.
return node.expr

View File

@@ -0,0 +1,7 @@
from __future__ import annotations
from syntax import EXPRESSION
class Optimization:
def setup(self, ast: EXPRESSION) -> None: ...
def apply(self, node: EXPRESSION) -> EXPRESSION: ...

View File

@@ -0,0 +1,2 @@
from optimizations.DeadAssignmentElimination import DeadAssignmentElimination
from optimizations.Optimization import Optimization

View File

@@ -0,0 +1,36 @@
from __future__ import annotations
from optimizations.Optimization import Optimization
from optimizations.DeadAssignmentElimination import DeadAssignmentElimination
from syntax import EXPRESSION
# Traverses the AST and applies the given optimizations
def __apply_optimizations(node: EXPRESSION, optimizations: list[Optimization]) -> EXPRESSION:
for key, value in list(node.__dict__.items()):
if key == "pp":
continue
if isinstance(value, EXPRESSION):
new_child = __apply_optimizations(value, optimizations)
if new_child is not value:
setattr(node, key, new_child)
elif isinstance(value, list):
for i, elem in enumerate(value):
if isinstance(elem, EXPRESSION):
new_elem = __apply_optimizations(elem, optimizations)
if new_elem is not elem:
value[i] = new_elem
result: EXPRESSION = node
for opt in optimizations:
result = opt.apply(result)
return result
# Stores the active optimizations
ACTIVE_OPTIMIZATIONS: list[Optimization] = [
DeadAssignmentElimination(),
]
# Apply optimizations to the given AST node
def optimize(ast: EXPRESSION) -> EXPRESSION:
for opt in ACTIVE_OPTIMIZATIONS:
opt.setup(ast)
return __apply_optimizations(ast, ACTIVE_OPTIMIZATIONS)

View File

@@ -0,0 +1,9 @@
let f(x, y)
{
let g(x)
{
y = x + 7
}
in x = g(5); y
}
in f(1, 2)

View File

@@ -1,3 +1,3 @@
let g(a) {
a*a
} in g(5)
} in b = g(5)