[pypy-commit] pypy jit-multilabel: add support for optimizing over multiple intermediate labels

hakanardo noreply at buildbot.pypy.org
Sun Dec 18 11:14:40 CET 2011


Author: Hakan Ardo <hakan at debian.org>
Branch: jit-multilabel
Changeset: r50647:94ea6fc640c5
Date: 2011-12-18 11:01 +0100
http://bitbucket.org/pypy/pypy/changeset/94ea6fc640c5/

Log:	add support for optimizing over multiple intermediate labels

diff --git a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
@@ -8,7 +8,7 @@
 class BaseTestMultiLabel(BaseTest):
     enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll"
 
-    def optimize_loop(self, ops, expected):
+    def optimize_loop(self, ops, expected, expected_shorts=None):
         loop = self.parse(ops)
         if expected != "crash!":
             expected = self.parse(expected)
@@ -32,15 +32,17 @@
             if nxt < len(loop.operations):
                 label = loop.operations[nxt]
                 assert label.getopnum() == rop.LABEL
-                jumpop = ResOperation(rop.JUMP, label.getarglist(),
-                                      None, descr=token)
-                operations.append(jumpop)
+                if label.getdescr() is None:
+                    label.setdescr(token)
+                operations.append(label)
             part.operations = operations
+
             self._do_optimize_loop(part, None)
             if part.operations[-1].getopnum() == rop.LABEL:
                 last_label = [part.operations.pop()]
             else:
                 last_label = []
+            
             optimized.operations.extend(part.operations)
             prv = nxt + 1
         
@@ -53,9 +55,32 @@
             print 'Failed!'
         print
 
+        shorts = [op.getdescr().short_preamble
+                  for op in optimized.operations
+                  if op.getopnum() == rop.LABEL]
+
+        if expected_shorts:
+            for short in shorts:
+                print
+                print "Short preamble:"
+                print '\n'.join([str(o) for o in short])
+
+
         assert expected != "crash!", "should have raised an exception"
         self.assert_equal(optimized, expected)
 
+        if expected_shorts:
+            assert len(shorts) == len(expected_shorts)
+            for short, expected_short in zip(shorts, expected_shorts):
+                expected_short = self.parse(expected_short)
+                short_preamble = TreeLoop('short preamble')
+                assert short[0].getopnum() == rop.LABEL
+                short_preamble.inputargs = short[0].getarglist()
+                short_preamble.operations = short
+                self.assert_equal(short_preamble, expected_short,
+                                  text_right='expected short preamble')
+
+        
         return optimized
 
     def test_simple(self):
@@ -193,8 +218,168 @@
         """
         with raises(InvalidLoop):
             self.optimize_loop(ops, ops)
-        
+
+    def test_two_intermediate_labels_basic_1(self):
+        ops = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i1)
+        i3 = getfield_gc(p1, descr=valuedescr)
+        i4 = int_add(i1, i3)
+        label(p1, i4)
+        i5 = int_add(i4, 1)
+        jump(p1, i5)
+        """
+        expected = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i1, i2)
+        i4 = int_add(i1, i2)
+        label(p1, i4)
+        i5 = int_add(i4, 1)
+        jump(p1, i5)
+        """
+        short1 = """
+        [p1, i1]
+        label(p1, i1)
+        i2 = getfield_gc(p1, descr=valuedescr)
+        jump(p1, i1, i2)
+        """
+        short2 = """
+        [p1, i1]
+        label(p1, i1)
+        jump(p1, i1)
+        """
+        self.optimize_loop(ops, expected, expected_shorts=[short1, short2])
+
+    def test_two_intermediate_labels_basic_2(self):
+        ops = """
+        [p1, i1]
+        i2 = int_add(i1, 1)
+        label(p1, i1)
+        i3 = getfield_gc(p1, descr=valuedescr)
+        i4 = int_add(i1, i3)
+        label(p1, i4)
+        i5 = getfield_gc(p1, descr=valuedescr)
+        i6 = int_add(i4, i5)
+        jump(p1, i6)
+        """
+        expected = """
+        [p1, i1]
+        i2 = int_add(i1, 1)
+        label(p1, i1)
+        i3 = getfield_gc(p1, descr=valuedescr)
+        i4 = int_add(i1, i3)
+        label(p1, i4, i3)
+        i6 = int_add(i4, i3)
+        jump(p1, i6, i3)
+        """
+        short1 = """
+        [p1, i1]
+        label(p1, i1)
+        jump(p1, i1)
+        """
+        short2 = """
+        [p1, i1]
+        label(p1, i1)
+        i2 = getfield_gc(p1, descr=valuedescr)
+        jump(p1, i1, i2)
+        """
+        self.optimize_loop(ops, expected, expected_shorts=[short1, short2])
+
+    def test_two_intermediate_labels_both(self):
+        ops = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i1)
+        i3 = getfield_gc(p1, descr=valuedescr)
+        i4 = int_add(i1, i3)
+        label(p1, i4)
+        i5 = getfield_gc(p1, descr=valuedescr)
+        i6 = int_mul(i4, i5)
+        jump(p1, i6)
+        """
+        expected = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i1, i2)
+        i4 = int_add(i1, i2)
+        label(p1, i4, i2)
+        i6 = int_mul(i4, i2)
+        jump(p1, i6, i2)
+        """
+        short = """
+        [p1, i1]
+        label(p1, i1)
+        i2 = getfield_gc(p1, descr=valuedescr)        
+        jump(p1, i1, i2)
+        """
+        self.optimize_loop(ops, expected, expected_shorts=[short, short])
+
+    def test_import_across_multiple_labels_basic(self):
+        # Not supported, juts make sure we get a functional trace
+        ops = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i1)
+        i3 = int_add(i1, 1)
+        label(p1, i1)
+        i4 = getfield_gc(p1, descr=valuedescr)
+        i5 = int_add(i4, 1)
+        jump(p1, i5)
+        """
+        self.optimize_loop(ops, ops)
+
+    def test_import_across_multiple_labels_with_duplication(self):
+        # Not supported, juts make sure we get a functional trace
+        ops = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i2)
+        i3 = int_add(i2, 1)
+        label(p1, i2)
+        i4 = getfield_gc(p1, descr=valuedescr)
+        i5 = int_add(i4, 1)
+        jump(p1, i5)
+        """
+        exported = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        i6 = same_as(i2)
+        label(p1, i2)
+        i3 = int_add(i2, 1)
+        label(p1, i2)
+        i4 = getfield_gc(p1, descr=valuedescr)
+        i5 = int_add(i4, 1)
+        jump(p1, i5)
+        """
+        self.optimize_loop(ops, exported)
     
