[pypy-commit] pypy default: merge getarrayitem-into-bridges:

cfbolz pypy.commits at gmail.com
Fri Aug 4 11:26:14 EDT 2017


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: 
Changeset: r92076:43ff4a9015e3
Date: 2017-08-04 16:54 +0200
http://bitbucket.org/pypy/pypy/changeset/43ff4a9015e3/

Log:	merge getarrayitem-into-bridges:

	improvement on what information is retained into a bridge: in
	particular, knowledge about the content of arrays (at fixed indices)
	is stored in guards (and thus available at the beginning of
	bridges). also, some better handling of constants.

diff --git a/rpython/jit/metainterp/optimizeopt/bridgeopt.py b/rpython/jit/metainterp/optimizeopt/bridgeopt.py
--- a/rpython/jit/metainterp/optimizeopt/bridgeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/bridgeopt.py
@@ -18,6 +18,10 @@
 # (<box1> <descr> <box2>) length times, if getfield(box1, descr) == box2
 #                         both boxes should be in the liveboxes
 #
+# <length>
+# (<box1> <index> <descr> <box2>) length times, if getarrayitem_gc(box1, index, descr) == box2
+#                                 both boxes should be in the liveboxes
+#
 # ----
 
 
@@ -82,18 +86,26 @@
     # structs
     # XXX could be extended to arrays
     if optimizer.optheap:
-        triples = optimizer.optheap.serialize_optheap(available_boxes)
+        triples_struct, triples_array = optimizer.optheap.serialize_optheap(available_boxes)
         # can only encode descrs that have a known index into
         # metainterp_sd.all_descrs
-        triples = [triple for triple in triples if triple[1].descr_index != -1]
-        numb_state.append_int(len(triples))
-        for box1, descr, box2 in triples:
-            index = descr.descr_index
+        triples_struct = [triple for triple in triples_struct if triple[1].descr_index != -1]
+        numb_state.append_int(len(triples_struct))
+        for box1, descr, box2 in triples_struct:
+            descr_index = descr.descr_index
+            numb_state.append_short(tag_box(box1, liveboxes_from_env, memo))
+            numb_state.append_int(descr_index)
+            numb_state.append_short(tag_box(box2, liveboxes_from_env, memo))
+        numb_state.append_int(len(triples_array))
+        for box1, index, descr, box2 in triples_array:
+            descr_index = descr.descr_index
             numb_state.append_short(tag_box(box1, liveboxes_from_env, memo))
             numb_state.append_int(index)
+            numb_state.append_int(descr_index)
             numb_state.append_short(tag_box(box2, liveboxes_from_env, memo))
     else:
         numb_state.append_int(0)
+        numb_state.append_int(0)
 
 def deserialize_optimizer_knowledge(optimizer, resumestorage, frontend_boxes, liveboxes):
     reader = resumecode.Reader(resumestorage.rd_numb)
@@ -123,13 +135,24 @@
     if not optimizer.optheap:
         return
     length = reader.next_item()
-    result = []
+    result_struct = []
+    for i in range(length):
+        tagged = reader.next_item()
+        box1 = decode_box(resumestorage, tagged, liveboxes, metainterp_sd.cpu)
+        descr_index = reader.next_item()
+        descr = metainterp_sd.all_descrs[descr_index]
+        tagged = reader.next_item()
+        box2 = decode_box(resumestorage, tagged, liveboxes, metainterp_sd.cpu)
+        result_struct.append((box1, descr, box2))
+    length = reader.next_item()
+    result_array = []
     for i in range(length):
         tagged = reader.next_item()
         box1 = decode_box(resumestorage, tagged, liveboxes, metainterp_sd.cpu)
         index = reader.next_item()
-        descr = metainterp_sd.all_descrs[index]
+        descr_index = reader.next_item()
+        descr = metainterp_sd.all_descrs[descr_index]
         tagged = reader.next_item()
         box2 = decode_box(resumestorage, tagged, liveboxes, metainterp_sd.cpu)
-        result.append((box1, descr, box2))
-    optimizer.optheap.deserialize_optheap(result)
+        result_array.append((box1, index, descr, box2))
+    optimizer.optheap.deserialize_optheap(result_struct, result_array)
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -698,7 +698,7 @@
         return self.emit(op)
 
     def serialize_optheap(self, available_boxes):
-        result = []
+        result_getfield = []
         for descr, cf in self.cached_fields.iteritems():
             if cf._lazy_set:
                 continue # XXX safe default for now
