Commits

Armin Rigo committed 4f4c1bd

Pointer comparison barrier.

Comments (0)

Files changed (2)

pypy/translator/stm/test/test_transform2.py

 class _stmptr(lltype._ptr):
     """Like lltype._ptr, but also keeps a current category level"""
 
-    __slots__ = ['_category']
+    __slots__ = ['_category', '_original_ptr']
 
     def __init__(self, ptr, category):
         lltype._ptr.__init__(self, ptr._TYPE, ptr._obj0, ptr._solid)
         _stmptr._category.__set__(self, category)
+        _stmptr._original_ptr.__set__(self, ptr)
+
+    def __eq__(self, other):
+        return self._original_ptr == other
 
 
 class BaseTestTransform(object):
         self.llinterpreter.tester.barriers.append(kind)
         return ptr2
 
+    def op_stm_ptr_eq(self, obj1, obj2):
+        self.check_category(obj1, 'P')
+        self.check_category(obj2, 'P')
+        self.llinterpreter.tester.barriers.append('=')
+        return obj1 == obj2
+
     def op_getfield(self, obj, field):
         self.check_category(obj, 'R')
         return LLFrame.op_getfield(self, obj, field)
         res = self.interpret(f1, [x])
         assert res == 36
         assert self.barriers == ['P2R']
+
+    def test_pointer_compare_0(self):
+        X = lltype.GcStruct('X', ('foo', lltype.Signed))
+        def f1(x):
+            return x != lltype.nullptr(X)
+        x = lltype.malloc(X, immortal=True)
+        res = self.interpret(f1, [x])
+        assert res == 1
+        assert self.barriers == []
+
+    def test_pointer_compare_1(self):
+        X = lltype.GcStruct('X', ('foo', lltype.Signed))
+        def f1(x, y):
+            return x != y
+        x = lltype.malloc(X, immortal=True)
+        y = lltype.malloc(X, immortal=True)
+        res = self.interpret(f1, [x, y])
+        assert res == 1
+        assert self.barriers == ['=']
+        res = self.interpret(f1, [x, x])
+        assert res == 0
+        assert self.barriers == ['=']
+
+    def test_pointer_compare_2(self):
+        X = lltype.GcStruct('X', ('foo', lltype.Signed))
+        def f1(x, y):
+            x.foo = 41
+            return x == y
+        x = lltype.malloc(X, immortal=True)
+        y = lltype.malloc(X, immortal=True)
+        res = self.interpret(f1, [x, y])
+        assert res == 0
+        assert self.barriers == ['P2W', '=']
+        res = self.interpret(f1, [x, x])
+        assert res == 1
+        assert self.barriers == ['P2W', '=']
+
+    def test_pointer_compare_4(self):
+        X = lltype.GcStruct('X', ('foo', lltype.Signed))
+        def f1(x, y):
+            x.foo = 40
+            y.foo = 41
+            return x != y
+        x = lltype.malloc(X, immortal=True)
+        y = lltype.malloc(X, immortal=True)
+        res = self.interpret(f1, [x, y])
+        assert res == 1
+        assert self.barriers == ['P2W', 'P2W']
+        res = self.interpret(f1, [x, x])
+        assert res == 0
+        assert self.barriers == ['P2W', 'P2W']

pypy/translator/stm/transform2.py

 def pre_insert_stm_barrier(stmtransformer, graph):
     graphinfo = stmtransformer.write_analyzer.compute_graph_info(graph)
 
+    def get_category(v):
+        if isinstance(v, Constant):
+            if v.value:
+                return 'G'
+            else:
+                return 'N'     # NULL
+        return category.get(v, 'P')
+
     for block in graph.iterblocks():
         if block.operations == ():
             continue
         #
         wants_a_barrier = {}
+        expand_comparison = set()
         for op in block.operations:
             if (op.opname in ('getfield', 'getarrayitem',
                               'getinteriorfield', 'gc_load') and
                   op.args[0].concretetype.TO._gckind == 'gc' and
                   not is_immutable(op)):
                 wants_a_barrier[op] = 'W'
+            elif (op.opname in ('ptr_eq', 'ptr_ne') and
+                  op.args[0].concretetype.TO._gckind == 'gc'):
+                expand_comparison.add(op)
         #
-        if wants_a_barrier:
+        if wants_a_barrier or expand_comparison:
             renamings = {}
             category = {}
             newoperations = []
                 if to is not None:
                     v = op.args[0]
                     v = renamings.get(v, v)
-                    if isinstance(v, Constant):
-                        frm = 'G'
-                    else:
-                        frm = category.get(v, 'P')
+                    frm = get_category(v)
                     if frm not in MORE_PRECISE_CATEGORIES[to]:
                         c_info = Constant('%s2%s' % (frm, to), lltype.Void)
                         w = varoftype(v.concretetype)
                         newoperations.append(newop)
                         renamings[op.args[0]] = w
                         category[w] = to
+                #
                 newop = SpaceOperation(op.opname,
                                        [renamings.get(v, v) for v in op.args],
                                        op.result)
                 newoperations.append(newop)
                 #
+                if op in expand_comparison:
+                    cats = ''.join([get_category(v) for v in newop.args])
+                    if ('N' not in cats and
+                            cats not in ('LL', 'LW', 'WL', 'WW')):
+                        if newop.opname == 'ptr_ne':
+                            v = varoftype(lltype.Bool)
+                            negop = SpaceOperation('bool_not', [v],
+                                                   newop.result)
+                            newoperations.append(negop)
+                            newop.result = v
+                        newop.opname = 'stm_ptr_eq'
+                #
                 effectinfo = stmtransformer.write_analyzer.analyze(
                     op, graphinfo=graphinfo)
                 if effectinfo: