forked from ethanchewy/PythonBuddy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathunsimplify.py
More file actions
173 lines (161 loc) · 6.72 KB
/
unsimplify.py
File metadata and controls
173 lines (161 loc) · 6.72 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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
from rpython.flowspace.model import (Variable, Constant, Block, Link,
SpaceOperation, c_last_exception, checkgraph)
def varoftype(concretetype, name=None):
var = Variable(name)
var.concretetype = concretetype
return var
def insert_empty_block(link, newops=[]):
"""Insert and return a new block along the given link."""
vars = {}
for v in link.args:
if isinstance(v, Variable):
vars[v] = True
for op in newops:
for v in op.args:
if isinstance(v, Variable):
vars.setdefault(v, True)
vars[op.result] = False
vars = [v for v, keep in vars.items() if keep]
mapping = {}
for v in vars:
mapping[v] = v.copy()
newblock = Block(vars)
newblock.operations.extend(newops)
newblock.closeblock(Link(link.args, link.target))
newblock.renamevariables(mapping)
link.args[:] = vars
link.target = newblock
return newblock
def insert_empty_startblock(graph):
vars = [v.copy() for v in graph.startblock.inputargs]
newblock = Block(vars)
newblock.closeblock(Link(vars, graph.startblock))
graph.startblock = newblock
def starts_with_empty_block(graph):
return (not graph.startblock.operations
and graph.startblock.exitswitch is None
and graph.startblock.exits[0].args == graph.getargs())
def split_block(block, index, _forcelink=None):
"""return a link where prevblock is the block leading up but excluding the
index'th operation and target is a new block with the neccessary variables
passed on.
"""
assert 0 <= index <= len(block.operations)
if block.exitswitch == c_last_exception:
assert index < len(block.operations)
#varmap is the map between names in the new and the old block
#but only for variables that are produced in the old block and needed in
#the new one
varmap = {}
vars_produced_in_new_block = set()
def get_new_name(var):
if var is None:
return None
if isinstance(var, Constant):
return var
if var in vars_produced_in_new_block:
return var
if var not in varmap:
varmap[var] = var.copy()
return varmap[var]
moved_operations = block.operations[index:]
new_moved_ops = []
for op in moved_operations:
repl = dict((arg, get_new_name(arg)) for arg in op.args)
newop = op.replace(repl)
new_moved_ops.append(newop)
vars_produced_in_new_block.add(op.result)
moved_operations = new_moved_ops
links = block.exits
block.exits = None
for link in links:
for i, arg in enumerate(link.args):
#last_exception and last_exc_value are considered to be created
#when the link is entered
if link.args[i] not in [link.last_exception, link.last_exc_value]:
link.args[i] = get_new_name(link.args[i])
exitswitch = get_new_name(block.exitswitch)
#the new block gets all the attributes relevant to outgoing links
#from block the old block
if _forcelink is not None:
assert index == 0
linkargs = list(_forcelink)
for v in varmap:
if v not in linkargs:
# 'v' was not specified by _forcelink, but we found out that
# we need it! Hack: if it is 'concretetype is lltype.Void'
# then it's ok to recreate its value in the target block.
# If not, then we have a problem :-)
from rpython.rtyper.lltypesystem import lltype
if v.concretetype is not lltype.Void:
raise Exception(
"The variable %r of type %r was not explicitly listed"
" in _forcelink. This issue can be caused by a"
" jitdriver.jit_merge_point() where some variable"
" containing an int or str or instance is actually"
" known to be constant, e.g. always 42." % (
v, v.concretetype))
c = Constant(None, lltype.Void)
w = varmap[v]
newop = SpaceOperation('same_as', [c], w)
i = 0
while i < len(moved_operations):
if w in moved_operations[i].args:
break
i += 1
moved_operations.insert(i, newop)
else:
linkargs = varmap.keys()
newblock = Block([get_new_name(v) for v in linkargs])
newblock.operations = moved_operations
newblock.recloseblock(*links)
newblock.exitswitch = exitswitch
link = Link(linkargs, newblock)
block.operations = block.operations[:index]
block.recloseblock(link)
block.exitswitch = None
return link
def call_initial_function(translator, initial_func, annhelper=None):
"""Before the program starts, call 'initial_func()'."""
from rpython.annotator import model as annmodel
from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator
own_annhelper = (annhelper is None)
if own_annhelper:
annhelper = MixLevelHelperAnnotator(translator.rtyper)
c_initial_func = annhelper.constfunc(initial_func, [], annmodel.s_None)
if own_annhelper:
annhelper.finish()
entry_point = translator.entry_point_graph
args = [v.copy() for v in entry_point.getargs()]
extrablock = Block(args)
v_none = varoftype(lltype.Void)
newop = SpaceOperation('direct_call', [c_initial_func], v_none)
extrablock.operations = [newop]
extrablock.closeblock(Link(args, entry_point.startblock))
entry_point.startblock = extrablock
checkgraph(entry_point)
def call_final_function(translator, final_func, annhelper=None):
"""When the program finishes normally, call 'final_func()'."""
from rpython.annotator import model as annmodel
from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator
own_annhelper = (annhelper is None)
if own_annhelper:
annhelper = MixLevelHelperAnnotator(translator.rtyper)
c_final_func = annhelper.constfunc(final_func, [], annmodel.s_None)
if own_annhelper:
annhelper.finish()
entry_point = translator.entry_point_graph
v = entry_point.getreturnvar().copy()
extrablock = Block([v])
v_none = varoftype(lltype.Void)
newop = SpaceOperation('direct_call', [c_final_func], v_none)
extrablock.operations = [newop]
extrablock.closeblock(Link([v], entry_point.returnblock))
for block in entry_point.iterblocks():
if block is not extrablock:
for link in block.exits:
if link.target is entry_point.returnblock:
link.target = extrablock
checkgraph(entry_point)