def find_direct_dominated_preds(blocks, dominator, dom_frontier_node): preds = {successors(block[-1]): name for name, block in blocks.items()} succ = {name: successors(block[-1]) for name, block in blocks.items()} dom = get_dom(succ, list(blocks.keys())[0]) results = set() for pred in preds[dom_frontier_node]: if pred in dom[dominator]: results.add(pred) return results
def cfg_dot(bril, verbose): """Generate a GraphViz "dot" file showing the control flow graph for a Bril program. In `verbose` mode, include the instructions in the vertices. """ for func in bril['functions']: print('digraph {} {{'.format(func['name'])) blocks = block_map(form_blocks(func['instrs'])) # Insert terminators into blocks that don't have them. add_terminators(blocks) # Add the vertices. for name, block in blocks.items(): if verbose: import briltxt print(r' {} [shape=box, xlabel="{}", label="{}\l"];'.format( name, name, r'\l'.join(briltxt.instr_to_string(i) for i in block), )) else: print(' {};'.format(name)) # Add the control-flow edges. for i, (name, block) in enumerate(blocks.items()): succ = successors(block[-1]) for label in succ: print(' {} -> {};'.format(name, label)) print('}')
def convert_to_ssa(func): # return labeled blocks blocks = block_map(form_blocks(func['instrs'])) # add entry block if required add_entry(blocks) # add terminators to block if required add_terminators(blocks) # get the successor of each block succ = {name: successors(block[-1]) for name, block in blocks.items()} # get the predecessor of each block pred = map_inv(succ) # get dominator of each block dom = get_dom(succ, list(blocks.keys())[0]) # get dominate frontier of each block df = dom_fronts(dom, succ) # varaible map to block label defs = def_blocks(blocks) # get function type types = get_types(func) # get argument name arg_names = {a['name'] for a in func['args']} if 'args' in func else set() # find phi nodes phis = get_phis(blocks, df, defs) # rename variables phi_args, phi_dests = ssa_rename(blocks, phis, succ, dom_tree(dom), arg_names) # inserte phi nodes insert_phis(blocks, phi_args, phi_dests, types) # rebuild the updated blocks func['instrs'] = reassemble(blocks)
def print_dom(bril, mode): for func in bril['functions']: # return labeled blocks blocks = block_map(form_blocks(func['instrs'])) #for name, block in blocks.items(): # print(str(name)+":"+str(block)) # add entry block if required add_entry(blocks) # add terminators to every block if required add_terminators(blocks) # get the successor of each block succ = {name: successors(block[-1]) for name, block in blocks.items()} #for name, block in succ.items(): # print(str(name)+": "+str(block)) dom = get_dom(succ, list(blocks.keys())[0]) if mode == 'front': res = dom_fronts(dom, succ) elif mode == 'tree': res = dom_tree(dom) else: res = dom # Format as JSON for stable output. print(json.dumps( {k: sorted(list(v)) for k, v in res.items()}, indent=2, sort_keys=True, ))
def get_dom_dict(bril): for func in bril['functions']: blocks = block_map(form_blocks(func['instrs'])) add_terminators(blocks) succ = {name: successors(block[-1]) for name, block in blocks.items()} dom = get_dom(succ, list(blocks.keys())[0]) return dom
def dfs_postorder(cfg, x): global post_max visit[x] = True for y in cfg.successors(x): if visit.get(y, None) is None: dfs_postorder(cfg, y) post_max += 1 post_n[post_max] = x post_i[x] = post_max
def get_closest(cfg, node, nodes): if len(nodes) == 1: return nodes.pop() min = 9000 indx = post_i[node] closest = None for n in nodes: i = indx - post_i[n] if len(cfg.successors(n)) == 1: return n if i < min: min = i closest = n return closest
def print_dom(bril): for func in bril['functions']: blocks = block_map(form_blocks(func['instrs'])) add_terminators(blocks) succ = {name: successors(block[-1]) for name, block in blocks.items()} dom = get_dom(succ, list(blocks.keys())[0]) # Format as JSON for stable output. print( json.dumps( {k: sorted(list(v)) for k, v in dom.items()}, indent=2, sort_keys=True, ))
def func_to_ssa(func): blocks = block_map(form_blocks(func['instrs'])) add_entry(blocks) add_terminators(blocks) succ = {name: successors(block[-1]) for name, block in blocks.items()} dom = get_dom(succ, list(blocks.keys())[0]) df = dom_fronts(dom, succ) defs = def_blocks(blocks) types = get_types(func) arg_names = {a['name'] for a in func['args']} if 'args' in func else set() phis = get_phis(blocks, df, defs) phi_args, phi_dests = ssa_rename(blocks, phis, succ, dom_tree(dom), arg_names) insert_phis(blocks, phi_args, phi_dests, types) func['instrs'] = reassemble(blocks)
def print_dom(bril, mode): for func in bril['functions']: blocks = block_map(form_blocks(func['instrs'])) add_entry(blocks) add_terminators(blocks) succ = {name: successors(block[-1]) for name, block in blocks.items()} dom = get_dom(succ, list(blocks.keys())[0]) if mode == 'front': res = dom_fronts(dom, succ) elif mode == 'tree': res = dom_tree(dom) else: res = dom # Format as JSON for stable output. print(json.dumps( {k: sorted(list(v)) for k, v in res.items()}, indent=2, sort_keys=True, ))
def form_cfg(bril, verbose): """Generate a GraphViz "dot" file showing the control flow graph for a Bril program. In `verbose` mode, include the instructions in the vertices. """ cfg = {} txt = open("update.bril", "w+") txt.write('main { \n') for func in bril['functions']: blocks = block_map(form_blocks(func['instrs'])) # Insert terminators into blocks that don't have them. add_terminators(blocks) # Add the control-flow edges. for i, (name, block) in enumerate(blocks.items()): if verbose: import vriltxt block_name = r' {} [shape=box, xlabel="{}", label="{}\l"];'.format( name, name, r'\l'.join(vriltxt.instr_to_string(i) for i in block), ) inbril = '{}:\n{};\n'.format( name, ';\n'.join(vriltxt.instr_to_string(i) for i in block)) else: block_name = '{}'.format(name) edges = [] succ = successors(block[-1]) for label in succ: edges.append('{}'.format(label)) cfg.update({block_name: edges}) txt.write(inbril) print_cfg(cfg) draw_cfg(cfg) txt.write('}\n') txt.close()
def analyze(cfg): entry = get_entry_node(cfg) global CT_nodes CT_nodes = set(cfg.nodes()) while True: global post_n global post_n global visit global post_max global post_ctr post_n = {} # map of Integer to Node post_i = {} # map of Node to Integer visit = {} # map of node to boolean post_max = 0 post_ctr = 1 old_size = len(cfg.nodes()) dfs_postorder(cfg, entry) while len(cfg.nodes()) > 1 and post_ctr <= post_max: n = post_n[post_ctr] # locate an acycic region if present node_set = set() ntype = acyclic_region_type(cfg, n, node_set) if ntype is not None: p = reduce_nodes(cfg, ntype, node_set) if entry in node_set: entry = p else: # locate a cyclic region, if present calculate_dominators(cfg, entry) reach_under = set() for m in cfg.nodes_iter(): if n in cfg.successors(m) and n in dominators[m]: reach_under.add(m) m = get_closest(cfg, n, reach_under) ntype = None if m is not None: reach_under = get_loop_nodes(cfg, n, m) exit_edge = False if len(reach_under) > 2: to_remove = [] to_add = [] for r in reach_under: if r == n or r == m: continue for s in cfg.successors(r): # identify a Continue if s == n: new = reduce_nodes(cfg, "Continue", set([r]), s) to_remove.append(r) to_add.append(new) break # Identify a Break if s not in reach_under and s not in to_add: new = reduce_nodes(cfg, "Break", set([r]), s) to_remove.append(r) to_add.append(new) break for r in to_remove: reach_under.remove(r) for a in to_add: reach_under.add(a) #if not exit_edge: ntype = cyclic_region_type(cfg, n, m, reach_under) if ntype is not None: p = reduce_nodes(cfg, ntype, reach_under) if entry in reach_under: entry = p else: post_ctr += 1 new_size = len(cfg.nodes()) if new_size == 1 or new_size == old_size: break return CT_nodes, CT_edges
def acyclic_region_type(cfg, node, nset): # check for a Block containing node n = node p = True s = len(cfg.successors(n)) == 1 while p and s: nset.add(n) n = cfg.successors(n)[0] p = len(cfg.predecessors(n)) == 1 s = len(cfg.successors(n)) == 1 if p and len(cfg.successors(n)) == 0: nset.add(n) n = node p = len(cfg.predecessors(n)) == 1 s = len(cfg.successors(n)) < 2 while p and s: nset.add(n) n = cfg.predecessors(n)[0] p = len(cfg.predecessors(n)) == 1 s = len(cfg.successors(n)) == 1 if s: nset.add(n) node = n if len(nset) >= 2: return "Block" elif len(cfg.successors(node)) == 2: succ0 = cfg.successors(node)[0] succ1 = cfg.successors(node)[1] # check for an IfThenElse if cfg.in_degree(succ0) == 1 and cfg.out_degree( succ0) == 1 and cfg.in_degree(succ1) == 1 and cfg.out_degree( succ1) == 1: grandchild0 = cfg.successors(succ0)[0] grandchild1 = cfg.successors(succ1)[0] if grandchild0 == grandchild1: nset.add(node) nset.add(succ0) nset.add(succ1) return "IfThenElse" # check for an IfThen elif cfg.in_degree(succ0) == 1 and cfg.out_degree( succ0) == 1 and cfg.in_degree(succ1) == 2 and cfg.successors( succ0)[0] == succ1: nset.add(node) nset.add(succ0) return "IfThen" elif cfg.in_degree(succ1) == 1 and cfg.out_degree( succ1) == 1 and cfg.in_degree(succ0) == 2 and cfg.successors( succ1)[0] == succ0: nset.add(node) nset.add(succ1) return "IfThen" # other cases (IfThen, Switch) if . . . else: return None
def dom_frontier(blocks): succ = {name: successors(block[-1]) for name, block in blocks.items()} dom = get_dom(succ, list(blocks.keys())[0]) return dom_fronts(dom, succ)