[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