1 # ScratchABlock - Program analysis and decompilation framework
3 # Copyright (c) 2015-2018 Paul Sokolovsky
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """Transformation passes on generic graphs (not CFGs)"""
20 from dom
import compute_idom
21 from utils
import make_set
25 def t1_transform(g
, node
):
26 if g
.has_edge(node
, node
):
27 print("t1: yes", node
)
28 g
.remove_edge(node
, node
)
34 def t2_transform(g
, node
):
35 if g
.degree_in(node
) == 1:
36 print("t2: yes", node
)
37 pred
= g
.pred(node
)[0]
38 g
.remove_edge(pred
, node
)
39 g
.move_succ(node
, pred
)
40 g
[pred
].setdefault("folded", []).append(node
)
53 for node
in list(g
.nodes()):
54 # Might have been deleted by previous iteration
56 changed |
= t1_transform(g
, node
)
57 changed |
= t2_transform(g
, node
)
60 def recursive_relation(g
, n
, in_prop
, out_prop
, is_reflexive
=False):
61 "Helper function to compute relation closures, don't use directly."
64 if in_prop
not in g
[n
]:
75 res |
= recursive_relation(g
, rel_n
, in_prop
, out_prop
, is_reflexive
)
85 def transitive_closure(g
, in_prop
, out_prop
):
86 """Compute a transitive closure of some graph relation.
88 in_prop: Name of node property storing relation (i.e.
89 value of property should be id of another node).
90 out_prop: Name of node property to store transitive closure
95 recursive_relation(g
, n
, in_prop
, out_prop
, False)
98 def reflexive_transitive_closure(g
, in_prop
, out_prop
):
99 """Compute a reflexive-transitive closure of some graph relation.
101 in_prop: Name of node property storing relation (i.e.
102 value of property should be id of another node).
103 out_prop: Name of node property to store transitive closure
108 recursive_relation(g
, n
, in_prop
, out_prop
, True)
112 transitive_closure(g
, "idom", "sdom")
116 reflexive_transitive_closure(g
, "idom", "dom")
119 def idom_children(g
, node
):
120 """Return children of idom node.
122 The implementation here is very inefficient.
126 for n
, info
in g
.nodes_props():
127 if info
["idom"] == node
:
132 def idom_transitive_dom(g
, node1
, node2
):
133 "Check whether node1 dominates node2, by walking idom chain."
134 while node2
is not None:
137 node2
= g
[node2
]["idom"]
141 def compute_dom_frontier_cytron(g
, node
=None):
142 """Compute dominance frontier of each node.
144 Intuitively, dominance frontier of a node X is a set of
145 successors of "last" nodes which X dominates. I.e., if
146 X dominates A, but not its successor B, then B is in X's
149 Ref: Efficiently Computing Static Single Assignment Form and the Control
150 Dependence Graph, Cytron, Ferrante, Rosen, Wegman, Zedeck
159 for y
in g
.succ(node
):
160 if g
[y
]["idom"] != node
:
163 for z
in idom_children(g
, node
):
164 compute_dom_frontier_cytron(g
, z
)
165 for y
in g
[z
]["dom_front"]:
166 if g
[y
]["idom"] != node
:
169 g
[node
]["dom_front"] = df
172 def compute_dom_frontier_cooper(g
):
173 """Compute dominance frontier of each node.
175 Ref: A Simple, Fast Dominance Algorithm, Cooper, Harvey, Kennedy
177 for n
, info
in g
.nodes_props():
178 info
["dom_front"] = set()
180 for n
, info
in g
.nodes_props():
185 while runner
!= info
["idom"]:
186 g
[runner
]["dom_front"].add(n
)
187 runner
= g
[runner
]["idom"]