def test_inconsistent_merge_branch(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('let x, y := a(P)') b = G.make_node('branch x') c = G.make_node('branch y') d = G.make_node('let P := d(P)') e = G.make_node('let P := e(P)') f = G.make_node('let P := f(P)') g = G.make_node('let P := g(P)') h = G.make_node('let P := h(P)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(b, c, index=0) G.make_edge(b, d, index=1) G.make_edge(c, e, index=0) G.make_edge(c, f, index=1) G.make_edge(d, g) G.make_edge(e, g) G.make_edge(f, h) G.make_edge(g, h) G.make_edge(h, exit) rvsdg = cfg2rvsdg.convert(G) rvsdg.normalize() ref0 = self._inconsistent_merge_branch_refgraph(0) ref1 = self._inconsistent_merge_branch_refgraph(1) #rvsdg_view.show(rvsdg) #rvsdg_view.show(ref1) self.assertTrue(rvsdg == ref0 or rvsdg == ref1)
def _splice_off_cfg(cfg, entry, exit): new_cfg = cfg_model.cfg() assert not entry.incoming assert not exit.outgoing nodes = set([exit]) def transfer(node): nodes.add(node) cfg_algorithm.visit([entry], [exit], transfer) for node in nodes: node.cfg = new_cfg cfg.nodes.remove(node) new_cfg.nodes.add(node) assert (e.origin in nodes for e in node.incoming) assert (e.target in nodes for e in node.outgoing) for e in node.outgoing: assert e.target in nodes del cfg.edges[(e.origin, e.target)] new_cfg.edges[(e.origin, e.target)] = e cfg.entries.remove(entry) new_cfg.entries.add(entry) cfg.exits.remove(exit) new_cfg.exits.add(exit) #cfg._check() #new_cfg._check() return new_cfg
def test_nested_merge_branch(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('let x, y := a(P)') b = G.make_node('branch x') c = G.make_node('branch y') d = G.make_node('let P := d(P)') e = G.make_node('let P := e(P)') f = G.make_node('let P := f(P)') g = G.make_node('let P := g(P)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(b, c, index=0) G.make_edge(b, d, index=1) G.make_edge(c, e, index=0) G.make_edge(c, f, index=1) G.make_edge(d, g) G.make_edge(e, g) G.make_edge(f, g) G.make_edge(g, exit) rvsdg = cfg2rvsdg.convert(G) rvsdg.normalize()
def test_acyclic_simple(self): # graph consisting of a single node, no branches G = cfg_model.cfg() G.make_node('let a := 0') newG = cfg2cfg.regularize_cfg_acyclic(G) self.assertTrue(cfg_algorithm.equivalent(G, newG))
def test_nico1(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) n0 = G.make_node('let v1, v2, v3, v4, v5, v6 := f(P)') n1 = G.make_node('branch v1') n2 = G.make_node('let v2 := 2') n3 = G.make_node('branch v3') n4 = G.make_node('let v4 := 4') n5 = G.make_node('let v5 := 5') n6 = G.make_node('let v6 := 6') n7 = G.make_node('let P := g(v1, v2, v3, v4, v5, v6, P)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, n0) G.make_edge(n0, n1) G.make_edge(n1, n2, index=0) G.make_edge(n1, n3, index=1) G.make_edge(n2, n4) G.make_edge(n3, n4, index=0) G.make_edge(n3, n5, index=1) G.make_edge(n4, n6) G.make_edge(n5, n6) G.make_edge(n6, n7) G.make_edge(n7, exit) #cfg_view.show(G) rvsdg = cfg2rvsdg.convert(G) rvsdg.normalize()
def _splice_off_cfg(cfg, nodes): new_cfg = cfg_model.cfg() for node in nodes: for e in tuple(node.incoming): if e.origin not in nodes: e.remove() for e in tuple(node.outgoing): if e.target not in nodes: e.remove() if not node.incoming: cfg.entries.remove(node) new_cfg.entries.add(node) if not node.outgoing: cfg.exits.remove(node) new_cfg.exits.add(node) node.cfg = new_cfg cfg.nodes.remove(node) new_cfg.nodes.add(node) for e in node.outgoing: assert e.target in nodes del cfg.edges[(e.origin, e.target)] new_cfg.edges[(e.origin, e.target)] = e #cfg._check() #new_cfg._check() return new_cfg
def test_visit(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node(stmt='let p, P := a(P)') head = G.make_node(stmt='branch p') b = G.make_node('let P := b(P)') c = G.make_node('let p, P := c(P)') tail = G.make_node('branch p') d = G.make_node('let P := d(P)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, head) G.make_edge(head, b) G.make_edge(head, c, index=1) G.make_edge(b, tail) G.make_edge(c, tail) G.make_edge(tail, head) G.make_edge(tail, d, index=1) G.make_edge(d, exit) visited = set() cfg_algorithm.visit((entry, ), (exit, ), lambda x: visited.add(x)) self.assertEqual(visited, set((entry, a, head, b, c, tail, d))) visited = set() cfg_algorithm.visit((head, ), (tail, ), lambda x: visited.add(x)) self.assertEqual(visited, set((head, b, c)))
def test_inconsistent_merge_vardef(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('let v := a(P)') b = G.make_node('branch v') c = G.make_node('let w := b(P)') d = G.make_node('branch w') e = G.make_node('let P := e(P)') f = G.make_node('let P := f(P)') e2 = G.make_node(stmts.let_stmt(('$p', ), stmts.parse_expr('0'))) f2 = G.make_node(stmts.let_stmt(('$p', ), stmts.parse_expr('1'))) exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(b, c, index=0) G.make_edge(b, f, index=1) G.make_edge(c, d) G.make_edge(d, e, index=0) G.make_edge(d, f, index=1) G.make_edge(e, e2) G.make_edge(f, f2) G.make_edge(e2, exit) G.make_edge(f2, exit) #cfg_view.show(G) rvsdg = cfg2rvsdg.convert(G, ('P', ), ('P', '$p'), ('P', '$p'))
def test_acyclic_inconsistent_nested_branches(self): def refG(pred): invpred = 1 - pred G = cfg_model.cfg() a = G.make_node('branch p') b = G.make_node('branch p') c = G.make_node('let c := 0') letp_c = G.make_node( stmts.let_stmt(('$p', ), stmts.parse_expr(str(pred)))) letp_d = G.make_node( stmts.let_stmt(('$p', ), stmts.parse_expr(str(pred)))) letp_e = G.make_node( stmts.let_stmt(('$p', ), stmts.parse_expr(str(invpred)))) n = G.make_node(stmts.null_stmt()) d = G.make_node('let d := 0') e = G.make_node('let e := 0') rebranch = G.make_node(stmts.branch_stmt(stmts.var_expr('$p'))) f = G.make_node('let f := 0') empty = G.make_node(stmts.null_stmt()) g = G.make_node('let g := 0') G.make_edge(a, b, 0) G.make_edge(a, c, 1) G.make_edge(b, d, 0) G.make_edge(b, e, 1) G.make_edge(c, letp_c) G.make_edge(d, letp_d) G.make_edge(e, letp_e) G.make_edge(letp_d, n) G.make_edge(letp_e, n) G.make_edge(letp_c, rebranch) G.make_edge(n, rebranch) G.make_edge(rebranch, f, pred) G.make_edge(rebranch, empty, invpred) G.make_edge(f, g) G.make_edge(empty, g) return G G = cfg_model.cfg() a = G.make_node('branch p') b = G.make_node('branch p') c = G.make_node('let c := 0') d = G.make_node('let d := 0') e = G.make_node('let e := 0') f = G.make_node('let f := 0') g = G.make_node('let g := 0') G.make_edge(a, b, 0) G.make_edge(a, c, 1) G.make_edge(b, d, 0) G.make_edge(b, e, 1) G.make_edge(c, f) G.make_edge(d, f) G.make_edge(e, g) G.make_edge(f, g) newG = cfg2cfg.regularize_cfg_acyclic(G) self.assertTrue( cfg_algorithm.equivalent(refG(1), newG) or cfg_algorithm.equivalent(refG(0), newG))
def refG(): cfg = cfg_model.cfg() entry = cfg.make_node(stmts.null_stmt()) l = cfg.make_node('let v3 := sub(v1, v2)') exit = cfg.make_node(stmts.null_stmt()) cfg.make_edge(entry, l) cfg.make_edge(l, exit) return cfg
def __init__(self, rvsdg): self.rvsdg = rvsdg self.cfg = cfg_model.cfg() self.entry = self.cfg.make_node(stmts.null_stmt()) self.exit= self.cfg.make_node(stmts.null_stmt()) self.var_mapping = ssa_mapping() self.node_mapping = {} self.extra_edges = {}
def test_acyclic_linear(self): # graph consisting of a linear node, no branches G = cfg_model.cfg() a = G.make_node('let a := 0') b = G.make_node('let b := 0') c = G.make_node('let c := 0') G.make_edge(a, b) G.make_edge(b, c) newG = cfg2cfg.regularize_cfg_acyclic(G) self.assertTrue(cfg_algorithm.equivalent(G, newG))
def test_strongly_connected_selfloop(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('branch p') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, a, index=1) G.make_edge(a, exit, index=0) clusters = cfg_algorithm.strongly_connected(G) self.assertEqual(clusters, [set((a, ))])
def test_acyclic_consistent_branch(self): # graph consisting of a single consistent branch G = cfg_model.cfg() a = G.make_node('branch p') b = G.make_node('let b := 0') c = G.make_node('let c := 0') d = G.make_node('let d := 0') G.make_edge(a, b, 0) G.make_edge(a, c, 1) G.make_edge(b, d) G.make_edge(c, d) newG = cfg2cfg.regularize_cfg_acyclic(G) self.assertTrue(cfg_algorithm.equivalent(G, newG))
def refG(): cfg = cfg_model.cfg() entry = cfg.make_node(stmts.null_stmt()) a = cfg.make_node('let v1, z := dec(v1)') b = cfg.make_node('let v2 := sqr(v2)') c = cfg.make_node('branch z') exit = cfg.make_node(stmts.null_stmt()) cfg.make_edge(entry, a) cfg.make_edge(a, b) cfg.make_edge(b, c) cfg.make_edge(c, a, index=1) cfg.make_edge(c, exit, index=0) return cfg
def test_pseudo_branch(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('let p := a(P)') b = G.make_node('branch p') c = G.make_node('let P := C(P)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(b, c) G.make_edge(c, exit) rvsdg = cfg2rvsdg.convert(G)
def test_empty_branch(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('let p := a(P)') b = G.make_node('branch p') c = G.make_node('let P := c(P)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(b, c, index=0) G.make_edge(b, exit, index=1) G.make_edge(c, exit) rvsdg = cfg2rvsdg.convert(G) rvsdg.normalize()
def refG(): cfg = cfg_model.cfg() entry = cfg.make_node(stmts.null_stmt()) c = cfg.make_node('let r := cmp(v1, v2)') b = cfg.make_node('branch r') alt1 = cfg.make_node('let v3 := add(v1, v2)') alt2 = cfg.make_node('let v3 := sub(v1, v2)') exit = cfg.make_node(stmts.null_stmt()) cfg.make_edge(entry, c) cfg.make_edge(c, b) cfg.make_edge(b, alt1, index=0) cfg.make_edge(b, alt2, index=1) cfg.make_edge(alt1, exit) cfg.make_edge(alt2, exit) return cfg
def test_empty_branch_fail(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('let v := a(P)') b = G.make_node('branch v') c = G.make_node('let x := 0') d = G.make_node('let w := d(P)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(b, d, index=0) G.make_edge(b, c, index=1) G.make_edge(c, d) G.make_edge(d, exit) # Test is considered to succeed if w is indeed defined at end # of region, no need to explicitly add expectations here. rvsdg = cfg2rvsdg.convert(G, ('P', ), ('P', 'w'), ('P', 'w'))
def test_linear(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('let P := a(P)') b = G.make_node('let x := 1') c = G.make_node('let y, z := 2, 3') d = G.make_node('let P := c(P, x, y, z)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(b, c) G.make_edge(c, d) G.make_edge(d, exit) rvsdg = cfg2rvsdg.convert(G) rvsdg.normalize() ref = self._linear_refgraph() self.assertEquals(rvsdg, ref)
def test_strongly_connected1(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('branch a') b = G.make_node('let P := b(P)') c = G.make_node('branch c') d = G.make_node('let P := d(P)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(a, c, index=1) G.make_edge(b, c) G.make_edge(c, b) G.make_edge(c, d, index=1) G.make_edge(d, exit) clusters = cfg_algorithm.strongly_connected(G) self.assertEqual(clusters, [set((b, c))])
def _pseudo_loop_ref_graph(self, pred, dummy_predicate=False): invpred = 1 - pred G = cfg_model.cfg() entry = G.make_node('let v := a(P)') a = G.make_node('branch v') b = G.make_node('let P := b(P)') if dummy_predicate: bp = G.make_node( stmts.let_stmt(('$p', '$x'), stmts.parse_expr('%d,-1' % invpred))) else: bp = G.make_node( stmts.let_stmt(('$p', ), stmts.parse_expr('%d' % invpred))) c = G.make_node( stmts.let_stmt(( '$p', '$x', ), stmts.parse_expr('%d, 0' % pred))) d = G.make_node( stmts.let_stmt(( '$p', '$x', ), stmts.parse_expr('%d, 1' % pred))) rebranch = G.make_node(stmts.branch_stmt(stmts.var_expr('$p'))) e = G.make_node( stmts.let_stmt(('P', ), stmts.call_expr('e', (stmts.var_expr('$x'), )))) f = G.make_node(stmts.let_stmt(('$p', ), stmts.parse_expr('0'))) g = G.make_node(stmts.let_stmt(('$p', ), stmts.parse_expr('1'))) exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b, 0) G.make_edge(a, c, 1) G.make_edge(a, d, 2) G.make_edge(b, bp) G.make_edge(bp, rebranch) G.make_edge(c, rebranch) G.make_edge(d, rebranch) G.make_edge(rebranch, e, pred) G.make_edge(rebranch, f, invpred) G.make_edge(e, g) G.make_edge(f, exit) G.make_edge(g, exit) return G
def test_acyclic_break_join(self): # graph consisting of two nested branches, but the three # paths opened up by the two branches are joined into a single # node; need to insert a "null" stmt to strictly join the # inner nested branch, but no new branch is required def refG(): G = cfg_model.cfg() n = G.make_node('branch p') n1 = G.make_node('branch p') n2 = G.make_node('let c := 0') n11 = G.make_node('let d := 0') n12 = G.make_node('let e := 0') n1c = G.make_node(stmts.null_stmt()) nc = G.make_node('let g := 0') G.make_edge(n, n1, 0) G.make_edge(n, n2, 1) G.make_edge(n1, n11, 0) G.make_edge(n1, n12, 1) G.make_edge(n11, n1c) G.make_edge(n12, n1c) G.make_edge(n1c, nc) G.make_edge(n2, nc) return G G = cfg_model.cfg() n = G.make_node('branch p') n1 = G.make_node('branch p') n2 = G.make_node('let c := 0') n11 = G.make_node('let d := 0') n12 = G.make_node('let e := 0') nc = G.make_node('let g := 0') G.make_edge(n, n1, 0) G.make_edge(n, n2, 1) G.make_edge(n1, n11, 0) G.make_edge(n1, n12, 1) G.make_edge(n11, nc) G.make_edge(n12, nc) G.make_edge(n2, nc) newG = cfg2cfg.regularize_cfg_acyclic(G) self.assertTrue(cfg_algorithm.equivalent(refG(), newG))
def refG(): cfg = cfg_model.cfg() entry = cfg.make_node(stmts.null_stmt()) a = cfg.make_node('let v2 := sqr(v2)') b = cfg.make_node('let c := cmp(v1, v2)') c = cfg.make_node('branch c') d = cfg.make_node('let r:= mov(v1)') e = cfg.make_node('let r:= mov(v2)') exit = cfg.make_node(stmts.null_stmt()) cfg.make_edge(entry, a) cfg.make_edge(a, b) cfg.make_edge(b, c) cfg.make_edge(c, d, index=0) cfg.make_edge(c, a, index=1) cfg.make_edge(c, e, index=2) cfg.make_edge(d, exit) cfg.make_edge(e, exit) return cfg
def test_simple_branch(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('let p := a(P)') b = G.make_node('branch p') c = G.make_node('let P := c(P)') d = G.make_node('let P := d(P)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(b, c, index=0) G.make_edge(b, d, index=1) G.make_edge(c, exit) G.make_edge(d, exit) rvsdg = cfg2rvsdg.convert(G) rvsdg.normalize() ref = self._simple_branch_refgraph() self.assertEquals(rvsdg, ref)
def refG(pred): invpred = 1 - pred G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('let v := a(P)') b = G.make_node('branch v') c = G.make_node('let w := b(P)') d = G.make_node('branch w') e = G.make_node('let P := e(P)') f = G.make_node('let P := f(P)') e2 = G.make_node(stmts.let_stmt(('$r', ), stmts.parse_expr('0'))) f2 = G.make_node(stmts.let_stmt(('$r', ), stmts.parse_expr('1'))) exit = G.make_node(stmts.null_stmt()) letp_1 = G.make_node( stmts.let_stmt(('$p', ), stmts.parse_expr(str(pred)))) letp_2 = G.make_node( stmts.let_stmt(('$p', ), stmts.parse_expr(str(pred)))) letp_3 = G.make_node( stmts.let_stmt(('$p', ), stmts.parse_expr(str(invpred)))) null_23 = G.make_node(stmts.null_stmt()) branchp = G.make_node(stmts.branch_stmt(stmts.var_expr('$p'))) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(b, c, index=0) G.make_edge(b, letp_1, index=1) G.make_edge(letp_1, branchp) G.make_edge(c, d) G.make_edge(d, e, index=0) G.make_edge(e, letp_3) G.make_edge(d, letp_2, index=1) G.make_edge(letp_2, null_23) G.make_edge(letp_3, null_23) G.make_edge(null_23, branchp) G.make_edge(branchp, f, pred) G.make_edge(f, f2) G.make_edge(f2, exit) G.make_edge(branchp, e2, invpred) G.make_edge(e2, exit) return G
def refG(): G = cfg_model.cfg() n = G.make_node('branch p') n1 = G.make_node('branch p') n2 = G.make_node('let c := 0') n11 = G.make_node('let d := 0') n12 = G.make_node('let e := 0') n1c = G.make_node(stmts.null_stmt()) nc = G.make_node('let g := 0') G.make_edge(n, n1, 0) G.make_edge(n, n2, 1) G.make_edge(n1, n11, 0) G.make_edge(n1, n12, 1) G.make_edge(n11, n1c) G.make_edge(n12, n1c) G.make_edge(n1c, nc) G.make_edge(n2, nc) return G
def regularize_cfg_acyclic(cfg, insert_dummy_predicate_assignments=False): head, branch_cfgs, tail = acyclic_cfg_branch_xformed_partition( cfg, insert_dummy_predicate_assignments) new_cfg = cfg_model.cfg() _, (head_exit, ) = new_cfg.insert_from(head) if tail.nodes: (tail_entry, ), _ = new_cfg.insert_from( regularize_cfg_acyclic(tail, insert_dummy_predicate_assignments)) else: tail_entry = None for branch_index, branch_cfg in branch_cfgs: (branch_entry, ), (branch_exit, ), = new_cfg.insert_from( regularize_cfg_acyclic(branch_cfg, insert_dummy_predicate_assignments)) new_cfg.make_edge(head_exit, branch_entry, branch_index) if tail_entry: new_cfg.make_edge(branch_exit, tail_entry) return new_cfg
def test_simple_loop(self): G = cfg_model.cfg() entry = G.make_node(stmts.null_stmt()) a = G.make_node('let P := a(P)') b = G.make_node('let p, P := b(P)') c = G.make_node('branch p') d = G.make_node('let P := d(P)') exit = G.make_node(stmts.null_stmt()) G.make_edge(entry, a) G.make_edge(a, b) G.make_edge(b, c) G.make_edge(c, d, index=0) G.make_edge(c, b, index=1) G.make_edge(d, exit) #cfg_view.show(G) #cfg2rvsdg.convert_loops(G, cfg2rvsdg.predicate_generator()) #cfg_view.show(G) rvsdg = cfg2rvsdg.convert(G) rvsdg.normalize()
def _convert_to_cfg(dg): cfg = cfg_model.cfg() cfg_tgt_map = {} cfg_org_map = {} entry = cfg.make_node(stmts.null_stmt()) exit = cfg.make_node(stmts.null_stmt()) for vertex, label in dg.vertex_labels.items(): if label == 'ENTER': cfg_org_map[vertex] = entry continue elif label == 'EXIT': cfg_tgt_map[vertex] = exit continue succs = dg.vertex_outgoing.get(vertex, []) is_branch = len(succs) > 1 if is_branch: n1 = cfg.make_node('let P, p%s := f%s(P)' % (vertex, vertex)) n2 = cfg.make_node('branch p%s' % vertex) cfg.make_edge(n1, n2) cfg_tgt_map[vertex] = n1 cfg_org_map[vertex] = n2 else: n = cfg.make_node('let P := f%s(P)' % vertex) cfg_tgt_map[vertex] = n cfg_org_map[vertex] = n for origin, tgts in dg.vertex_outgoing.items(): for target, label in tgts: n1 = cfg_org_map[origin] n2 = cfg_tgt_map[target] if (n1, n2) in cfg.edges: dummy = cfg.make_node('let P := dummy(P)') cfg.make_edge(dummy, n2, 0) n2 = dummy cfg.make_edge(n1, n2, int(label)) return cfg