forked from ethanchewy/PythonBuddy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsupport.py
More file actions
124 lines (112 loc) · 4.02 KB
/
support.py
File metadata and controls
124 lines (112 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.rmodel import inputconst
from rpython.tool.ansi_print import AnsiLogger
from rpython.translator.simplify import get_graph
log = AnsiLogger("backendopt")
def graph_operations(graph):
for block in graph.iterblocks():
for op in block.operations:
yield op
def all_operations(graphs):
for graph in graphs:
for block in graph.iterblocks():
for op in block.operations:
yield op
def annotate(translator, func, result, args):
args = [arg.concretetype for arg in args]
graph = translator.rtyper.annotate_helper(func, args)
fptr = lltype.functionptr(lltype.FuncType(args, result.concretetype), func.func_name, graph=graph)
c = inputconst(lltype.typeOf(fptr), fptr)
return c
def var_needsgc(var):
vartype = var.concretetype
return isinstance(vartype, lltype.Ptr) and vartype._needsgc()
def find_calls_from(translator, graph, memo=None):
if memo and graph in memo:
return memo[graph]
res = [i for i in _find_calls_from(translator, graph)]
if memo is not None:
memo[graph] = res
return res
def _find_calls_from(translator, graph):
for block in graph.iterblocks():
for op in block.operations:
if op.opname == "direct_call":
called_graph = get_graph(op.args[0], translator)
if called_graph is not None:
yield block, called_graph
if op.opname == "indirect_call":
graphs = op.args[-1].value
if graphs is not None:
for called_graph in graphs:
yield block, called_graph
def find_backedges(graph, block=None, seen=None, seeing=None):
"""finds the backedges in the flow graph"""
backedges = []
if block is None:
block = graph.startblock
if seen is None:
seen = set([block])
if seeing is None:
seeing = set()
seeing.add(block)
for link in block.exits:
if link.target in seen:
if link.target in seeing:
backedges.append(link)
else:
seen.add(link.target)
backedges.extend(find_backedges(graph, link.target, seen, seeing))
seeing.remove(block)
return backedges
def compute_reachability(graph):
reachable = {}
blocks = list(graph.iterblocks())
# Reversed order should make the reuse path more likely.
for block in reversed(blocks):
reach = set()
scheduled = [block]
while scheduled:
current = scheduled.pop()
for link in current.exits:
if link.target in reachable:
reach.add(link.target)
reach = reach | reachable[link.target]
continue
if link.target not in reach:
reach.add(link.target)
scheduled.append(link.target)
reachable[block] = reach
return reachable
def find_loop_blocks(graph):
"""find the blocks in a graph that are part of a loop"""
loop = {}
reachable = compute_reachability(graph)
for backedge in find_backedges(graph):
start = backedge.target
end = backedge.prevblock
loop[start] = start
loop[end] = start
scheduled = [start]
seen = {}
while scheduled:
current = scheduled.pop()
connects = end in reachable[current]
seen[current] = True
if connects:
loop[current] = start
for link in current.exits:
if link.target not in seen:
scheduled.append(link.target)
return loop
def md5digest(translator):
from hashlib import md5
graph2digest = {}
for graph in translator.graphs:
m = md5()
for op in graph_operations(graph):
m.update(op.opname + str(op.result))
for a in op.args:
m.update(str(a))
graph2digest[graph.name] = m.digest()
return graph2digest