Start refactoring task 1 and 2
This commit is contained in:
64
Project-02-03-04-05/cfa/LiveVariables.py
Normal file
64
Project-02-03-04-05/cfa/LiveVariables.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
from cfa.BackwardAnalysis import BackwardAnalysis, Var
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from cfg.CFG import CFG
|
||||
|
||||
class LiveVariables(BackwardAnalysis):
|
||||
def __init__(self, cfg: "CFG") -> None:
|
||||
# Base populates uses, defs, _func_scope, etc.
|
||||
super().__init__(cfg)
|
||||
|
||||
self.gen: dict[int, set[Var]] = {}
|
||||
self.kill: dict[int, set[Var]] = {}
|
||||
self.incoming: dict[int, set[Var]] = {}
|
||||
self.outgoing: dict[int, set[Var]] = {}
|
||||
|
||||
self.__init_sets()
|
||||
self.solve()
|
||||
|
||||
# Initialize gen, kill, in, and out sets for all CFG nodes.
|
||||
def __init_sets(self) -> None:
|
||||
for node in self.cfg.nodes():
|
||||
nid = node.id
|
||||
|
||||
# GEN(n) = USE(n); KILL(n) = DEF(n)
|
||||
self.gen[nid] = set(self.uses[nid])
|
||||
self.kill[nid] = set(self.defs[nid])
|
||||
|
||||
# IN(n) = GEN(n) = USE(n); OUT(n) = empty
|
||||
self.incoming[nid] = set(self.gen[nid])
|
||||
self.outgoing[nid] = set()
|
||||
|
||||
# Update the lists until the fixpoint.
|
||||
def solve(self) -> None:
|
||||
nodes = list(self.cfg.nodes())
|
||||
known: set[int] = set(n.id for n in nodes)
|
||||
|
||||
# while there are changes do
|
||||
changes = True
|
||||
while changes:
|
||||
changes = False
|
||||
|
||||
# for all v IN V do
|
||||
for node in nodes:
|
||||
nid = node.id
|
||||
|
||||
# OUT(n) = UNION IN(s) for all successors s
|
||||
new_out: set[Var] = set()
|
||||
for child in node.children:
|
||||
if child.id in known:
|
||||
new_out |= self.incoming[child.id]
|
||||
|
||||
# IN(n) = (OUT(n) MINUS KILL(n)) UNION GEN(n)
|
||||
new_in: set[Var] = (new_out - self.kill[nid]) | self.gen[nid]
|
||||
|
||||
if new_out != self.outgoing[nid] or new_in != self.incoming[nid]:
|
||||
self.outgoing[nid] = new_out
|
||||
self.incoming[nid] = new_in
|
||||
changes = True # there are changes -> loop again
|
||||
|
||||
# Return the living variables within each node
|
||||
def live_vars_by_node(self) -> dict[int, set[Var]]:
|
||||
return {nid: set(vs) for nid, vs in self.incoming.items() if vs}
|
||||
Reference in New Issue
Block a user