Skip to content

Commit

Permalink
Merge branch 'main' of github.com:costa-group/grey
Browse files Browse the repository at this point in the history
  • Loading branch information
tutugordillo committed Jul 18, 2024
2 parents d4f1153 + 8a80fdd commit e0b6443
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 17 deletions.
3 changes: 2 additions & 1 deletion src/analysis/abstract_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ def digraph_from_block_info(block_info: Iterable[AbstractBlockInfo]) -> pgv.AGra
"""
Generates a DiGraph considering the information from successors
"""
graph = pgv.AGraph()
graph = pgv.AGraph(directed=True)
for block in block_info:
graph.add_node(block.block_id)
for successor in block.successors:
graph.add_edge(block.block_id, successor)
return graph
Expand Down
13 changes: 8 additions & 5 deletions src/analysis/fixpoint_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,23 @@ def get_input_state(self) -> state_T:
def get_output_state(self) -> state_T:
return self.output_state

def revisit_block(self, input_state: state_T):
def revisit_block(self, current_state: state_T):
"""
Evaluates if a block need to be revisited or not
"""
logging.debug("Comparing...")
logging.debug("Current input state: " + str(self))
logging.debug("Compared state: " + str(input_state))
leq = input_state.leq(self.input_state)
logging.debug("Stored state: " + str(self))
logging.debug("Current state: " + str(current_state))

# If the state being considered is leq than the one
# currently stored, then we return False
leq = current_state.leq(self.input_state)
logging.debug("Result: " + str(leq))

if leq:
return False

self.input_state.lub(input_state)
self.input_state.lub(current_state)
return True

@abstractmethod
Expand Down
38 changes: 30 additions & 8 deletions src/liveness/liveness_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from analysis.fixpoint_analysis import BlockAnalysisInfo, BackwardsAnalysis
from analysis.abstract_state import digraph_from_block_info
from liveness.liveness_state import LivenessState, LivenessBlockInfo
from parser.cfg_block_list import CFGBlockList
from parser.cfg import CFG
from parser.parser import parser_CFG_from_JSON
import networkx
Expand All @@ -30,21 +31,42 @@ def propagate_information(self):
else:
self.output_state.lub(self.input_state)

def dot_repr(self):
instr_repr = '\n'.join([instr.dot_repr() for instr in self.block_info._instructions]) \
if len(self.block_info._instructions) > 0 else "[]"
text_repr_list = [f"{self.output_state}", instr_repr, f"{self.input_state}"]
return '\n'.join(text_repr_list)

def __repr__(self):
text_repr_list = [f"Input state: {self.input_state}", f"Output state: {self.output_state}",
f"Block info: {self.block_info}"]
return '\n'.join(text_repr_list)


def construct_analysis_info_from_cfgblocklist(block_list: CFGBlockList) -> Dict[str, Any]:
"""
Constructs the info needed for the liveness analysis from a given set of blocks.
This information consists of a dict with two entries: "block_info", that contains the information needed per
block and "terminal_blocks", which contain the list of terminal block ids
"""
block_info = {block_id: LivenessBlockInfo(block) for block_id, block in block_list.get_block_dict().items()}
terminal_blocks = block_list.get_terminal_blocks()
return {"block_info": block_info, "terminal_blocks": terminal_blocks}


def construct_analysis_info(cfg: CFG):
# TODO: decide how to construct the vertices for each subobject
cfg_info = dict()
for object_id, subobject in cfg.objectCFG.items():
block_list = subobject.blocks
block_info = {block_id: LivenessBlockInfo(block) for block_id, block in block_list.get_block_dict().items()}
terminal_blocks = block_list.get_terminal_blocks()
cfg_info[subobject.name] = {"block_info": block_info, "terminal_blocks": terminal_blocks}
logging.debug("Suboject" + str(cfg_info))

# Construct the cfg information for the blocks in the objects
for object_id, cfg_object in cfg.objectCFG.items():
block_list = cfg_object.blocks
cfg_info[object_id] = construct_analysis_info_from_cfgblocklist(block_list)

# We also consider the information per function
for function_name, cfg_function in cfg_object.functions.items():
cfg_info[function_name] = construct_analysis_info_from_cfgblocklist(cfg_function.blocks)

# TODO: handle subobjects as well
return cfg_info


Expand Down Expand Up @@ -84,7 +106,7 @@ def dot_from_analysis(cfg: CFG):

for block_live, live_vars in liveness.items():
n = pgv_graph.get_node(block_live)
n.attr["label"] = f"{block_live}\n{live_vars}"
n.attr["label"] = live_vars.dot_repr()

pgv_graph.write(f"{component_name}.dot")

Expand Down
5 changes: 4 additions & 1 deletion src/liveness/liveness_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ def _uses_defines_from_instructions(instructions: List[CFGInstruction]) -> Tuple
"""
uses, defines = set(), set()
for instruction in instructions:
uses.update([element for element in instruction.in_args if not element.startswith("0x")])
# For computing the uses, we cannot include variables that have been defined in the same block
uses.update([element for element in instruction.in_args if not element.startswith("0x")
and element not in defines])
defines.update(instruction.out_args)
return uses, defines

Expand All @@ -32,6 +34,7 @@ def __init__(self, basic_block: CFGBlock):
self._block_type = basic_block.get_jump_type()
self._comes_from = basic_block.get_comes_from()
self.uses, self.defines = _uses_defines_from_instructions(basic_block.get_instructions())
self._instructions = basic_block.get_instructions()

# Variables that need to be propagated
self.propagated_variables = self.uses.difference(self.defines)
Expand Down
3 changes: 2 additions & 1 deletion src/parser/cfg_block_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ def get_terminal_blocks(self) -> List[str]:
"""
Terminal blocks are either mainExit and terminal blocks
"""
return [block.block_id for block in self.blocks.values() if block.get_jump_type() in ["mainExit", "terminal"]]
return [block.block_id for block in self.blocks.values() if block.get_jump_type() in
["mainExit", "terminal", "FunctionReturn"]]

def build_spec(self):
"""
Expand Down
5 changes: 4 additions & 1 deletion src/parser/cfg_instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ def get_instruction_representation(self):
instr = outs+self.op+"("+inps+")"

return instr


def dot_repr(self):
return self.get_instruction_representation()

def __repr__(self):
return json.dumps(self.get_as_json())

0 comments on commit e0b6443

Please sign in to comment.