Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r59951:02f2e74659ab
Date: 2013-01-11 15:35 +0100
http://bitbucket.org/pypy/pypy/changeset/02f2e74659ab/

Log:    jitdriver(reds='auto'): fix it to only include the red vars that are
        alive across the jitdriver. Test. Move the logic to support, too.

diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -10,7 +10,7 @@
 from pypy.rpython.extregistry import ExtRegistryEntry
 from pypy.translator.simplify import get_funcobj
 from pypy.translator.unsimplify import split_block
-from pypy.objspace.flow.model import Constant
+from pypy.objspace.flow.model import Variable, Constant
 from pypy.translator.translator import TranslationContext
 from pypy.annotation.policy import AnnotatorPolicy
 from pypy.annotation import model as annmodel
@@ -59,6 +59,45 @@
     rtyper = annotate(func, values)
     return rtyper.annotator.translator.graphs[0]
 
+def autodetect_jit_markers_redvars(graph):
+    # the idea is to find all the jit_merge_point and
+    # add all the variables across the links to the reds.
+    for block, op in graph.iterblockops():
+        if op.opname == 'jit_marker':
+            jitdriver = op.args[1].value
+            if not jitdriver.autoreds:
+                continue
+            # if we want to support also can_enter_jit, we should find a
+            # way to detect a consistent set of red vars to pass *both* to
+            # jit_merge_point and can_enter_jit. The current simple
+            # solution doesn't work because can_enter_jit might be in
+            # another block, so the set of alive_v will be different.
+            methname = op.args[0].value
+            assert methname == 'jit_merge_point', (
+                "reds='auto' is supported only for jit drivers which " 
+                "calls only jit_merge_point. Found a call to %s" % methname)
+            #
+            # compute the set of live variables across the jit_marker
+            alive_v = set()
+            for link in block.exits:
+                alive_v.update(link.args)
+                alive_v.difference_update(link.getextravars())
+            for op1 in block.operations[::-1]:
+                if op1 is op:
+                    break # stop when the meet the jit_marker
+                alive_v.discard(op1.result)
+                alive_v.update(op1.args)
+            greens_v = op.args[2:]
+            reds_v = alive_v - set(greens_v)
+            reds_v = [v for v in reds_v if isinstance(v, Variable) and
+                                           v.concretetype is not lltype.Void]
+            reds_v = sort_vars(reds_v)
+            op.args.extend(reds_v)
+            if jitdriver.numreds is None:
+                jitdriver.numreds = len(reds_v)
+            else:
+                assert jitdriver.numreds == len(reds_v), 'inconsistent number 
of reds_v'
+
 def split_before_jit_merge_point(graph, portalblock, portalopindex):
     """Split the block just before the 'jit_merge_point',
     making sure the input args are in the canonical order.
diff --git a/pypy/jit/metainterp/test/test_warmspot.py 
b/pypy/jit/metainterp/test/test_warmspot.py
--- a/pypy/jit/metainterp/test/test_warmspot.py
+++ b/pypy/jit/metainterp/test/test_warmspot.py
@@ -383,6 +383,23 @@
         assert res == expected
         self.check_resops(int_sub=2, int_mul=0, int_add=2)
 
+    def test_loop_automatic_reds_not_too_many_redvars(self):
+        myjitdriver = JitDriver(greens = ['m'], reds = 'auto')
+        def one():
+            return 1
+        def f(n, m):
+            res = 0
+            while n > 0:
+                n -= one()
+                myjitdriver.jit_merge_point(m=m)
+                res += m*2
+            return res
+        expected = f(21, 5)
+        res = self.meta_interp(f, [21, 5])
+        assert res == expected
+        oplabel = get_stats().loops[0].operations[0]
+        assert len(oplabel.getarglist()) == 2     # 'n', 'res' in some order
+
     def test_inline_jit_merge_point(self):
         # test that the machinery to inline jit_merge_points in callers
         # works. The final user does not need to mess manually with the
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -347,49 +347,13 @@
         self.jitdrivers_sd = []
         graphs = self.translator.graphs
         for graph, block, pos in find_jit_merge_points(graphs):
-            self.autodetect_jit_markers_redvars(graph)
+            support.autodetect_jit_markers_redvars(graph)
             self.split_graph_and_record_jitdriver(graph, block, pos)
         #
         assert (len(set([jd.jitdriver for jd in self.jitdrivers_sd])) ==
                 len(self.jitdrivers_sd)), \
                 "there are multiple jit_merge_points with the same jitdriver"
 
-    def autodetect_jit_markers_redvars(self, graph):
-        # the idea is to find all the jit_merge_point and can_enter_jit and
-        # add all the variables across the links to the reds.
-        for block, op in graph.iterblockops():
-            if op.opname == 'jit_marker':
-                jitdriver = op.args[1].value
-                if not jitdriver.autoreds:
-                    continue
-                # if we want to support also can_enter_jit, we should find a
-                # way to detect a consistent set of red vars to pass *both* to
-                # jit_merge_point and can_enter_jit. The current simple
-                # solution doesn't work because can_enter_jit might be in
-                # another block, so the set of alive_v will be different.
-                methname = op.args[0].value
-                assert methname == 'jit_merge_point', (
-                    "reds='auto' is supported only for jit drivers which " 
-                    "calls only jit_merge_point. Found a call to %s" % 
methname)
-                #
-                # compute the set of live variables before the jit_marker
-                alive_v = set(block.inputargs)
-                for op1 in block.operations:
-                    if op1 is op:
-                        break # stop when the meet the jit_marker
-                    if op1.result.concretetype != lltype.Void:
-                        alive_v.add(op1.result)
-                greens_v = op.args[2:]
-                reds_v = alive_v - set(greens_v)
-                reds_v = [v for v in reds_v if v.concretetype is not 
lltype.Void]
-                reds_v = support.sort_vars(reds_v)
-                op.args.extend(reds_v)
-                if jitdriver.numreds is None:
-                    jitdriver.numreds = len(reds_v)
-                else:
-                    assert jitdriver.numreds == len(reds_v), 'inconsistent 
number of reds_v'
-
-
     def split_graph_and_record_jitdriver(self, graph, block, pos):
         op = block.operations[pos]
         jd = JitDriverStaticData()
@@ -717,6 +681,9 @@
             jitdriver = op.args[1].value
             assert jitdriver in sublists, \
                    "can_enter_jit with no matching jit_merge_point"
+            assert not jitdriver.autoreds, (
+                   "can_enter_jit not supported with a jitdriver that "
+                   "has reds='auto'")
             jd, sublist = sublists[jitdriver]
             origportalgraph = jd._jit_merge_point_in
             if graph is not origportalgraph:
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to