def prune_unsat_branches(node: c_ast.Node, theory: C99Theory): if type(node) == c_ast.Compound: to_delete = [] for i in node.block_items: if type(i) == c_ast.If: cond_predicate = theory.evaluate_ast(i.cond) if theory.is_sat(cond_predicate): new_context = copy.deepcopy(theory) # uncomment to incorporate the if predicate to the solver #new_context.handle_if(i) # start a new dfs with the augmented context cast_lib.map_dfs(i.iftrue, prune_unsat_branches, [new_context]) else: # delete this branch to_delete.append(i) elif type(i) == c_ast.Assignment: pred = theory.evaluate_ast(i) var_name = i.lvalue.name theory.add_var_predicate(var_name, pred) elif type(i) == c_ast.While: cast_lib.map_dfs(i.stmt, prune_unsat_branches, [theory]) for i in to_delete: node.block_items.remove(i) # break dfs on this branch return False
def prune_unsat_branches(node: c_ast.Node, theory: C99Theory): if type(node) == c_ast.Compound: to_delete = [] for i in node.block_items: if type(i) == c_ast.If: if theory.is_sat(i): new_context = copy.deepcopy(theory) new_context.handle_if(i) # start a new dfs with the augmented context cast_lib.map_dfs(i.iftrue, prune_unsat_branches, [new_context]) else: # delete this branch to_delete.append(i) elif type(i) == c_ast.Assignment: theory.handle_assigment(i) elif type(i) == c_ast.While: cast_lib.map_dfs(i.stmt, prune_unsat_branches, [theory]) for i in to_delete: node.block_items.remove(i) # break dfs on this branch return False
def dead_code_elimination(codeast: c_ast.FileAST, phasevar): # Syntactic tree prune, everything after a phase increment is removed main_while = cast_lib.find_while_node(codeast) cast_lib.map_dfs(main_while, cast_lib.prune_after_phase_increment, [phasevar]) # Construct a theory using definitions and declarations theory = C99Theory(codeast) # Recursively explore the AST tree and cut the unfeasible branches cast_lib.map_dfs(codeast, prune_unsat_branches, [theory])
def dead_code_elimination(codeast: c_ast.FileAST, config): # Syntactic tree prune, everything after a phase increment is removed main_while = cast_lib.find_while_node(codeast) if config is not None and hasattr(config, 'phase'): cast_lib.map_dfs(main_while, cast_lib.prune_after_phase_increment, [config['phase'], config['round']]) # Construct a theory using definitions and declarations theory = C99Theory(codeast) # Recursively explore the AST tree and cut the unfeasible branches cast_lib.map_dfs(codeast, prune_unsat_branches, [theory])
def _phase_unfold(compound: c_ast.Compound, while_body, initial_states, phase_var, final_states): to_delete = [] upons = [n for n in compound if type(n) == c_ast.If] for upon in upons: sat_init_state = None for init in initial_states: cond_predicate = init.evaluate_ast(upon.cond) if init.is_sat(cond_predicate): sat_init_state = init break if sat_init_state is not None: new_context = copy.deepcopy(sat_init_state) path_end = False for n in upon.iftrue: if type(n) == c_ast.Assignment: pred = new_context.evaluate_ast(n) var_name = n.lvalue.name new_context.add_var_predicate(var_name, pred) if cast_lib.is_var_increment(n, phase_var): path_end = True if not path_end: while_body_copy = copy.deepcopy(while_body) cast_lib.map_dfs(upon, cast_lib.insert_node_after_continue, [while_body_copy]) _phase_unfold(upon.iftrue, while_body_copy, [new_context], phase_var, final_states) else: final_states.append(new_context) else: to_delete.append(upon) for upon in to_delete: compound.block_items.remove(upon)
def async_to_sync(async_ast: c_ast.Node, config): """ Given a c99 code in a AST form, returns the corresponding code of its synchronous equivalent program. Notes ----- First step is calculate all code between round variables assigments, then we add all the context needed to reach that piece of code. Entry point if ... if ... Current round Next round * --------------------------------> *----------------------> * A B The code we want to extract is in path B, but we need to collect all the conditions to reach this path, this is obtained collection all c_ast.If in path A. Path A and B can't contain c_ast.Continue nodes. Path B can't contain other round assigments in the middle. """ phase_variable = config['phase'] round_variable = config['round'] labels = config['labels'] # we discard what we won't use main_ast = cast_lib.find_funcdef_node(async_ast, 'main') cast_lib.map_dfs(main_ast, cast_lib.replace_while_with_body, []) cast_lib.filter_nodes(main_ast, remove_declarations) codecfg = cfg.ControlFlowGraph(main_ast) # we search paths between every (monotonically increasing) assigment of round variables paths_between_rounds = paths_between_round_assignments( codecfg, labels, round_variable, phase_variable) # for every protocol's round we calculate all possible paths including its previous context (e.g., ifs conditions) start_node = list(nx.topological_sort(codecfg))[0] complete_paths_by_round = {} for round_label, suffix_paths in paths_between_rounds.items(): complete_paths_by_round[round_label] = [] for suffix_path in suffix_paths: suffix_first_node = list(nx.topological_sort(suffix_path))[0] prefix_paths = get_cfg_paths_between_nodes(codecfg, start_node, suffix_first_node) cp = complete_paths(suffix_path, prefix_paths) complete_paths_by_round[round_label].extend(cp) # the code of a round is the (graph) union of all the complete paths found to belong to that round # the easiest approach is to remove the nodes not included in those paths from the original code using the coord property sync_code = {} for round_label, paths in complete_paths_by_round.items(): round_code_cfg = cfg.ControlFlowGraph() nodes_to_keep = set() for p in paths: for n in p.nodes(): nodes_to_keep.add(str(n.coord)) round_sync_code = copy.deepcopy(main_ast) cast_lib.filter_nodes(round_sync_code, node_coord_not_in_set, nodes_to_keep) sync_code[round_label] = round_sync_code # translate to CompHO compho = {} for round_label, ast_code in sync_code.items(): compho[round_label] = {} ast_send = c_ast.FileAST([copy.deepcopy(ast_code)]) get_compho_send(ast_send) ast_update = c_ast.FileAST([copy.deepcopy(ast_code)]) get_compho_update(ast_update, round_variable, round_label) compho[round_label]['send'] = ast_send compho[round_label]['update'] = ast_update return compho