[pypy-svn] r17528 - in pypy/dist/pypy/translator: . backend_opt backendopt backendopt/test c/test llvm test
arigo at codespeak.net
arigo at codespeak.net
Tue Sep 13 16:49:16 CEST 2005
Author: arigo
Date: Tue Sep 13 16:49:13 2005
New Revision: 17528
Added:
pypy/dist/pypy/translator/backendopt/ (props changed)
- copied from r17526, pypy/dist/pypy/translator/backend_opt/
pypy/dist/pypy/translator/backendopt/all.py (contents, props changed)
pypy/dist/pypy/translator/backendopt/removenoops.py
- copied, changed from r17526, pypy/dist/pypy/translator/backend_opt/remove_no_ops.py
pypy/dist/pypy/translator/backendopt/test/test_all.py (contents, props changed)
pypy/dist/pypy/translator/backendopt/test/test_removenoops.py
- copied, changed from r17526, pypy/dist/pypy/translator/backend_opt/test/test_remove_no_ops.py
Removed:
pypy/dist/pypy/translator/backend_opt/
pypy/dist/pypy/translator/backendopt/remove_no_ops.py
pypy/dist/pypy/translator/backendopt/test/test_remove_no_ops.py
pypy/dist/pypy/translator/backendoptimization.py
pypy/dist/pypy/translator/test/test_backendoptimization.py
Modified:
pypy/dist/pypy/translator/backendopt/__init__.py (props changed)
pypy/dist/pypy/translator/backendopt/inline.py
pypy/dist/pypy/translator/backendopt/malloc.py
pypy/dist/pypy/translator/backendopt/matfunc.py (props changed)
pypy/dist/pypy/translator/backendopt/ssa.py
pypy/dist/pypy/translator/backendopt/test/ (props changed)
pypy/dist/pypy/translator/backendopt/test/test_inline.py
pypy/dist/pypy/translator/backendopt/test/test_malloc.py
pypy/dist/pypy/translator/backendopt/test/test_ssa.py
pypy/dist/pypy/translator/c/test/test_backendoptimized.py
pypy/dist/pypy/translator/geninterplevel.py
pypy/dist/pypy/translator/llvm/funcnode.py
pypy/dist/pypy/translator/translator.py
Log:
* Removed underscores from directory and file names.
* Finished sorting the tests in their own backendopt/test/test_* files.
* Changed outside code to use backendopt/ instead of backendoptimization.py,
which is deleted.
* Fixed some bugs here and there, there are more bugs open, both in
inlining and malloc removal...
* llvm seems quite broken at the moment, sorry if I caused that.
I will check this too.
Added: pypy/dist/pypy/translator/backendopt/all.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/backendopt/all.py Tue Sep 13 16:49:13 2005
@@ -0,0 +1,30 @@
+from pypy.objspace.flow.model import checkgraph
+from pypy.translator.backendopt.removenoops import remove_same_as
+from pypy.translator.backendopt.inline import auto_inlining
+from pypy.translator.backendopt.malloc import remove_simple_mallocs
+from pypy.translator.backendopt.ssa import SSI_to_SSA
+from pypy.translator import simplify
+
+
+def backend_optimizations(translator, inline_threshold=1, ssa_form=True):
+ # remove obvious no-ops
+ for graph in translator.flowgraphs.values():
+ remove_same_as(graph)
+ simplify.eliminate_empty_blocks(graph)
+
+ # inline functions around
+ if inline_threshold and 0: # XXX in progress
+ auto_inlining(translator, inline_threshold)
+
+ # vaporize mallocs
+ # XXX in progress
+ for graph in []:# translator.flowgraphs.values():
+ if remove_simple_mallocs(graph):
+ # remove typical leftovers from malloc removal
+ remove_same_as(graph)
+ simplify.eliminate_empty_blocks(graph)
+ simplify.transform_dead_op_vars(graph)
+
+ if ssa_form:
+ for graph in translator.flowgraphs.values():
+ SSI_to_SSA(graph)
Modified: pypy/dist/pypy/translator/backendopt/inline.py
==============================================================================
--- pypy/dist/pypy/translator/backend_opt/inline.py (original)
+++ pypy/dist/pypy/translator/backendopt/inline.py Tue Sep 13 16:49:13 2005
@@ -1,16 +1,20 @@
-##from pypy.translator.translator import Translator
-##from pypy.translator.simplify import eliminate_empty_blocks, join_blocks
-##from pypy.translator.simplify import remove_identical_vars
-##from pypy.translator.simplify import transform_dead_op_vars
-##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
-##from pypy.annotation import model as annmodel
-##from pypy.tool.unionfind import UnionFind
-##from pypy.rpython.lltype import Void, Bool
-##from pypy.rpython import rmodel, lltype
-from pypy.translator.backend_opt import matfunc
+import sys
+from pypy.translator.simplify import eliminate_empty_blocks, join_blocks
+from pypy.translator.simplify import remove_identical_vars
+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
+from pypy.rpython import rmodel
+from pypy.translator.backendopt import matfunc
+
+BASE_INLINE_THRESHOLD = 17.0 # just enough to inline ll_rangeiter_next()
+
+class CannotInline(Exception):
+ pass
+
def collect_called_functions(graph):
funcs = {}
@@ -23,28 +27,34 @@
traverse(visit, graph)
return funcs
-def inline_function(translator, inline_func, graph):
- count = 0
+def find_callsites(graph, calling_what):
callsites = []
- def find_callsites(block):
+ def visit(block):
if isinstance(block, Block):
for i, op in enumerate(block.operations):
if not (op.opname == "direct_call" and
isinstance(op.args[0], Constant)):
continue
funcobj = op.args[0].value._obj
+ graph = getattr(funcobj, 'graph', None)
# accept a function or a graph as 'inline_func'
- if (getattr(funcobj, 'graph', None) is inline_func or
- getattr(funcobj, '_callable', None) is inline_func):
- callsites.append((block, i))
- traverse(find_callsites, graph)
+ if (graph is calling_what or
+ getattr(funcobj, '_callable', None) is calling_what):
+ callsites.append((graph, block, i))
+ traverse(visit, graph)
+ return callsites
+
+def inline_function(translator, inline_func, graph):
+ count = 0
+ callsites = find_callsites(graph, inline_func)
while callsites != []:
- block, index_operation = callsites.pop()
+ subgraph, block, index_operation = callsites.pop()
+ if find_callsites(subgraph, subgraph):
+ raise CannotInline("inlining a recursive function")
_inline_function(translator, graph, block, index_operation)
- callsites = []
- traverse(find_callsites, graph)
checkgraph(graph)
count += 1
+ callsites = find_callsites(graph, inline_func)
return count
def _find_exception_type(block):
@@ -70,7 +80,7 @@
index_operation == len(block.operations) - 1):
exception_guarded = True
if len(collect_called_functions(graph_to_inline)) != 0:
- raise NotImplementedError("can't handle exceptions yet")
+ raise CannotInline("can't handle exceptions yet")
entrymap = mkentrymap(graph_to_inline)
beforeblock = block
afterblock = split_block(translator, graph, block, index_operation)
@@ -269,7 +279,7 @@
static_instruction_count(graph))
-def static_callers(translator):
+def static_callers(translator, ignore_primitives=False):
result = []
def build_call_graph(node):
if isinstance(node, Block):
@@ -279,27 +289,33 @@
funcobj = op.args[0].value._obj
graph = getattr(funcobj, 'graph', None)
if graph is not None:
+ if ignore_primitives:
+ if getattr(getattr(funcobj, '_callable', None),
+ 'suggested_primitive', False):
+ continue
result.append((parentgraph, graph))
for parentgraph in translator.flowgraphs.itervalues():
traverse(build_call_graph, parentgraph)
return result
-def auto_inlining(translator, threshold=20):
- from heapq import heappop, heapreplace
+def auto_inlining(translator, threshold=1):
+ from heapq import heappush, heappop, heapreplace
+ threshold *= BASE_INLINE_THRESHOLD
callers = {} # {graph: {graphs-that-call-it}}
callees = {} # {graph: {graphs-that-it-calls}}
- for graph1, graph2 in static_callers(translator):
+ for graph1, graph2 in static_callers(translator, ignore_primitives=True):
callers.setdefault(graph2, {})[graph1] = True
callees.setdefault(graph1, {})[graph2] = True
fiboheap = [(0.0, graph) for graph in callers]
valid_weight = {}
+ couldnt_inline = {}
while fiboheap:
weight, graph = fiboheap[0]
if not valid_weight.get(graph):
weight = inlining_heuristic(graph)
- print ' + cost %7.2f %50s' % (weight, graph.name)
+ #print ' + cost %7.2f %50s' % (weight, graph.name)
heapreplace(fiboheap, (weight, graph))
valid_weight[graph] = True
continue
@@ -312,13 +328,24 @@
for parentgraph in callers[graph]:
if parentgraph == graph:
continue
- print '\t\t-> in %s' % parentgraph.name
+ print '\t\t-> in %s...' % parentgraph.name,
+ sys.stdout.flush()
try:
- if backendoptimization.inline_function(translator, graph,
- parentgraph):
- valid_weight[parentgraph] = False
- for graph2 in callees.get(graph, {}):
- callees[parentgraph][graph2] = True
- callers[graph2][parentgraph] = True
- except NotImplementedError:
- pass
+ res = bool(inline_function(translator, graph, parentgraph))
+ except CannotInline:
+ couldnt_inline[graph] = True
+ res = CannotInline
+ print res
+ if res is True:
+ # the parentgraph should now contain all calls that were
+ # done by 'graph'
+ for graph2 in callees.get(graph, {}):
+ callees[parentgraph][graph2] = True
+ callers[graph2][parentgraph] = True
+ if parentgraph in couldnt_inline:
+ # the parentgraph was previously uninlinable, but it has
+ # been modified. Maybe now we can inline it into further
+ # parents?
+ del couldnt_inline[parentgraph]
+ heappush(fiboheap, (0.0, parentgraph))
+ valid_weight[parentgraph] = False
Modified: pypy/dist/pypy/translator/backendopt/malloc.py
==============================================================================
--- pypy/dist/pypy/translator/backend_opt/malloc.py (original)
+++ pypy/dist/pypy/translator/backendopt/malloc.py Tue Sep 13 16:49:13 2005
@@ -1,15 +1,7 @@
-##from pypy.translator.translator import Translator
-##from pypy.translator.simplify import eliminate_empty_blocks, join_blocks
-##from pypy.translator.simplify import remove_identical_vars
-##from pypy.translator.simplify import transform_dead_op_vars
-##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
-##from pypy.annotation import model as annmodel
-##from pypy.tool.unionfind import UnionFind
-##from pypy.rpython.lltype import Void, Bool
-##from pypy.rpython import rmodel, lltype
+from pypy.objspace.flow.model import Variable, Constant, Block, Link
+from pypy.objspace.flow.model import SpaceOperation, traverse
+from pypy.tool.unionfind import UnionFind
+from pypy.rpython import lltype
class Blocked(Exception):
pass
Modified: pypy/dist/pypy/translator/backendopt/ssa.py
==============================================================================
--- pypy/dist/pypy/translator/backend_opt/ssa.py (original)
+++ pypy/dist/pypy/translator/backendopt/ssa.py Tue Sep 13 16:49:13 2005
@@ -1,15 +1,5 @@
-##from pypy.translator.translator import Translator
-##from pypy.translator.simplify import eliminate_empty_blocks, join_blocks
-##from pypy.translator.simplify import remove_identical_vars
-##from pypy.translator.simplify import transform_dead_op_vars
-##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
-##from pypy.annotation import model as annmodel
-##from pypy.tool.unionfind import UnionFind
-##from pypy.rpython.lltype import Void, Bool
-##from pypy.rpython import rmodel, lltype
+from pypy.objspace.flow.model import Variable, mkentrymap
+from pypy.tool.unionfind import UnionFind
def SSI_to_SSA(graph):
"""Rename the variables in a flow graph as much as possible without
Added: pypy/dist/pypy/translator/backendopt/test/test_all.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/backendopt/test/test_all.py Tue Sep 13 16:49:13 2005
@@ -0,0 +1,54 @@
+import py
+from pypy.translator.backendopt.all import backend_optimizations
+from pypy.translator.backendopt.test.test_malloc import check_malloc_removed
+from pypy.translator.translator import Translator
+from pypy.objspace.flow.model import Constant
+from pypy.rpython.llinterp import LLInterpreter
+
+
+class A:
+ def __init__(self, x, y):
+ self.bounds = (x, y)
+ def mean(self, percentage=50):
+ x, y = self.bounds
+ total = x*percentage + y*(100-percentage)
+ return total//100
+
+def condition(n):
+ return n >= 100
+
+def firstthat(function, condition):
+ for n in range(101):
+ if condition(function(n)):
+ return n
+ else:
+ return -1
+
+def myfunction(n):
+ a = A(117, n)
+ return a.mean()
+
+def big():
+ """This example should be turned into a simple 'while' loop with no
+ malloc nor direct_call by back-end optimizations, given a high enough
+ inlining threshold.
+ """
+ return firstthat(myfunction, condition)
+
+
+def test_big():
+ py.test.skip("in progress")
+ assert big() == 83
+
+ t = Translator(big)
+ t.annotate([])
+ t.specialize()
+ backend_optimizations(t, inline_threshold=100)
+
+ t.view()
+ graph = t.getflowgraph()
+ check_malloc_removed(graph)
+
+ interp = LLInterpreter(t.flowgraphs, t.rtyper)
+ res = interp.eval_function(big, [])
+ assert res == 83
Modified: pypy/dist/pypy/translator/backendopt/test/test_inline.py
==============================================================================
--- pypy/dist/pypy/translator/backend_opt/test/test_inline.py (original)
+++ pypy/dist/pypy/translator/backendopt/test/test_inline.py Tue Sep 13 16:49:13 2005
@@ -1,47 +1,10 @@
-from pypy.translator.backendoptimization import remove_void, inline_function
-from pypy.translator.backendoptimization import remove_simple_mallocs
+import py
+from pypy.translator.backendopt.inline import inline_function, CannotInline
+from pypy.translator.backendopt.inline import auto_inlining
+from pypy.translator.backendopt.inline import collect_called_functions
from pypy.translator.translator import Translator
-from pypy.rpython.lltype import Void
from pypy.rpython.llinterp import LLInterpreter
-from pypy.objspace.flow.model import checkgraph, flatten, Block
-from pypy.translator.test.snippet import simple_method, is_perfect_number
-from pypy.translator.llvm.log import log
-
-import py
-log = py.log.Producer('test_backendoptimization')
-
-def annotate_and_remove_void(f, annotate):
- t = Translator(f)
- a = t.annotate(annotate)
- t.specialize()
- remove_void(t)
- return t
-
-def test_remove_void_args():
- def f(i):
- return [1,2,3,i][i]
- t = annotate_and_remove_void(f, [int])
- for func, graph in t.flowgraphs.iteritems():
- assert checkgraph(graph) is None
- for arg in graph.startblock.inputargs:
- assert arg.concretetype is not Void
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- assert interp.eval_function(f, [0]) == 1
-
-def test_remove_void_in_struct():
- t = annotate_and_remove_void(simple_method, [int])
- #t.view()
- log(t.flowgraphs.iteritems())
- for func, graph in t.flowgraphs.iteritems():
- log('func : ' + str(func))
- log('graph: ' + str(graph))
- assert checkgraph(graph) is None
- #for fieldname in self.struct._names: #XXX helper (in lltype?) should remove these voids
- # type_ = getattr(struct, fieldname)
- # log('fieldname=%(fieldname)s , type_=%(type_)s' % locals())
- # assert _type is not Void
- #interp = LLInterpreter(t.flowgraphs, t.rtyper)
- #assert interp.eval_function(f, [0]) == 1
+from pypy.translator.test.snippet import is_perfect_number
def test_inline_simple():
def f(x, y):
@@ -233,53 +196,64 @@
result = interp.eval_function(f, [10])
assert result == 45
+def test_inline_constructor():
+ class A:
+ def __init__(self, x, y):
+ self.bounds = (x, y)
+ def area(self, height=10):
+ return height * (self.bounds[1] - self.bounds[0])
+ def f(i):
+ a = A(117, i)
+ return a.area()
+ t = Translator(f)
+ a = t.annotate([int])
+ a.simplify()
+ t.specialize()
+ inline_function(t, A.__init__.im_func, t.flowgraphs[f])
+ interp = LLInterpreter(t.flowgraphs, t.rtyper)
+ result = interp.eval_function(f, [120])
+ assert result == 30
-def check_malloc_removed(fn, signature, expected_remaining_mallocs):
- t = Translator(fn)
- t.annotate(signature)
- t.specialize()
- graph = t.getflowgraph()
- remove_simple_mallocs(graph)
- checkgraph(graph)
- count = 0
- for node in flatten(graph):
- if isinstance(node, Block):
- for op in node.operations:
- if op.opname == 'malloc':
- count += 1
- assert count == expected_remaining_mallocs
-
-def test_remove_mallocs():
- def fn1(x, y):
- s, d = x+y, x-y
- return s*d
- yield check_malloc_removed, fn1, [int, int], 0
- #
- class T:
- pass
- def fn2(x, y):
- t = T()
- t.x = x
- t.y = y
- if x > 0:
- return t.x + t.y
+def test_cannot_inline_recursive_function():
+ def factorial(n):
+ if n > 1:
+ return n * factorial(n-1)
else:
- return t.x - t.y
- yield check_malloc_removed, fn2, [int, int], 0
- #
- def fn3(x):
- a, ((b, c), d, e) = x+1, ((x+2, x+3), x+4, x+5)
- return a+b+c+d+e
- yield check_malloc_removed, fn3, [int], 0
- #
- class A:
- pass
- class B(A):
- pass
- def fn4(i):
- a = A()
- b = B()
- a.b = b
- b.i = i
- return a.b.i
- yield check_malloc_removed, fn4, [int], 0
+ return 1
+ def f(n):
+ return factorial(n//2)
+ t = Translator(f)
+ a = t.annotate([int])
+ a.simplify()
+ t.specialize()
+ py.test.raises(CannotInline,
+ "inline_function(t, factorial, t.flowgraphs[f])")
+
+def test_auto_inlining_small_call_big():
+ def leaf(n):
+ total = 0
+ i = 0
+ while i < n:
+ total += i
+ if total > 100:
+ raise OverflowError
+ i += 1
+ return total
+ def g(n):
+ return leaf(n)
+ def f(n):
+ try:
+ return g(n)
+ except OverflowError:
+ return -1
+ t = Translator(f)
+ a = t.annotate([int])
+ a.simplify()
+ t.specialize()
+ auto_inlining(t, threshold=10)
+ assert len(collect_called_functions(t.getflowgraph(f))) == 0
+ interp = LLInterpreter(t.flowgraphs, t.rtyper)
+ result = interp.eval_function(f, [10])
+ assert result == 45
+ result = interp.eval_function(f, [15])
+ assert result == -1
Modified: pypy/dist/pypy/translator/backendopt/test/test_malloc.py
==============================================================================
--- pypy/dist/pypy/translator/backend_opt/test/test_malloc.py (original)
+++ pypy/dist/pypy/translator/backendopt/test/test_malloc.py Tue Sep 13 16:49:13 2005
@@ -1,260 +1,41 @@
-from pypy.translator.backendoptimization import remove_void, inline_function
-from pypy.translator.backendoptimization import remove_simple_mallocs
+from pypy.translator.backendopt.malloc import remove_simple_mallocs
+from pypy.translator.backendopt.inline import inline_function
from pypy.translator.translator import Translator
-from pypy.rpython.lltype import Void
-from pypy.rpython.llinterp import LLInterpreter
from pypy.objspace.flow.model import checkgraph, flatten, Block
-from pypy.translator.test.snippet import simple_method, is_perfect_number
-from pypy.translator.llvm.log import log
-
-import py
-log = py.log.Producer('test_backendoptimization')
-
-def annotate_and_remove_void(f, annotate):
- t = Translator(f)
- a = t.annotate(annotate)
- t.specialize()
- remove_void(t)
- return t
-
-def test_remove_void_args():
- def f(i):
- return [1,2,3,i][i]
- t = annotate_and_remove_void(f, [int])
- for func, graph in t.flowgraphs.iteritems():
- assert checkgraph(graph) is None
- for arg in graph.startblock.inputargs:
- assert arg.concretetype is not Void
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- assert interp.eval_function(f, [0]) == 1
-
-def test_remove_void_in_struct():
- t = annotate_and_remove_void(simple_method, [int])
- #t.view()
- log(t.flowgraphs.iteritems())
- for func, graph in t.flowgraphs.iteritems():
- log('func : ' + str(func))
- log('graph: ' + str(graph))
- assert checkgraph(graph) is None
- #for fieldname in self.struct._names: #XXX helper (in lltype?) should remove these voids
- # type_ = getattr(struct, fieldname)
- # log('fieldname=%(fieldname)s , type_=%(type_)s' % locals())
- # assert _type is not Void
- #interp = LLInterpreter(t.flowgraphs, t.rtyper)
- #assert interp.eval_function(f, [0]) == 1
-
-def test_inline_simple():
- def f(x, y):
- return (g(x, y) + 1) * x
- def g(x, y):
- if x > 0:
- return x * y
- else:
- return -x * y
- t = Translator(f)
- a = t.annotate([int, int])
- a.simplify()
- t.specialize()
- inline_function(t, g, t.flowgraphs[f])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(f, [-1, 5])
- assert result == f(-1, 5)
- result = interp.eval_function(f, [2, 12])
- assert result == f(2, 12)
-
-def test_inline_big():
- def f(x):
- result = []
- for i in range(1, x+1):
- if is_perfect_number(i):
- result.append(i)
- return result
- t = Translator(f)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, is_perfect_number, t.flowgraphs[f])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(f, [10])
- assert result.length == len(f(10))
-
-def test_inline_raising():
- def f(x):
- if x == 1:
- raise ValueError
- return x
- def g(x):
- a = f(x)
- if x == 2:
- raise KeyError
- def h(x):
- try:
- g(x)
- except ValueError:
- return 1
- except KeyError:
- return 2
- return x
- t = Translator(h)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, f, t.flowgraphs[g])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(h, [0])
- assert result == 0
- result = interp.eval_function(h, [1])
- assert result == 1
- result = interp.eval_function(h, [2])
- assert result == 2
-
-def test_inline_several_times():
- def f(x):
- return (x + 1) * 2
- def g(x):
- if x:
- a = f(x) + f(x)
- else:
- a = f(x) + 1
- return a + f(x)
- t = Translator(g)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, f, t.flowgraphs[g])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(g, [0])
- assert result == g(0)
- result = interp.eval_function(g, [42])
- assert result == g(42)
-
-def test_inline_exceptions():
- def f(x):
- if x == 0:
- raise ValueError
- if x == 1:
- raise KeyError
- def g(x):
- try:
- f(x)
- except ValueError:
- return 2
- except KeyError:
- return x+2
- return 1
- t = Translator(g)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, f, t.flowgraphs[g])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(g, [0])
- assert result == 2
- result = interp.eval_function(g, [1])
- assert result == 3
- result = interp.eval_function(g, [42])
- assert result == 1
-
-def DONOTtest_inline_var_exception():
- # this test is disabled for now, because f() contains a direct_call
- # (at the end, to a ll helper, to get the type of the exception object)
- def f(x):
- e = None
- if x == 0:
- e = ValueError()
- elif x == 1:
- e = KeyError()
- if x == 0 or x == 1:
- raise e
- def g(x):
- try:
- f(x)
- except ValueError:
- return 2
- except KeyError:
- return 3
- return 1
- t = Translator(g)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, f, t.flowgraphs[g])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(g, [0])
- assert result == 2
- result = interp.eval_function(g, [1])
- assert result == 3
- result = interp.eval_function(g, [42])
- assert result == 1
-
-def DONOTtest_call_call():
- # for reference. Just remove this test if we decide not to support
- # catching exceptions while inlining a graph that contains further
- # direct_calls.
- def e(x):
- if x < 0:
- raise KeyError
- return x+1
- def f(x):
- return e(x)+2
- def g(x):
- try:
- return f(x)+3
- except KeyError:
- return -1
- t = Translator(g)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, f, t.flowgraphs[g])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(g, [100])
- assert result == 106
- result = interp.eval_function(g, [-100])
- assert result == -1
-
-def test_for_loop():
- def f(x):
- result = 0
- for i in range(0, x):
- result += i
- return result
- t = Translator(f)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- for graph in t.flowgraphs.values():
- if graph.name.startswith('ll_rangenext'):
- break
- else:
- assert 0, "cannot find ll_rangenext_*() function"
- inline_function(t, graph, t.flowgraphs[f])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(f, [10])
- assert result == 45
+from pypy.rpython.llinterp import LLInterpreter
+def check_malloc_removed(graph):
+ checkgraph(graph)
+ count1 = count2 = 0
+ for node in flatten(graph):
+ if isinstance(node, Block):
+ for op in node.operations:
+ if op.opname == 'malloc':
+ count1 += 1
+ if op.opname == 'direct_call':
+ count2 += 1
+ assert count1 == 0 # number of mallocs left
+ assert count2 == 0 # number of direct_calls left
-def check_malloc_removed(fn, signature, expected_remaining_mallocs):
+def check(fn, signature, args, expected_result):
t = Translator(fn)
t.annotate(signature)
t.specialize()
graph = t.getflowgraph()
remove_simple_mallocs(graph)
- checkgraph(graph)
- count = 0
- for node in flatten(graph):
- if isinstance(node, Block):
- for op in node.operations:
- if op.opname == 'malloc':
- count += 1
- assert count == expected_remaining_mallocs
+ check_malloc_removed(graph)
+ interp = LLInterpreter(t.flowgraphs, t.rtyper)
+ res = interp.eval_function(fn, args)
+ assert res == expected_result
+
-def test_remove_mallocs():
+def test_fn1():
def fn1(x, y):
s, d = x+y, x-y
return s*d
- yield check_malloc_removed, fn1, [int, int], 0
- #
+ check(fn1, [int, int], [15, 10], 125)
+
+def test_fn2():
class T:
pass
def fn2(x, y):
@@ -265,13 +46,15 @@
return t.x + t.y
else:
return t.x - t.y
- yield check_malloc_removed, fn2, [int, int], 0
- #
+ check(fn2, [int, int], [-6, 7], -13)
+
+def test_fn3():
def fn3(x):
a, ((b, c), d, e) = x+1, ((x+2, x+3), x+4, x+5)
return a+b+c+d+e
- yield check_malloc_removed, fn3, [int], 0
- #
+ check(fn3, [int], [10], 65)
+
+def test_fn4():
class A:
pass
class B(A):
@@ -282,4 +65,14 @@
a.b = b
b.i = i
return a.b.i
- yield check_malloc_removed, fn4, [int], 0
+ check(fn4, [int], [42], 42)
+
+def test_fn5():
+ class A:
+ attr = 666
+ class B(A):
+ attr = 42
+ def fn5():
+ b = B()
+ return b.attr
+ check(fn5, [], [], 42)
Modified: pypy/dist/pypy/translator/backendopt/test/test_ssa.py
==============================================================================
--- pypy/dist/pypy/translator/backend_opt/test/test_ssa.py (original)
+++ pypy/dist/pypy/translator/backendopt/test/test_ssa.py Tue Sep 13 16:49:13 2005
@@ -1,285 +1,2 @@
-from pypy.translator.backendoptimization import remove_void, inline_function
-from pypy.translator.backendoptimization import remove_simple_mallocs
-from pypy.translator.translator import Translator
-from pypy.rpython.lltype import Void
-from pypy.rpython.llinterp import LLInterpreter
-from pypy.objspace.flow.model import checkgraph, flatten, Block
-from pypy.translator.test.snippet import simple_method, is_perfect_number
-from pypy.translator.llvm.log import log
-import py
-log = py.log.Producer('test_backendoptimization')
-
-def annotate_and_remove_void(f, annotate):
- t = Translator(f)
- a = t.annotate(annotate)
- t.specialize()
- remove_void(t)
- return t
-
-def test_remove_void_args():
- def f(i):
- return [1,2,3,i][i]
- t = annotate_and_remove_void(f, [int])
- for func, graph in t.flowgraphs.iteritems():
- assert checkgraph(graph) is None
- for arg in graph.startblock.inputargs:
- assert arg.concretetype is not Void
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- assert interp.eval_function(f, [0]) == 1
-
-def test_remove_void_in_struct():
- t = annotate_and_remove_void(simple_method, [int])
- #t.view()
- log(t.flowgraphs.iteritems())
- for func, graph in t.flowgraphs.iteritems():
- log('func : ' + str(func))
- log('graph: ' + str(graph))
- assert checkgraph(graph) is None
- #for fieldname in self.struct._names: #XXX helper (in lltype?) should remove these voids
- # type_ = getattr(struct, fieldname)
- # log('fieldname=%(fieldname)s , type_=%(type_)s' % locals())
- # assert _type is not Void
- #interp = LLInterpreter(t.flowgraphs, t.rtyper)
- #assert interp.eval_function(f, [0]) == 1
-
-def test_inline_simple():
- def f(x, y):
- return (g(x, y) + 1) * x
- def g(x, y):
- if x > 0:
- return x * y
- else:
- return -x * y
- t = Translator(f)
- a = t.annotate([int, int])
- a.simplify()
- t.specialize()
- inline_function(t, g, t.flowgraphs[f])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(f, [-1, 5])
- assert result == f(-1, 5)
- result = interp.eval_function(f, [2, 12])
- assert result == f(2, 12)
-
-def test_inline_big():
- def f(x):
- result = []
- for i in range(1, x+1):
- if is_perfect_number(i):
- result.append(i)
- return result
- t = Translator(f)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, is_perfect_number, t.flowgraphs[f])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(f, [10])
- assert result.length == len(f(10))
-
-def test_inline_raising():
- def f(x):
- if x == 1:
- raise ValueError
- return x
- def g(x):
- a = f(x)
- if x == 2:
- raise KeyError
- def h(x):
- try:
- g(x)
- except ValueError:
- return 1
- except KeyError:
- return 2
- return x
- t = Translator(h)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, f, t.flowgraphs[g])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(h, [0])
- assert result == 0
- result = interp.eval_function(h, [1])
- assert result == 1
- result = interp.eval_function(h, [2])
- assert result == 2
-
-def test_inline_several_times():
- def f(x):
- return (x + 1) * 2
- def g(x):
- if x:
- a = f(x) + f(x)
- else:
- a = f(x) + 1
- return a + f(x)
- t = Translator(g)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, f, t.flowgraphs[g])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(g, [0])
- assert result == g(0)
- result = interp.eval_function(g, [42])
- assert result == g(42)
-
-def test_inline_exceptions():
- def f(x):
- if x == 0:
- raise ValueError
- if x == 1:
- raise KeyError
- def g(x):
- try:
- f(x)
- except ValueError:
- return 2
- except KeyError:
- return x+2
- return 1
- t = Translator(g)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, f, t.flowgraphs[g])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(g, [0])
- assert result == 2
- result = interp.eval_function(g, [1])
- assert result == 3
- result = interp.eval_function(g, [42])
- assert result == 1
-
-def DONOTtest_inline_var_exception():
- # this test is disabled for now, because f() contains a direct_call
- # (at the end, to a ll helper, to get the type of the exception object)
- def f(x):
- e = None
- if x == 0:
- e = ValueError()
- elif x == 1:
- e = KeyError()
- if x == 0 or x == 1:
- raise e
- def g(x):
- try:
- f(x)
- except ValueError:
- return 2
- except KeyError:
- return 3
- return 1
- t = Translator(g)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, f, t.flowgraphs[g])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(g, [0])
- assert result == 2
- result = interp.eval_function(g, [1])
- assert result == 3
- result = interp.eval_function(g, [42])
- assert result == 1
-
-def DONOTtest_call_call():
- # for reference. Just remove this test if we decide not to support
- # catching exceptions while inlining a graph that contains further
- # direct_calls.
- def e(x):
- if x < 0:
- raise KeyError
- return x+1
- def f(x):
- return e(x)+2
- def g(x):
- try:
- return f(x)+3
- except KeyError:
- return -1
- t = Translator(g)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- inline_function(t, f, t.flowgraphs[g])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(g, [100])
- assert result == 106
- result = interp.eval_function(g, [-100])
- assert result == -1
-
-def test_for_loop():
- def f(x):
- result = 0
- for i in range(0, x):
- result += i
- return result
- t = Translator(f)
- a = t.annotate([int])
- a.simplify()
- t.specialize()
- for graph in t.flowgraphs.values():
- if graph.name.startswith('ll_rangenext'):
- break
- else:
- assert 0, "cannot find ll_rangenext_*() function"
- inline_function(t, graph, t.flowgraphs[f])
- interp = LLInterpreter(t.flowgraphs, t.rtyper)
- result = interp.eval_function(f, [10])
- assert result == 45
-
-
-def check_malloc_removed(fn, signature, expected_remaining_mallocs):
- t = Translator(fn)
- t.annotate(signature)
- t.specialize()
- graph = t.getflowgraph()
- remove_simple_mallocs(graph)
- checkgraph(graph)
- count = 0
- for node in flatten(graph):
- if isinstance(node, Block):
- for op in node.operations:
- if op.opname == 'malloc':
- count += 1
- assert count == expected_remaining_mallocs
-
-def test_remove_mallocs():
- def fn1(x, y):
- s, d = x+y, x-y
- return s*d
- yield check_malloc_removed, fn1, [int, int], 0
- #
- class T:
- pass
- def fn2(x, y):
- t = T()
- t.x = x
- t.y = y
- if x > 0:
- return t.x + t.y
- else:
- return t.x - t.y
- yield check_malloc_removed, fn2, [int, int], 0
- #
- def fn3(x):
- a, ((b, c), d, e) = x+1, ((x+2, x+3), x+4, x+5)
- return a+b+c+d+e
- yield check_malloc_removed, fn3, [int], 0
- #
- class A:
- pass
- class B(A):
- pass
- def fn4(i):
- a = A()
- b = B()
- a.b = b
- b.i = i
- return a.b.i
- yield check_malloc_removed, fn4, [int], 0
+# XXX write a test!
Modified: pypy/dist/pypy/translator/c/test/test_backendoptimized.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_backendoptimized.py (original)
+++ pypy/dist/pypy/translator/c/test/test_backendoptimized.py Tue Sep 13 16:49:13 2005
@@ -1,7 +1,6 @@
import autopath
from pypy.translator.tool.cbuild import skip_missing_compiler
from pypy.translator.translator import Translator
-from pypy.translator import backendoptimization
from pypy.translator.c.test.test_typed import TestTypedTestCase as _TestTypedTestCase
@@ -20,8 +19,7 @@
a = t.annotate(argstypelist)
a.simplify()
t.specialize()
- for graph in t.flowgraphs.values():
- backendoptimization.backend_optimizations(graph)
+ t.backend_optimizations()
t.checkgraphs()
return skip_missing_compiler(t.ccompile)
Modified: pypy/dist/pypy/translator/geninterplevel.py
==============================================================================
--- pypy/dist/pypy/translator/geninterplevel.py (original)
+++ pypy/dist/pypy/translator/geninterplevel.py Tue Sep 13 16:49:13 2005
@@ -56,7 +56,7 @@
from pypy.interpreter.error import OperationError
from pypy.interpreter.argument import Arguments
from pypy.rpython.rarithmetic import r_int, r_uint
-from pypy.translator.backendoptimization import SSI_to_SSA
+from pypy.translator.backendopt.ssa import SSI_to_SSA
from pypy.translator.translator import Translator
from pypy.objspace.flow import FlowObjSpace
Modified: pypy/dist/pypy/translator/llvm/funcnode.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/funcnode.py (original)
+++ pypy/dist/pypy/translator/llvm/funcnode.py Tue Sep 13 16:49:13 2005
@@ -2,7 +2,6 @@
from pypy.objspace.flow.model import Block, Constant, Variable, Link
from pypy.objspace.flow.model import flatten, mkentrymap, traverse, last_exception
from pypy.rpython import lltype
-from pypy.translator.backendoptimization import backend_optimizations
from pypy.translator.unsimplify import remove_double_links
from pypy.translator.llvm.node import LLVMNode, ConstantLLVMNode
from pypy.translator.llvm.opwriter import OpWriter
@@ -37,8 +36,9 @@
self.db = db
self.value = value
self.ref = self.make_ref('%pypy_', value.graph.name)
- self.graph = value.graph
- backend_optimizations(self.graph, opt_SSI_to_SSA=False)
+ self.graph = value.graph
+ # XXX the following needs to be done in advance (e.g. for inlining)
+ #backend_optimizations(self.graph, opt_SSI_to_SSA=False)
remove_double_links(self.db.translator, self.graph)
def __str__(self):
Modified: pypy/dist/pypy/translator/translator.py
==============================================================================
--- pypy/dist/pypy/translator/translator.py (original)
+++ pypy/dist/pypy/translator/translator.py Tue Sep 13 16:49:13 2005
@@ -142,10 +142,9 @@
self.rtyper = RPythonTyper(self.annotator)
self.rtyper.specialize(**flags)
- def backend_optimizations(self):
- from pypy.translator.backendoptimization import backend_optimizations
- for graph in self.flowgraphs.values():
- backend_optimizations(graph)
+ def backend_optimizations(self, **kwds):
+ from pypy.translator.backendopt.all import backend_optimizations
+ backend_optimizations(self, **kwds)
def source(self, func=None):
"""Returns original Python source.
More information about the Pypy-commit
mailing list