CAP/MiniC/TP05/LivenessDataFlow.py

100 lines
3.8 KiB
Python
Raw Permalink Normal View History

2024-10-06 19:58:11 +02:00
from typing import Dict, Set
from Lib.Operands import Operand, Temporary
from Lib.Statement import Statement, Instruction, regset_to_string
from Lib.CFG import CFG, Block
import copy
class LivenessDataFlow:
def __init__(self, function, debug=False):
self._function: CFG = function
self._debug = debug
# Live Operands at input and output of blocks
self._blockin: Dict[Block, Set[Operand]] = {}
self._blockout: Dict[Block, Set[Operand]] = {}
# Live Operands at outputs of instructions
self._liveout: Dict[tuple[Block, Statement], Set[Operand]] = {}
def run(self):
self.set_gen_kill()
if self._debug:
self.print_gen_kill()
self.run_dataflow_analysis()
if self._debug:
self.print_map_in_out()
self.fill_liveout()
def set_gen_kill(self):
"""Set the _gen and _kill field for each block in the function."""
for blk in self._function.get_blocks():
self.set_gen_kill_in_block(blk)
def set_gen_kill_in_block(self, block: Block) -> None:
gen = set()
kill = set()
for i in block.get_all_statements():
# Reminder: '|' is set union, '-' is subtraction.
raise NotImplementedError()
block._gen = gen
block._kill = kill
def run_dataflow_analysis(self):
"""Run the dataflow liveness analysis, i.e. compute self._blockin and
self._blockout based on the ._kill and ._gen fields of individual
instructions."""
if self._debug:
print("Dataflow Analysis")
# initialisation of all blockout,blockin sets, and def = kill
for blk in self._function.get_blocks():
self._blockin[blk] = set()
self._blockout[blk] = set()
stable = False
while not stable:
# Iterate until fixpoint :
# make calls to self._function.dataflow_one_step
stable = True # CHANGE
# TODO (lab5) ! (perform iterations until fixpoint).
def dataflow_one_step(self):
"""Run one iteration of the dataflow analysis. This function is meant
to be run iteratively until fixpoint."""
for blk in self._function.get_blocks():
self._blockout[blk] = set()
for child_label in blk.get_terminator().targets():
child = self._function.get_block(child_label)
self._blockout[blk] = self._blockout[blk] | self._blockin[child]
self._blockin[blk] = (self._blockout[blk] - blk._kill) | blk._gen
def fill_liveout(self):
"""Propagate the information from blockout/blockin inside the block
to get liveset instruction by instructions."""
for blk in self._function.get_blocks():
liveset = self._blockout[blk]
for instr in reversed(blk.get_all_statements()):
self._liveout[blk, instr] = liveset
liveset = (liveset - set(instr.defined())) | set(instr.used())
def print_gen_kill(self): # pragma: no cover
print("Dataflow Analysis, Initialisation")
for i, block in enumerate(self._function.get_blocks()):
print("block " + str(block._label), ":", i)
print("gen: " + regset_to_string(block._gen))
print("kill: " + regset_to_string(block._kill) + "\n")
def print_map_in_out(self): # pragma: no cover
"""Print in/out sets, useful for debug!"""
print("In: {" +
", ".join(str(x.get_label()) + ": "
+ regset_to_string(self._blockin[x])
for x in self._blockin.keys()) +
"}")
print("Out: {" +
", ".join(str(x.get_label()) + ": "
+ regset_to_string(self._blockout[x])
for x in self._blockout.keys()) +
"}")