Files
Construction-of-Compilers/Project-02-03-04-05/optimizations/DeadAssignmentElimination.py
2026-03-12 11:32:41 +01:00

46 lines
1.7 KiB
Python

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