Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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])
Ejemplo n.º 4
0
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])
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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