+    def test_import_virtual_across_multiple_labels(self):
+        ops = """
+        [p0, i1]
+        i1a = int_add(i1, 1)
+        pv = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(pv, i1a, descr=valuedescr)
+        label(pv, i1)
+        i2 = int_mul(i1, 3)
+        label(pv, i2)
+        i3 = getfield_gc(pv, descr=valuedescr)
+        i4 = int_add(i3, i2)
+        jump(pv, i4)
+        """
+        expected = """
+        [p0, i1]
+        i1a = int_add(i1, 1)
+        i5 = same_as(i1a)
+        label(i1a, i1)
+        i2 = int_mul(i1, 3)
+        label(i1a, i2)
+        i4 = int_add(i1a, i2)
+        jump(i1a, i4)
+        """
+        self.optimize_loop(ops, expected)
+
 class TestLLtype(BaseTestMultiLabel, LLtypeMixin):
     pass
 
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -54,6 +54,7 @@
     
     def __init__(self, metainterp_sd, loop, optimizations):
         self.optimizer = UnrollableOptimizer(metainterp_sd, loop, optimizations)
+        self.boxes_created_this_iteration = None
 
     def fix_snapshot(self, jump_args, snapshot):
         if snapshot is None:
@@ -129,6 +130,12 @@
                     return
 
         # Found nothing to jump to, emit a label instead
+        
+        if self.short:
+            # Construct our short preamble
+            assert start_label
+            self.close_bridge(start_label)
+
         self.optimizer.flush()
         KillHugeIntBounds(self.optimizer).apply()
 
@@ -172,7 +179,13 @@
         inputargs = virtual_state.make_inputargs(values, self.optimizer)
         short_inputargs = virtual_state.make_inputargs(values, self.optimizer, keyboxes=True)
 
-        short_boxes = ShortBoxes(self.optimizer, inputargs)
+
+        if self.boxes_created_this_iteration is not None:
+            for box in self.inputargs:
+                self.boxes_created_this_iteration[box] = True
+
+        short_boxes = ShortBoxes(self.optimizer, inputargs,
+                                 self.boxes_created_this_iteration)
 
         self.optimizer.clear_newoperations()
         for i in range(len(original_jump_args)):
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -559,12 +559,13 @@
     pass
 
 class ShortBoxes(object):
-    def __init__(self, optimizer, surviving_boxes):
+    def __init__(self, optimizer, surviving_boxes, availible_boxes=None):
         self.potential_ops = {}
         self.alternatives = {}
         self.synthetic = {}
         self.rename = {}
         self.optimizer = optimizer
+        self.availible_boxes = availible_boxes
 
         if surviving_boxes is not None:
             for box in surviving_boxes:
@@ -635,6 +636,8 @@
             return
         if box in self.short_boxes_in_production:
             raise BoxNotProducable
+        if self.availible_boxes is not None and box not in self.availible_boxes:
+            raise BoxNotProducable
         self.short_boxes_in_production[box] = True
         
         if box in self.potential_ops:


More information about the pypy-commit mailing list