def test_boost_example(self): # Graph taken from Figure 1 of # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6), (5, 7), (6, 4)] G = nx.DiGraph(edges) assert nx.dominance_frontiers(G, 0) == { 0: set(), 1: set(), 2: {7}, 3: {7}, 4: {4, 7}, 5: {7}, 6: {4}, 7: set(), } # Test postdominance. result = nx.dominance_frontiers(G.reverse(copy=False), 7) expected = { 0: set(), 1: set(), 2: {1}, 3: {1}, 4: {1, 4}, 5: {1}, 6: {4}, 7: set(), } assert result == expected
def test_missing_immediate_doms(self): # see https://github.com/networkx/networkx/issues/2070 g = nx.DiGraph() edges = [ ("entry_1", "b1"), ("b1", "b2"), ("b2", "b3"), ("b3", "exit"), ("entry_2", "b3"), ] # entry_1 # | # b1 # | # b2 entry_2 # | / # b3 # | # exit g.add_edges_from(edges) # formerly raised KeyError on entry_2 when parsing b3 # because entry_2 does not have immediate doms (no path) nx.dominance_frontiers(g, "entry_1")
def test_boost_example(self): # Graph taken from Figure 1 of # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6), (5, 7), (6, 4)] G = nx.DiGraph(edges) assert_equal(nx.dominance_frontiers(G, 0), { 0: [], 1: [], 2: [7], 3: [7], 4: [7], 5: [7], 6: [4], 7: [] }) # Test postdominance. with nx.utils.reversed(G): assert_equal(nx.dominance_frontiers(G, 7), { 0: [], 1: [], 2: [1], 3: [1], 4: [1], 5: [1], 6: [4], 7: [] })
def test_boost_example(self): # Graph taken from Figure 1 of # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6), (5, 7), (6, 4)] G = nx.DiGraph(edges) assert (nx.dominance_frontiers(G, 0) == { 0: set(), 1: set(), 2: set([7]), 3: set([7]), 4: set([4, 7]), 5: set([7]), 6: set([4]), 7: set() }) # Test postdominance. with nx.utils.reversed(G): assert (nx.dominance_frontiers(G, 7) == { 0: set(), 1: set(), 2: set([1]), 3: set([1]), 4: set([1, 4]), 5: set([1]), 6: set([4]), 7: set() })
def test_missing_immediate_doms(self): # see https://github.com/networkx/networkx/issues/2070 g = nx.DiGraph() edges = [ ('entry_1', 'b1'), ('b1', 'b2'), ('b2', 'b3'), ('b3', 'exit'), ('entry_2', 'b3') ] # entry_1 # | # b1 # | # b2 entry_2 # | / # b3 # | # exit g.add_edges_from(edges) # formerly raised KeyError on entry_2 when parsing b3 # because entry_2 does not have immediate doms (no path) nx.dominance_frontiers(g,'entry_1')
def test_domrel_png(self): # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)] G = nx.DiGraph(edges) assert_equal(nx.dominance_frontiers(G, 1), {1: [], 2: [], 3: [5], 4: [5], 5: [2], 6: []}) # Test postdominance. with nx.utils.reversed(G): assert_equal(nx.dominance_frontiers(G, 6), {1: [], 2: [], 3: [2], 4: [2], 5: [2], 6: []})
def test_boost_example(self): # Graph taken from Figure 1 of # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6), (5, 7), (6, 4)] G = nx.DiGraph(edges) assert_equal(nx.dominance_frontiers(G, 0), {0: set(), 1: set(), 2: set([7]), 3: set([7]), 4: set([4,7]), 5: set([7]), 6: set([4]), 7: set()}) # Test postdominance. with nx.utils.reversed(G): assert_equal(nx.dominance_frontiers(G, 7), {0: set(), 1: set(), 2: set([1]), 3: set([1]), 4: set([1,4]), 5: set([1]), 6: set([4]), 7: set()})
def test_domrel_png(self): # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)] G = nx.DiGraph(edges) assert nx.dominance_frontiers(G, 1) == { 1: set(), 2: {2}, 3: {5}, 4: {5}, 5: {2}, 6: set(), } # Test postdominance. result = nx.dominance_frontiers(G.reverse(copy=False), 6) assert result == {1: set(), 2: {2}, 3: {2}, 4: {2}, 5: {2}, 6: set()}
def test_loops_larger(self): # from # http://ecee.colorado.edu/~waite/Darmstadt/motion.html g = nx.DiGraph() edges = [ ("entry", "exit"), ("entry", "1"), ("1", "2"), ("2", "3"), ("3", "4"), ("4", "5"), ("5", "6"), ("6", "exit"), ("6", "2"), ("5", "3"), ("4", "4"), ] g.add_edges_from(edges) df = nx.dominance_frontiers(g, "entry") answer = { "entry": set(), "1": {"exit"}, "2": {"exit", "2"}, "3": {"exit", "3", "2"}, "4": {"exit", "4", "3", "2"}, "5": {"exit", "3", "2"}, "6": {"exit", "2"}, "exit": set(), } for n in df: assert set(df[n]) == set(answer[n])
def _build_dom_sets(self, graph: nx.DiGraph, gname=''): v_entry = 'virtual_entry' graph.add_edges_from( ((v_entry, node) for node, i in tuple(graph.in_degree) if i == 0)) if v_entry not in graph: err_msg = f'Failed to find an entry to build dominance tree for {gname}' logging.error(err_msg) raise NoEntryForDomTreeError(err_msg) dom_tree = nx.DiGraph() dom_tree.add_nodes_from(graph.nodes) for node, dominator in nx.immediate_dominators(graph, v_entry).items(): dom_tree.add_edge(dominator, node) dom_tree.remove_node(v_entry) dominances = { node: set.union(nx.descendants(dom_tree, node), { node, }) for node in dom_tree.nodes } frontier = nx.dominance_frontiers(graph, v_entry) frontier.pop(v_entry) graph.remove_node(v_entry) return dom_tree, dominances, frontier
def test_discard_issue(self): # https://github.com/networkx/networkx/issues/2071 g = nx.DiGraph() g.add_edges_from([ ("b0", "b1"), ("b1", "b2"), ("b2", "b3"), ("b3", "b1"), ("b1", "b5"), ("b5", "b6"), ("b5", "b8"), ("b6", "b7"), ("b8", "b7"), ("b7", "b3"), ("b3", "b4"), ]) df = nx.dominance_frontiers(g, "b0") assert df == { "b4": set(), "b5": {"b3"}, "b6": {"b7"}, "b7": {"b3"}, "b0": set(), "b1": {"b1"}, "b2": {"b3"}, "b3": {"b1"}, "b8": {"b7"}, }
def test_unreachable(self): n = 5 assert_greater(n, 1) G = nx.path_graph(n, create_using=nx.DiGraph()) assert_equal(nx.dominance_frontiers(G, n // 2), {i: [] for i in range(n // 2, n)})
def test_loops_larger(self): # from # http://ecee.colorado.edu/~waite/Darmstadt/motion.html g = nx.DiGraph() edges = [ ('entry', 'exit'), ('entry', '1'), ('1', '2'), ('2', '3'), ('3', '4'), ('4', '5'), ('5', '6'), ('6', 'exit'), ('6', '2'), ('5', '3'), ('4', '4') ] g.add_edges_from(edges) df = nx.dominance_frontiers(g,'entry') answer = {'entry': set(), '1': set(['exit']), '2': set(['exit', '2']), '3': set(['exit', '3', '2']), '4': set(['exit', '4','3', '2']), '5': set(['exit', '3', '2']), '6': set(['exit', '2']), 'exit': set()} for n in df: assert_equal(set(df[n]),set(answer[n]))
def test_unreachable(self): n = 5 assert n > 1 G = nx.path_graph(n, create_using=nx.DiGraph()) assert (nx.dominance_frontiers( G, n // 2) == {i: set() for i in range(n // 2, n)})
def test_irreducible1(self): # Graph taken from Figure 2 of # K. D. Cooper, T. J. Harvey, and K. Kennedy. # A simple, fast dominance algorithm. # Software Practice & Experience, 4:110, 2001. edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)] G = nx.DiGraph(edges) assert_equal({u: sorted(df) for u, df in nx.dominance_frontiers(G, 5).items()}, {1: [2], 2: [1], 3: [2], 4: [1], 5: []})
def test_irreducible2(self): # Graph taken from Figure 4 of # K. D. Cooper, T. J. Harvey, and K. Kennedy. # A simple, fast dominance algorithm. # Software Practice & Experience, 4:110, 2001. edges = [(1, 2), (2, 1), (2, 3), (3, 2), (4, 2), (4, 3), (5, 1), (6, 4), (6, 5)] G = nx.DiGraph(edges) assert_equal(nx.dominance_frontiers(G, 6), {1: set([2]), 2: set([1, 3]), 3: set([2]), 4: set([2, 3]), 5: set([1]), 6: set([])})
def test_domrel_png(self): # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)] G = nx.DiGraph(edges) assert (nx.dominance_frontiers(G, 1) == { 1: set([]), 2: set([2]), 3: set([5]), 4: set([5]), 5: set([2]), 6: set() }) # Test postdominance. with nx.utils.reversed(G): assert (nx.dominance_frontiers(G, 6) == { 1: set(), 2: set([2]), 3: set([2]), 4: set([2]), 5: set([2]), 6: set() })
def test_domrel_png(self): # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)] G = nx.DiGraph(edges) assert_equal(nx.dominance_frontiers(G, 1), { 1: [], 2: [], 3: [5], 4: [5], 5: [2], 6: [] }) # Test postdominance. with nx.utils.reversed(G): assert_equal(nx.dominance_frontiers(G, 6), { 1: [], 2: [], 3: [2], 4: [2], 5: [2], 6: [] })
def test_irreducible1(self): # Graph taken from Figure 2 of # K. D. Cooper, T. J. Harvey, and K. Kennedy. # A simple, fast dominance algorithm. # Software Practice & Experience, 4:110, 2001. edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)] G = nx.DiGraph(edges) assert ({u: df for u, df in nx.dominance_frontiers(G, 5).items()} == { 1: set([2]), 2: set([1]), 3: set([2]), 4: set([1]), 5: set() })
def test_irreducible2(self): # Graph taken from Figure 4 of # K. D. Cooper, T. J. Harvey, and K. Kennedy. # A simple, fast dominance algorithm. # Software Practice & Experience, 4:110, 2001. edges = [(1, 2), (2, 1), (2, 3), (3, 2), (4, 2), (4, 3), (5, 1), (6, 4), (6, 5)] G = nx.DiGraph(edges) assert (nx.dominance_frontiers(G, 6) == { 1: set([2]), 2: set([1, 3]), 3: set([2]), 4: set([2, 3]), 5: set([1]), 6: set([]) })
def test_irreducible2(self): # Graph taken from Figure 4 of # K. D. Cooper, T. J. Harvey, and K. Kennedy. # A simple, fast dominance algorithm. # Software Practice & Experience, 4:110, 2001. edges = [(1, 2), (2, 1), (2, 3), (3, 2), (4, 2), (4, 3), (5, 1), (6, 4), (6, 5)] G = nx.DiGraph(edges) assert_equal(nx.dominance_frontiers(G, 6), { 1: [2], 2: [1, 3], 3: [2], 4: [2, 3], 5: [1], 6: [] })
def test_irreducible1(self): # Graph taken from Figure 2 of # K. D. Cooper, T. J. Harvey, and K. Kennedy. # A simple, fast dominance algorithm. # Software Practice & Experience, 4:110, 2001. edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)] G = nx.DiGraph(edges) assert_equal( {u: sorted(df) for u, df in nx.dominance_frontiers(G, 5).items()}, { 1: [2], 2: [1], 3: [2], 4: [1], 5: [] })
def phi_function_locations(block_graph, start_block): """ From slide 26 in lecture7.ppt about the Cytron 1991 Efficiently Computing SSA paper Parameters ---------- block_graph : TYPE : nx.DiGraph Holds the node/edge connections from the block_list, where nodes are Basic_Block objects holding all required Instruction_Info objects Returns ------- block_graph : TYPE : nx.DiGraph Holds the node/edge connections from the block_list, where nodes are Basic_Block objects holding all required Instruction_Info objects. Nodes have been updated with Phi functions for specific registers """ dom_dict = nx.dominance_frontiers(block_graph, start_block) for register_number in range(start_block[0].num_regs): work_list = set() ever_on_work_list = set() already_has_phi_func = set() # Get all nodes which assign a value to our target_reg for block in block_graph: if register_number in block.variables_changed_in_block: work_list.add(block) ever_on_work_list = work_list while len(work_list) != 0: check_dom_front_of_block = work_list.pop() for dom_front_node in dom_dict[check_dom_front_of_block]: # Insert at most 1 phi function per node if dom_front_node not in already_has_phi_func: dom_front_node.phi_functions.append(register_number) already_has_phi_func.add(dom_front_node) # Process each node at most once if dom_front_node not in ever_on_work_list: work_list.add(dom_front_node) ever_on_work_list.add(dom_front_node) return block_graph
def build_dominators(self, root: str): """ This builds the requisite dominator structures: dominator tree, immediate dominators, and dominance frontier for each function present in the program. :param root: Name of function to build for. :return: None """ self.frontier[root] = nx.dominance_frontiers( self.program.bb_graph, self.program.functions[root]['entry']) self.idoms[root] = nx.immediate_dominators( self.program.bb_graph, self.program.functions[root]['entry']) self.dominator_tree[root] = defaultdict(lambda: set()) for key, value in self.idoms[root].items(): # Ensure a self dominated node isn't added # This guarantees no infinite iteration if key != value: self.dominator_tree[root][value].add(key)
def test_discard_issue(self): # https://github.com/networkx/networkx/issues/2071 g = nx.DiGraph() g.add_edges_from([('b0', 'b1'), ('b1', 'b2'), ('b2', 'b3'), ('b3', 'b1'), ('b1', 'b5'), ('b5', 'b6'), ('b5', 'b8'), ('b6', 'b7'), ('b8', 'b7'), ('b7', 'b3'), ('b3', 'b4')]) df = nx.dominance_frontiers(g, 'b0') assert df == { 'b4': set(), 'b5': set(['b3']), 'b6': set(['b7']), 'b7': set(['b3']), 'b0': set(), 'b1': set(['b1']), 'b2': set(['b3']), 'b3': set(['b1']), 'b8': set(['b7']) }
def test_discard_issue(self): # https://github.com/networkx/networkx/issues/2071 g = nx.DiGraph() g.add_edges_from([ ('b0','b1'), ('b1', 'b2'), ('b2', 'b3'), ('b3','b1'), ('b1','b5'), ('b5', 'b6'), ('b5', 'b8'), ('b6', 'b7'), ('b8', 'b7'), ('b7', 'b3'), ('b3', 'b4') ] ) df = nx.dominance_frontiers(g, 'b0') assert_equal(df, {'b4': set(), 'b5': set(['b3']), 'b6': set(['b7']), 'b7': set(['b3']), 'b0': set(), 'b1': set(['b1']), 'b2': set(['b3']), 'b3': set(['b1']), 'b8': set(['b7'])})
def createCDG(cfg, clusterId, funcName, pathToFile): # http://staff.cs.upt.ro/~chirila/teaching/upt/c51-pt/aamcij/7113/Fly0145.html # Construction of the control-dependence graph To construct the CDG of a control-flow graph G, # 1. Add a new entry-node r to G, with an edge r to s to the start node s of G (indicating that the surrounding program might enter G) # and an edge r to exit to the exit node of G (indicating that the surrounding program might not execute G at all). cfgModel = nx.DiGraph() cfgModel.add_nodes_from(cfg.nodes(data=True)) edges = map(lambda x: (x[0], x[1]), cfg.edges) cfgModel.add_edges_from(edges) lasts = filter(lambda x: len(list(cfg.succ[x])) == 0, cfg.nodes) en = 'BB_entry' + clusterId ex = 'BB_exit' + clusterId cfgModel.add_node(ex, shape="record", funcName=funcName, file=pathToFile, label="") for l in lasts: cfgModel.add_edge(l, ex) cfgModel.add_edge(en, ex) # nx.nx_agraph.view_pygraphviz(cfgModel, prog='fdp') # 2. Let G' be the reverse control-flow graph that has an edge y to x whenever G has an edge x to y;the start node of G' corresponds to the exit node of G. rev_cfg = cfgModel.reverse() # 3. Construct the dominator tree of G' (its root corresponds to the exit node of G). # 4. Calculate the dominance frontiers DF_G' of the nodes of G'. df = nx.dominance_frontiers(rev_cfg, ex) # print df # 5. The CDG has edge x to y whenever x in DF_G'[y]. cdg = nx.DiGraph() # control dependence graph cdg.add_nodes_from(cfg.nodes(data=True)) for n, nodes in df.items(): for m in nodes: cdg.add_edge(m, n) cdg.add_edge(en, ex) # might not be neccessary # nx.nx_agraph.view_pygraphviz(cdg, prog='fdp') return cdg
def compare_dominance_frontiers(self, start, end, edges): G = nx.DiGraph(edges) dom_frontier_nx = sorted( (u, sorted(df)) for u, df in nx.dominance_frontiers(G, start).items()) cfg = ControlFlowGraph.fromEdgeList(start, end, edges) control_nodes = findControlNodes(cfg, reverse=True) control_dependents = {k: [] for k in cfg.nodes} for controller in control_nodes: for controllee in control_nodes[controller]: if controllee == '': continue control_dependents[controllee].append(controller) # print(dom_frontier_nx) # print(control_dependents) for node, frontiers in dom_frontier_nx: self.assertListEqual(sorted(control_dependents[node]), sorted(frontiers), "node: {}".format(node))
def test_loops_larger(self): # from # http://ecee.colorado.edu/~waite/Darmstadt/motion.html g = nx.DiGraph() edges = [('entry', 'exit'), ('entry', '1'), ('1', '2'), ('2', '3'), ('3', '4'), ('4', '5'), ('5', '6'), ('6', 'exit'), ('6', '2'), ('5', '3'), ('4', '4')] g.add_edges_from(edges) df = nx.dominance_frontiers(g, 'entry') answer = { 'entry': set(), '1': set(['exit']), '2': set(['exit', '2']), '3': set(['exit', '3', '2']), '4': set(['exit', '4', '3', '2']), '5': set(['exit', '3', '2']), '6': set(['exit', '2']), 'exit': set() } for n in df: assert set(df[n]) == set(answer[n])
def test_loop(self): g = nx.DiGraph() g.add_edges_from([("a", "b"), ("b", "c"), ("b", "a")]) df = nx.dominance_frontiers(g, "a") assert df == {"a": set(), "b": set(), "c": set()}
def test_singleton(self): G = nx.DiGraph() G.add_node(0) assert_equal(nx.dominance_frontiers(G, 0), {0: []}) G.add_edge(0, 0) assert_equal(nx.dominance_frontiers(G, 0), {0: []})
def test_loop(self): g = nx.DiGraph() g.add_edges_from([('a', 'b'), ('b', 'c'), ('b', 'a')]) df = nx.dominance_frontiers(g, 'a') assert df == {'a': set(), 'b': set(), 'c': set()}
def test_cycle(self): n = 5 G = nx.cycle_graph(n, create_using=nx.DiGraph()) assert_equal(nx.dominance_frontiers(G, 0), dict((i, set()) for i in range(n)))
def test_path(self): n = 5 G = nx.path_graph(n, create_using=nx.DiGraph()) assert_equal(nx.dominance_frontiers(G, 0), {i: set() for i in range(n)})
def test_cycle(self): n = 5 G = nx.cycle_graph(n, create_using=nx.DiGraph()) assert_equal(nx.dominance_frontiers(G, 0), {i: set() for i in range(n)})
def test_path(self): n = 5 G = nx.path_graph(n, create_using=nx.DiGraph()) assert_equal(nx.dominance_frontiers(G, 0), {i: [] for i in range(n)})
def test_unreachable(self): n = 5 assert_greater(n, 1) G = nx.path_graph(n, create_using=nx.DiGraph()) assert_equal(nx.dominance_frontiers(G, n // 2), {i: set() for i in range(n // 2, n)})
def test_cycle(self): n = 5 G = nx.cycle_graph(n, create_using=nx.DiGraph()) assert (nx.dominance_frontiers(G, 0) == {i: set() for i in range(n)})
def test_singleton(self): G = nx.DiGraph() G.add_node(0) assert nx.dominance_frontiers(G, 0) == {0: set()} G.add_edge(0, 0) assert nx.dominance_frontiers(G, 0) == {0: set()}
def test_singleton(self): G = nx.DiGraph() G.add_node(0) assert_equal(nx.dominance_frontiers(G, 0), {0: set()}) G.add_edge(0, 0) assert_equal(nx.dominance_frontiers(G, 0), {0: set()})
def test_loop(self): g = nx.DiGraph() g.add_edges_from([('a','b'),('b','c'),('b','a')]) df = nx.dominance_frontiers(g, 'a') assert_equal(df, {'a': set(), 'b': set(), 'c': set()})