From 6e89c4a2b9249b9d758c1bc47358fdc8f013d376 Mon Sep 17 00:00:00 2001 From: alexcere <48130030+alexcere@users.noreply.github.com> Date: Thu, 18 Jul 2024 17:02:20 +0200 Subject: [PATCH 1/6] Include blocks from functions in liveness analysis --- src/liveness/liveness_analysis.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/liveness/liveness_analysis.py b/src/liveness/liveness_analysis.py index c9b91401..b747f159 100644 --- a/src/liveness/liveness_analysis.py +++ b/src/liveness/liveness_analysis.py @@ -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 @@ -36,15 +37,30 @@ def __repr__(self): 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(block_list) + + # TODO: handle subobjects as well return cfg_info From 859e9e41ea1fb73ee0a117aae28c36920858ff98 Mon Sep 17 00:00:00 2001 From: alexcere <48130030+alexcere@users.noreply.github.com> Date: Thu, 18 Jul 2024 17:20:21 +0200 Subject: [PATCH 2/6] Minor errors in call to functions --- src/analysis/abstract_state.py | 1 + src/liveness/liveness_analysis.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/analysis/abstract_state.py b/src/analysis/abstract_state.py index d407104e..f3e69959 100644 --- a/src/analysis/abstract_state.py +++ b/src/analysis/abstract_state.py @@ -41,6 +41,7 @@ def digraph_from_block_info(block_info: Iterable[AbstractBlockInfo]) -> pgv.AGra """ graph = pgv.AGraph() 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 diff --git a/src/liveness/liveness_analysis.py b/src/liveness/liveness_analysis.py index b747f159..13d6bdd3 100644 --- a/src/liveness/liveness_analysis.py +++ b/src/liveness/liveness_analysis.py @@ -58,7 +58,7 @@ def construct_analysis_info(cfg: CFG): # 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(block_list) + cfg_info[function_name] = construct_analysis_info_from_cfgblocklist(cfg_function.blocks) # TODO: handle subobjects as well return cfg_info From 38fcf0074564f6ab9fab9225d3464a57d417cb77 Mon Sep 17 00:00:00 2001 From: alexcere <48130030+alexcere@users.noreply.github.com> Date: Thu, 18 Jul 2024 17:46:32 +0200 Subject: [PATCH 3/6] Add FunctionReturn blocks to the set of terminal blocks --- src/parser/cfg_block_list.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/parser/cfg_block_list.py b/src/parser/cfg_block_list.py index 1eda8f06..dd7b097a 100644 --- a/src/parser/cfg_block_list.py +++ b/src/parser/cfg_block_list.py @@ -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): """ From 1f068395ef21de6c8703c441f5bf13f77904a851 Mon Sep 17 00:00:00 2001 From: alexcere <48130030+alexcere@users.noreply.github.com> Date: Thu, 18 Jul 2024 18:07:12 +0200 Subject: [PATCH 4/6] Improve dot representation --- src/analysis/abstract_state.py | 2 +- src/liveness/liveness_analysis.py | 8 +++++++- src/liveness/liveness_state.py | 1 + src/parser/cfg_instruction.py | 5 ++++- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/analysis/abstract_state.py b/src/analysis/abstract_state.py index f3e69959..cfb219e3 100644 --- a/src/analysis/abstract_state.py +++ b/src/analysis/abstract_state.py @@ -39,7 +39,7 @@ 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: diff --git a/src/liveness/liveness_analysis.py b/src/liveness/liveness_analysis.py index 13d6bdd3..27f61463 100644 --- a/src/liveness/liveness_analysis.py +++ b/src/liveness/liveness_analysis.py @@ -31,6 +31,12 @@ 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}"] @@ -100,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") diff --git a/src/liveness/liveness_state.py b/src/liveness/liveness_state.py index a4d932b2..3fa31e40 100644 --- a/src/liveness/liveness_state.py +++ b/src/liveness/liveness_state.py @@ -32,6 +32,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) diff --git a/src/parser/cfg_instruction.py b/src/parser/cfg_instruction.py index 8cb572a7..c31fb3d9 100644 --- a/src/parser/cfg_instruction.py +++ b/src/parser/cfg_instruction.py @@ -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()) From 7361f9508b4838a9dbdf57e5d6b195b63d6939dc Mon Sep 17 00:00:00 2001 From: alexcere <48130030+alexcere@users.noreply.github.com> Date: Thu, 18 Jul 2024 19:39:56 +0200 Subject: [PATCH 5/6] Fix computation of uses set --- src/liveness/liveness_state.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/liveness/liveness_state.py b/src/liveness/liveness_state.py index 3fa31e40..50f11f9e 100644 --- a/src/liveness/liveness_state.py +++ b/src/liveness/liveness_state.py @@ -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 From 8a80fdd5b2b7c21fa97999afc73225e1678921e4 Mon Sep 17 00:00:00 2001 From: alexcere <48130030+alexcere@users.noreply.github.com> Date: Thu, 18 Jul 2024 19:40:17 +0200 Subject: [PATCH 6/6] Fix traversal comparison in revisiting block --- src/analysis/fixpoint_analysis.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/analysis/fixpoint_analysis.py b/src/analysis/fixpoint_analysis.py index f5970487..af5476fb 100644 --- a/src/analysis/fixpoint_analysis.py +++ b/src/analysis/fixpoint_analysis.py @@ -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