@@ -706,27 +706,62 @@
             if not parent_descr.is_object():
                 continue # XXX could be extended to non-instance objects
             for i, box1 in enumerate(cf.cached_structs):
-                if box1 not in available_boxes:
+                if not box1.is_constant() and box1 not in available_boxes:
                     continue
                 structinfo = cf.cached_infos[i]
-                box2 = structinfo.getfield(descr).get_box_replacement()
-                if isinstance(box2, Const) or box2 in available_boxes:
-                    result.append((box1, descr, box2))
-        return result
+                box2 = structinfo.getfield(descr)
+                if box2 is None:
+                    # XXX this should not happen, as it is an invariant
+                    # violation! yet it does if box1 is a constant
+                    continue
+                box2 = box2.get_box_replacement()
+                if box2.is_constant() or box2 in available_boxes:
+                    result_getfield.append((box1, descr, box2))
+        result_array = []
+        for descr, indexdict in self.cached_arrayitems.iteritems():
+            for index, cf in indexdict.iteritems():
+                if cf._lazy_set:
+                    continue # XXX safe default for now
+                for i, box1 in enumerate(cf.cached_structs):
+                    if not box1.is_constant() and box1 not in available_boxes:
+                        continue
+                    arrayinfo = cf.cached_infos[i]
+                    box2 = arrayinfo.getitem(descr, index)
+                    if box2 is None:
+                        # XXX this should not happen, as it is an invariant
+                        # violation! yet it does if box1 is a constant
+                        continue
+                    box2 = box2.get_box_replacement()
+                    if box2.is_constant() or box2 in available_boxes:
+                        result_array.append((box1, index, descr, box2))
+        return result_getfield, result_array
 
-    def deserialize_optheap(self, triples):
-        for box1, descr, box2 in triples:
+    def deserialize_optheap(self, triples_struct, triples_array):
+        for box1, descr, box2 in triples_struct:
             parent_descr = descr.get_parent_descr()
             assert parent_descr.is_object()
-            structinfo = box1.get_forwarded()
-            if not isinstance(structinfo, info.AbstractVirtualPtrInfo):
-                structinfo = info.InstancePtrInfo(parent_descr)
-                structinfo.init_fields(parent_descr, descr.get_index())
-                box1.set_forwarded(structinfo)
-
+            if box1.is_constant():
+                structinfo = info.ConstPtrInfo(box1)
+            else:
+                structinfo = box1.get_forwarded()
+                if not isinstance(structinfo, info.AbstractVirtualPtrInfo):
+                    structinfo = info.InstancePtrInfo(parent_descr)
+                    structinfo.init_fields(parent_descr, descr.get_index())
+                    box1.set_forwarded(structinfo)
             cf = self.field_cache(descr)
             structinfo.setfield(descr, box1, box2, optheap=self, cf=cf)
 
+        for box1, index, descr, box2 in triples_array:
+            if box1.is_constant():
+                arrayinfo = info.ConstPtrInfo(box1)
+            else:
+                arrayinfo = box1.get_forwarded()
+                if not isinstance(arrayinfo, info.AbstractVirtualPtrInfo):
+                    arrayinfo = info.ArrayPtrInfo(descr)
+                    box1.set_forwarded(arrayinfo)
+            cf = self.arrayitem_cache(descr, index)
+            arrayinfo.setitem(descr, index, box1, box2, optheap=self, cf=cf)
+
 
 dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_',
                                       default=OptHeap.emit)
diff --git a/rpython/jit/metainterp/test/test_bridgeopt.py b/rpython/jit/metainterp/test/test_bridgeopt.py
--- a/rpython/jit/metainterp/test/test_bridgeopt.py
+++ b/rpython/jit/metainterp/test/test_bridgeopt.py
@@ -61,7 +61,7 @@
 
     serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, {}, None)
 
-    assert unpack_numbering(numb_state.create_numbering()) == [1, 0b010000, 0]
+    assert unpack_numbering(numb_state.create_numbering()) == [1, 0b010000, 0, 0]
 
     rbox1 = InputArgRef()
     rbox2 = InputArgRef()
@@ -97,7 +97,7 @@
 
     serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, {}, None)
 
