Add compiler improvement
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 356 KiB After Width: | Height: | Size: 36 KiB |
BIN
Project-02-03-04-05/images/getOptimized/after.png
Normal file
BIN
Project-02-03-04-05/images/getOptimized/after.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 113 KiB |
BIN
Project-02-03-04-05/images/getOptimized/before.png
Normal file
BIN
Project-02-03-04-05/images/getOptimized/before.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 123 KiB |
@@ -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
|
||||
|
||||
@@ -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
|
||||
7
Project-02-03-04-05/optimizations/Optimization.py
Normal file
7
Project-02-03-04-05/optimizations/Optimization.py
Normal 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: ...
|
||||
2
Project-02-03-04-05/optimizations/__init__.py
Normal file
2
Project-02-03-04-05/optimizations/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from optimizations.DeadAssignmentElimination import DeadAssignmentElimination
|
||||
from optimizations.Optimization import Optimization
|
||||
36
Project-02-03-04-05/optimizations/optimize.py
Normal file
36
Project-02-03-04-05/optimizations/optimize.py
Normal 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)
|
||||
9
Project-02-03-04-05/triplaprograms/getOptimized.tripla
Normal file
9
Project-02-03-04-05/triplaprograms/getOptimized.tripla
Normal file
@@ -0,0 +1,9 @@
|
||||
let f(x, y)
|
||||
{
|
||||
let g(x)
|
||||
{
|
||||
y = x + 7
|
||||
}
|
||||
in x = g(5); y
|
||||
}
|
||||
in f(1, 2)
|
||||
@@ -1,3 +1,3 @@
|
||||
let g(a) {
|
||||
a*a
|
||||
} in g(5)
|
||||
} in b = g(5)
|
||||
Reference in New Issue
Block a user