[pypy-svn] r17890 - in pypy/dist/pypy/translator: . test
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Sep 27 00:43:41 CEST 2005
Author: cfbolz
Date: Tue Sep 27 00:43:40 2005
New Revision: 17890
Added:
pypy/dist/pypy/translator/test/test_simplify.py
Modified:
pypy/dist/pypy/translator/simplify.py
Log:
try to find functions without side-effects and remove them in
transform_dead_op_vars.
Modified: pypy/dist/pypy/translator/simplify.py
==============================================================================
--- pypy/dist/pypy/translator/simplify.py (original)
+++ pypy/dist/pypy/translator/simplify.py Tue Sep 27 00:43:40 2005
@@ -9,7 +9,7 @@
from pypy.objspace.flow.model import Variable, Constant, Block, Link
from pypy.objspace.flow.model import last_exception
from pypy.objspace.flow.model import checkgraph, traverse, mkentrymap
-
+from pypy.translator.backendopt.tailrecursion import get_graph
# ____________________________________________________________
def eliminate_empty_blocks(graph):
@@ -322,7 +322,57 @@
block.exits = tuple(lst)
traverse(visit, graph)
-def transform_dead_op_vars(graph):
+
+# _____________________________________________________________________
+# decide whether a function has side effects
+lloperations_with_side_effects = {"setfield": True,
+ "setarrayitem": True,
+ }
+
+class HasSideEffects(Exception):
+ pass
+
+# XXX: this could even be improved:
+# if setfield and setarrayitem only occur on things that are malloced
+# in this function then the function still does not have side effects
+
+def has_no_side_effects(translator, graph, seen=None):
+ #is the graph specialized? if no we can't say anything
+ #don't cache the result though
+ if translator.rtyper is None:
+ return False
+ else:
+ if graph.startblock not in translator.rtyper.already_seen:
+ return False
+ if seen is None:
+ seen = []
+ elif graph in seen:
+ return True
+ try:
+ def visit(block):
+ if not isinstance(block, Block):
+ return
+ for op in block.operations:
+ if op.opname in lloperations_with_side_effects:
+ raise HasSideEffects
+ if op.opname == "direct_call":
+ if isinstance(op.args[0], Variable):
+ raise HasSideEffects
+ g = get_graph(op.args[0], translator)
+ if g is None:
+ raise HasSideEffects
+ if not has_no_side_effects(translator, g, seen + [graph]):
+ raise HasSideEffects
+ traverse(visit, graph)
+ except HasSideEffects:
+ return False
+ else:
+ return True
+
+# ___________________________________________________________________________
+# remove operations if their result is not used and they have no side effects
+
+def transform_dead_op_vars(graph, translator=None):
"""Remove dead operations and variables that are passed over a link
but not used in the target block. Input is a graph."""
blocks = {}
@@ -330,7 +380,7 @@
if isinstance(block, Block):
blocks[block] = True
traverse(visit, graph)
- return transform_dead_op_vars_in_blocks(blocks)
+ return transform_dead_op_vars_in_blocks(blocks, translator)
# the set of operations that can safely be removed
# (they have no side effects, at least in R-Python)
@@ -349,7 +399,7 @@
hasattr: True,
}
-def transform_dead_op_vars_in_blocks(blocks):
+def transform_dead_op_vars_in_blocks(blocks, translator=None):
"""Remove dead operations and variables that are passed over a link
but not used in the target block. Input is a set of blocks"""
read_vars = {} # set of variables really used
@@ -427,7 +477,14 @@
del block.operations[i]
except TypeError: # func is not hashable
pass
-
+ elif op.opname == 'direct_call':
+ if translator is not None:
+ graph = get_graph(op.args[0], translator)
+ if (graph is not None and
+ has_no_side_effects(translator, graph) and
+ (block.exitswitch != Constant(last_exception) or
+ i != len(block.operations)- 1)):
+ del block.operations[i]
# look for output variables never used
# warning: this must be completely done *before* we attempt to
# remove the corresponding variables from block.inputargs!
Added: pypy/dist/pypy/translator/test/test_simplify.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/test/test_simplify.py Tue Sep 27 00:43:40 2005
@@ -0,0 +1,59 @@
+from pypy.translator.translator import Translator
+from pypy.objspace.flow.model import traverse, Block
+
+def test_remove_direct_call_without_side_effects():
+ def f(x):
+ return x + 123
+ def g(x):
+ a = f(x)
+ return x * 12
+ t = Translator(g)
+ a = t.annotate([int])
+ t.specialize()
+ t.backend_optimizations()
+ assert len(t.flowgraphs[g].startblock.operations) == 1
+
+def test_dont_remove_external_calls():
+ import os
+ def f(x):
+ os.close(x)
+ t = Translator(f)
+ a = t.annotate([int])
+ t.specialize()
+ t.backend_optimizations()
+ assert len(t.flowgraphs[f].startblock.operations) == 1
+
+def test_remove_recursive_call():
+ def rec(a):
+ if a <= 1:block.exitswitch != Constant(last_exception):
+ return 0
+ else:
+ return rec(a - 1) + 1
+ def f(x):
+ a = rec(x)
+ return x + 12
+ t = Translator(f)
+ a = t.annotate([int])
+ t.specialize()
+ t.backend_optimizations()
+ assert len(t.flowgraphs[f].startblock.operations)
+
+def test_dont_remove_if_exception_guarded():
+ def f(x):
+ a = {} #do some stuff to prevent inlining
+ a['123'] = 123
+ a['1123'] = 1234
+ return x + 1
+ def g(x):
+ try:
+ a = f(x)
+ except OverflowError:
+ raise
+ else:
+ return 1
+ t = Translator(g)
+ a = t.annotate([int])
+ t.specialize()
+ t.backend_optimizations()
+ assert t.flowgraphs[g].startblock.operations[-1].opname == 'direct_call'
+
More information about the Pypy-commit
mailing list