[pypy-svn] r17889 - in pypy/dist/pypy/translator/backendopt: . test
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Sep 27 00:40:12 CEST 2005
Author: cfbolz
Date: Tue Sep 27 00:40:11 2005
New Revision: 17889
Added:
pypy/dist/pypy/translator/backendopt/tailrecursion.py
pypy/dist/pypy/translator/backendopt/test/test_tailrecursion.py
Log:
a very academical transformation: tail recursion elimination for some very
specific cases (I was bored).
Added: pypy/dist/pypy/translator/backendopt/tailrecursion.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/backendopt/tailrecursion.py Tue Sep 27 00:40:11 2005
@@ -0,0 +1,61 @@
+import sys
+from pypy.translator.unsimplify import copyvar, split_block
+from pypy.objspace.flow.model import Variable, Constant, Block, Link
+from pypy.objspace.flow.model import SpaceOperation, last_exception
+from pypy.objspace.flow.model import traverse, mkentrymap, checkgraph, flatten
+from pypy.annotation import model as annmodel
+from pypy.rpython.lltype import Bool, typeOf, FuncType, _ptr
+from pypy.rpython import rmodel
+
+# this transformation is very academical -- I had too much time
+
+def get_graph(arg, translator):
+ if isinstance(arg, Variable):
+ return None
+ f = arg.value
+ if not isinstance(f, _ptr):
+ return None
+ try:
+ callable = f._obj._callable
+ #external function calls don't have a real graph
+ if getattr(callable, "suggested_primitive", False):
+ return None
+ if callable in translator.flowgraphs:
+ return translator.flowgraphs[callable]
+ except AttributeError, KeyError:
+ pass
+ try:
+ return f._obj.graph
+ except AttributeError:
+ return None
+
+def _remove_tail_call(translator, graph, block):
+ print "removing tail call"
+ assert len(block.exits) == 1
+ assert block.exits[0].target is graph.returnblock
+ assert block.operations[-1].result == block.exits[0].args[0]
+ op = block.operations[-1]
+ block.operations = block.operations[:-1]
+ block.exits[0].args = op.args[1:]
+ block.exits[0].target = graph.startblock
+
+def remove_tail_calls_to_self(translator, graph):
+ entrymap = mkentrymap(graph)
+ changed = False
+ for link in entrymap[graph.returnblock]:
+ block = link.prevblock
+ if (len(block.exits) == 1 and
+ len(block.operations) > 0 and
+ block.operations[-1].opname == 'direct_call' and
+ block.operations[-1].result == link.args[0]):
+ call = get_graph(block.operations[-1].args[0], translator)
+ print "getgraph", graph
+ if graph is graph:
+ _remove_tail_call(translator, graph, block)
+ changed = True
+ if changed:
+ from pypy.translator import simplify
+ checkgraph(graph)
+ simplify.remove_identical_vars(graph)
+ simplify.eliminate_empty_blocks(graph)
+ simplify.join_blocks(graph)
Added: pypy/dist/pypy/translator/backendopt/test/test_tailrecursion.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/backendopt/test/test_tailrecursion.py Tue Sep 27 00:40:11 2005
@@ -0,0 +1,20 @@
+from pypy.objspace.flow.model import traverse, Block, Link, Variable, Constant
+from pypy.translator.backendopt.tailrecursion import remove_tail_calls_to_self
+from pypy.translator.translator import Translator
+from pypy.rpython.llinterp import LLInterpreter
+from pypy.translator.test.snippet import is_perfect_number
+
+def test_recursive_gcd():
+ def gcd(a, b):
+ if a == 1 or a == 0:
+ return b
+ if a > b:
+ return gcd(b, a)
+ return gcd(b % a, a)
+ t = Translator(gcd)
+ a = t.annotate([int, int])
+ t.specialize()
+ remove_tail_calls_to_self(t, t.flowgraphs[gcd])
+ lli = LLInterpreter(t.flowgraphs, t.rtyper)
+ res = lli.eval_function(gcd, (15, 25))
+ assert res == 5
More information about the Pypy-commit
mailing list