[pypy-svn] r59066 - in pypy/dist/pypy/translator/backendopt: . test
arigo at codespeak.net
arigo at codespeak.net
Mon Oct 13 13:43:37 CEST 2008
Author: arigo
Date: Mon Oct 13 13:43:36 2008
New Revision: 59066
Modified:
pypy/dist/pypy/translator/backendopt/mallocv.py
pypy/dist/pypy/translator/backendopt/test/test_mallocv.py
Log:
- "for i in range" works.
- recursion detection, trying to prevent non-termination.
Modified: pypy/dist/pypy/translator/backendopt/mallocv.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/mallocv.py (original)
+++ pypy/dist/pypy/translator/backendopt/mallocv.py Mon Oct 13 13:43:36 2008
@@ -120,8 +120,8 @@
class VirtualFrame(object):
- def __init__(self, sourcegraph, sourceblock, nextopindex,
- allnodes, callerframe=None):
+ def __init__(self, sourceblock, nextopindex,
+ allnodes, callerframe=None, calledgraphs={}):
if isinstance(allnodes, dict):
self.varlist = vars_alive_through_op(sourceblock, nextopindex)
self.nodelist = [allnodes[v] for v in self.varlist]
@@ -129,10 +129,10 @@
assert nextopindex == 0
self.varlist = sourceblock.inputargs
self.nodelist = allnodes[:]
- self.sourcegraph = sourcegraph
self.sourceblock = sourceblock
self.nextopindex = nextopindex
self.callerframe = callerframe
+ self.calledgraphs = calledgraphs
def get_nodes_in_use(self):
return dict(zip(self.varlist, self.nodelist))
@@ -142,13 +142,13 @@
newframe.varlist = self.varlist
newframe.nodelist = [node.copy(memo, flagreadonly)
for node in self.nodelist]
- newframe.sourcegraph = self.sourcegraph
newframe.sourceblock = self.sourceblock
newframe.nextopindex = self.nextopindex
if self.callerframe is None:
newframe.callerframe = None
else:
newframe.callerframe = self.callerframe.copy(memo, flagreadonly)
+ newframe.calledgraphs = self.calledgraphs
return newframe
def enum_call_stack(self):
@@ -251,8 +251,7 @@
else:
yield (block, op)
elif op.opname == 'direct_call':
- fobj = op.args[0].value._obj
- graph = getattr(fobj, 'graph', None)
+ graph = graph_called_by(op)
if graph in self.inline_and_remove:
yield (block, op)
@@ -339,7 +338,7 @@
assert len(graph.getargs()) == len(nodelist)
if is_trivial_nodelist(nodelist):
return 'trivial', graph
- virtualframe = VirtualFrame(graph, graph.startblock, 0, nodelist)
+ virtualframe = VirtualFrame(graph.startblock, 0, nodelist)
key = virtualframe.getfrozenkey()
try:
return self.specialized_graphs[key]
@@ -349,7 +348,7 @@
def build_specialized_graph(self, graph, key, nodelist):
graph2 = copygraph(graph)
- virtualframe = VirtualFrame(graph2, graph2.startblock, 0, nodelist)
+ virtualframe = VirtualFrame(graph2.startblock, 0, nodelist)
graphbuilder = GraphBuilder(self, graph2)
specblock = graphbuilder.start_from_virtualframe(virtualframe)
specblock.isstartblock = True
@@ -394,7 +393,7 @@
nodelist = []
for v in block.inputargs:
nodelist.append(RuntimeSpecNode(v, v.concretetype))
- trivialframe = VirtualFrame(graph, block, 0, nodelist)
+ trivialframe = VirtualFrame(block, 0, nodelist)
spec = BlockSpecializer(self, v_result)
spec.initialize_renamings(trivialframe)
self.pending_specializations.append(spec)
@@ -434,9 +433,9 @@
newframe = self.return_to_caller(currentframe, nodelist[0])
else:
targetnodes = dict(zip(targetblock.inputargs, nodelist))
- newframe = VirtualFrame(currentframe.sourcegraph,
- targetblock, 0, targetnodes,
- callerframe=currentframe.callerframe)
+ newframe = VirtualFrame(targetblock, 0, targetnodes,
+ callerframe=currentframe.callerframe,
+ calledgraphs=currentframe.calledgraphs)
rtnodes = newframe.find_rt_nodes()
specblock = self.get_specialized_block(newframe, v_expand_malloc)
@@ -650,6 +649,11 @@
newops_for_this_op = meth(op)
newoperations += newops_for_this_op
self.ops_produced_by_last_op = len(newops_for_this_op)
+ for op in newoperations:
+ if op.opname == 'direct_call':
+ graph = graph_called_by(op)
+ if graph in self.virtualframe.calledgraphs:
+ raise CannotVirtualize("recursion in residual call")
self.specblock.operations = newoperations
def follow_exits(self):
@@ -847,10 +851,9 @@
return self.handle_default(op)
def handle_op_direct_call(self, op):
- fobj = op.args[0].value._obj
- if not hasattr(fobj, 'graph'):
+ graph = graph_called_by(op)
+ if graph is None:
return self.handle_default(op)
- graph = fobj.graph
nb_args = len(op.args) - 1
assert nb_args == len(graph.getargs())
newnodes = [self.getnode(v) for v in op.args[1:]]
@@ -878,13 +881,12 @@
raise ValueError(kind)
def get_updated_frame(self, op):
- sourcegraph = self.virtualframe.sourcegraph
sourceblock = self.virtualframe.sourceblock
nextopindex = self.virtualframe.nextopindex
self.nodes[op.result] = FutureReturnValue(op)
- myframe = VirtualFrame(sourcegraph, sourceblock, nextopindex,
- self.nodes,
- self.virtualframe.callerframe)
+ myframe = VirtualFrame(sourceblock, nextopindex, self.nodes,
+ self.virtualframe.callerframe,
+ self.virtualframe.calledgraphs)
del self.nodes[op.result]
return myframe
@@ -900,8 +902,12 @@
def handle_inlined_call(self, myframe, graph, newnodes):
assert len(graph.getargs()) == len(newnodes)
targetnodes = dict(zip(graph.getargs(), newnodes))
- calleeframe = VirtualFrame(graph, graph.startblock, 0,
- targetnodes, myframe)
+ calledgraphs = myframe.calledgraphs.copy()
+ if graph in calledgraphs:
+ raise CannotVirtualize("recursion during inlining")
+ calledgraphs[graph] = True
+ calleeframe = VirtualFrame(graph.startblock, 0,
+ targetnodes, myframe, calledgraphs)
self.virtualframe = calleeframe
self.nodes = calleeframe.get_nodes_in_use()
return []
@@ -985,3 +991,9 @@
rtnode = RuntimeSpecNode(None, v.concretetype)
renamings[rtnode] = v
return rtnode
+
+def graph_called_by(op):
+ assert op.opname == 'direct_call'
+ fobj = op.args[0].value._obj
+ graph = getattr(fobj, 'graph', None)
+ return graph
Modified: pypy/dist/pypy/translator/backendopt/test/test_mallocv.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_mallocv.py (original)
+++ pypy/dist/pypy/translator/backendopt/test/test_mallocv.py Mon Oct 13 13:43:36 2008
@@ -425,6 +425,59 @@
return a.x * a.y
self.check(fn9, [int], [6], 42, expected_calls=0) # inlined
+ def test_remove_for_in_range(self):
+ def fn10(n):
+ total = 0
+ for i in range(n):
+ total += i
+ return total
+ self.check(fn10, [int], [10], 45)
+
+ def test_recursion_spec(self):
+ class A:
+ pass
+ def make_chain(n):
+ a = A()
+ if n >= 0:
+ a.next = make_chain(n-1)
+ a.value = a.next.value + n
+ else:
+ a.value = 0
+ return a
+ def fn11(n):
+ return make_chain(n).value
+ self.check(fn11, [int], [10], 55,
+ expected_calls=1)
+
+ def test_recursion_inlining(self):
+ class A:
+ pass
+ def make_chain(a, n):
+ if n >= 0:
+ a.next = A()
+ make_chain(a.next, n-1)
+ a.value = a.next.value + n
+ else:
+ a.value = 0
+ def fn12(n):
+ a = A()
+ make_chain(a, n)
+ return a.value
+ self.check(fn12, [int], [10], 55,
+ expected_mallocs=1, expected_calls=1)
+
+ def test_constfold_exitswitch(self):
+ class A:
+ pass
+ def fn13(n):
+ a = A()
+ if lloperation.llop.same_as(lltype.Bool, True):
+ a.n = 4
+ else:
+ a.n = -13
+ return a.n
+ self.check(fn13, [int], [10], 4)
+
class TestLLTypeMallocRemoval(BaseMallocRemovalTest):
type_system = 'lltype'
More information about the Pypy-commit
mailing list