-    assert len(numb_state.create_numbering().code) == 2 + math.ceil(len(refboxes) / 6.0)
+    assert len(numb_state.create_numbering().code) == 3 + math.ceil(len(refboxes) / 6.0)
 
     dct = {box: cls
               for box, known_class in boxes_known_classes
@@ -143,11 +143,7 @@
     def test_bridge_field_read(self):
         myjitdriver = jit.JitDriver(greens=[], reds=['y', 'res', 'n', 'a'])
         class A(object):
-            def f(self):
-                return 1
-        class B(A):
-            def f(self):
-                return 2
+            pass
         class M(object):
             _immutable_fields_ = ['x']
             def __init__(self, x):
@@ -156,14 +152,12 @@
         m1 = M(1)
         m2 = M(2)
         def f(x, y, n):
+            a = A()
+            a.n = n
             if x:
-                a = A()
                 a.m = m1
-                a.n = n
             else:
-                a = B()
                 a.m = m2
-                a.n = n
             a.x = 0
             res = 0
             while y > 0:
@@ -186,3 +180,105 @@
         self.check_resops(getfield_gc_i=4) # 3x a.x, 1x a.n
         self.check_resops(getfield_gc_r=1) # in main loop
 
+    def test_bridge_field_read_constants(self):
+        myjitdriver = jit.JitDriver(greens=[], reds=['y', 'res', 'n'])
+        class A(object):
+            pass
+        class M(object):
+            _immutable_fields_ = ['x']
+            def __init__(self, x):
+                self.x = x
+
+        m1 = M(1)
+        m2 = M(2)
+        a = A()
+        a.m = m1
+        a.n = 0
+        def f(x, y, n):
+            if x:
+                a.m = m1
+                a.n = n
+            else:
+                a.m = m2
+                a.n = n
+            a.x = 0
+            res = 0
+            while y > 0:
+                myjitdriver.jit_merge_point(y=y, n=n, res=res)
+                n1 = a.n
+                m = jit.promote(a.m)
+                res += m.x
+                a.x += 1
+                if y > n:
+                    res += 1
+                m = jit.promote(a.m)
+                res += m.x
+                res += n1 + a.n
+                y -= 1
+            return res
+        res = self.meta_interp(f, [6, 32, 16])
+        assert res == f(6, 32, 16)
+        self.check_trace_count(3)
+        self.check_resops(guard_value=1)
+        self.check_resops(getfield_gc_i=4) # 3x a.x, 1x a.n
+        self.check_resops(getfield_gc_r=1) # in main loop
+
+    def test_bridge_array_read(self):
+        myjitdriver = jit.JitDriver(greens=[], reds=['y', 'res', 'n', 'a'])
+        def f(x, y, n):
+            if x:
+                a = [1, n, 0]
+            else:
+                a = [2, n, 0]
+            res = 0
+            while y > 0:
+                myjitdriver.jit_merge_point(y=y, n=n, res=res, a=a)
+                n1 = a[1]
+                m = jit.promote(a[0])
+                res += m
+                a[2] += 1
+                if y > n:
+                    res += 1
+                m = jit.promote(a[0])
+                res += m
+                res += n1 + a[1]
+                y -= 1
+            return res
+        res = self.meta_interp(f, [6, 32, 16])
+        assert res == f(6, 32, 16)
+        self.check_trace_count(3)
+        self.check_resops(guard_value=1)
+        self.check_resops(getarrayitem_gc_i=4)
+
+    def test_bridge_array_read_constant(self):
+        myjitdriver = jit.JitDriver(greens=[], reds=['y', 'res', 'n'])
+        class A(object):
+            pass
+        a = A()
+        a.l = [1, -65, 0]
+        def f(x, y, n):
+            if x:
+                a.l[0] = 1
+            else:
+                a.l[0] = 2
+            a.l[1] = n
+            a.l[2] = 0
+            res = 0
+            while y > 0:
+                myjitdriver.jit_merge_point(y=y, n=n, res=res)
+                n1 = a.l[1]
+                m = jit.promote(a.l[0])
+                res += m
+                a.l[2] += 1
+                if y > n:
+                    res += 1
+                m = jit.promote(a.l[0])
+                res += m
+                res += n1 + a.l[1]
+                y -= 1
+            return res
+        res = self.meta_interp(f, [6, 32, 16])
+        assert res == f(6, 32, 16)
+        self.check_trace_count(3)
+        self.check_resops(guard_value=1)
+        self.check_resops(getarrayitem_gc_i=5)


More information about the pypy-commit mailing list