Author: Maciej Fijalkowski <[email protected]>
Branch: result-in-resops
Changeset: r57559:a68b82aa7b91
Date: 2012-09-25 11:40 +0200
http://bitbucket.org/pypy/pypy/changeset/a68b82aa7b91/

Log:    Carefully read values of boxes. Note that for call_pure this is
        safe, because we're checking the equality of actually encountered
        boxes with proven constants

diff --git a/pypy/jit/metainterp/optimizeopt/pure.py 
b/pypy/jit/metainterp/optimizeopt/pure.py
--- a/pypy/jit/metainterp/optimizeopt/pure.py
+++ b/pypy/jit/metainterp/optimizeopt/pure.py
@@ -1,12 +1,12 @@
 from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, REMOVED
-from pypy.jit.metainterp.resoperation import rop, create_resop_2, create_resop
+from pypy.jit.metainterp.resoperation import rop, create_resop_2
 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method,\
-     ArgsDict
+     ArgsSet
 
 class OptPure(Optimization):
     def __init__(self):
         self.posponedop = None
-        self.pure_operations = ArgsDict()
+        self.pure_operations = ArgsSet()
         self.emitted_pure_operations = []
 
     def propagate_forward(self, op):
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py 
b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -447,24 +447,15 @@
         return False
 
     def optimize_CALL_PURE_i(self, op):
-        arg_consts = []
         for i in range(op.numargs()):
             arg = op.getarg(i)
             const = self.get_constant_box(arg)
-            if const is None:
+            if const is None or not const.eq_value(arg):
                 break
-            arg_consts.append(const)
         else:
-            # all constant arguments: check if we already know the result
-            try:
-                result = self.optimizer.call_pure_results[arg_consts]
-            except KeyError:
-                pass
-            else:
-                # this removes a CALL_PURE with all constant arguments.
-                self.make_constant(op, result)
-                self.last_emitted_operation = REMOVED
-                return
+            self.make_constant(op, op.constbox())
+            self.last_emitted_operation = REMOVED
+            return
         self.emit_operation(op)
     optimize_CALL_PURE_f = optimize_CALL_PURE_i
     optimize_CALL_PURE_p = optimize_CALL_PURE_i
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py 
b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -114,15 +114,15 @@
 
     enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap"
 
-    def optimize_loop(self, ops, optops, call_pure_results=None):
-        loop = self.parse(ops)
+    def optimize_loop(self, ops, optops, results=None):
+        loop = self.parse(ops, results=results)
         token = JitCellToken()
         loop.operations = [create_resop(rop.LABEL, None, loop.inputargs, 
descr=TargetToken(token))] + \
                           loop.operations
         if loop.operations[-1].getopnum() == rop.JUMP:
             loop.operations[-1]._descr = token
         expected = convert_old_style_to_targets(self.parse(optops), jump=True)
-        self._do_optimize_loop(loop, call_pure_results)
+        self._do_optimize_loop(loop)
         print '\n'.join([str(o) for o in loop.operations])
         self.assert_equal(loop, expected)
 
@@ -717,12 +717,10 @@
         self.optimize_loop(ops, expected)
 
     def test_remove_guard_no_exception_with_call_pure_on_constant_args(self):
-        arg_consts = [ConstInt(i) for i in (123456, 81)]
-        call_pure_results = {tuple(arg_consts): ConstInt(5)}
         ops = """
         [i1]
-        i3 = same_as(81)
-        i2 = call_pure(123456, i3, descr=nonwritedescr)
+        i3 = same_as_i(81)
+        i2 = call_pure_i(123456, i3, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
         jump(i2)
         """
@@ -730,7 +728,7 @@
         [i1]
         jump(5)
         """
-        self.optimize_loop(ops, expected, call_pure_results)
+        self.optimize_loop(ops, expected, results=[81, 5, None, None])
 
     def test_remove_guard_no_exception_with_duplicated_call_pure(self):
         ops = """
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py 
b/pypy/jit/metainterp/optimizeopt/test/test_util.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_util.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py
@@ -8,7 +8,7 @@
 from pypy.jit.metainterp.history import (TreeLoop, AbstractDescr,
                                          JitCellToken, TargetToken)
 from pypy.jit.metainterp.optimizeopt.util import sort_descrs, equaloplists,\
-     ArgsDict
+     ArgsDict, ArgsSet
 from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.codewriter.heaptracker import register_known_gctype
 from pypy.jit.tool.oparser import parse, pure_parse
@@ -17,7 +17,7 @@
 from pypy.jit.metainterp.jitprof import EmptyProfiler
 from pypy.config.pypyoption import get_pypy_config
 from pypy.jit.metainterp.resoperation import rop, create_resop, BoxPtr,\
-     create_resop_0, REF, INT, FLOAT
+     create_resop_0, REF, INT, FLOAT, create_resop_2, BoxInt
 
 def test_sort_descrs():
     class PseudoDescr(AbstractDescr):
@@ -71,12 +71,31 @@
                    "equaloplists(loop1.operations, loop3.operations)")
 
 
-def test_argsdict():
-    d = ArgsDict()
+def test_argsset():
+    d = ArgsSet()
     op = create_resop_0(rop.FORCE_TOKEN, 13)
     assert d.get(op) is None
     d.add(op)
     assert d.get(op) is op
+    d2 = d.copy()
+    op2 = create_resop_2(rop.INT_ADD, 15, BoxInt(0), BoxInt(1))
+    d2.add(op2)
+    assert d2.get(op) is op
+    assert d2.get(op2) is op2
+    assert d.get(op2) is None
+
+def test_argdict():
+    d = ArgsDict()
+    op = create_resop_0(rop.FORCE_TOKEN, 13)
+    assert d.get(op) is None
+    d.set(op, 3)
+    assert d.get(op) == 3
+    d2 = d.copy()
+    op2 = create_resop_2(rop.INT_ADD, 15, BoxInt(0), BoxInt(1))
+    d2.set(op2, 5)
+    assert d2.get(op2) == 5
+    assert d2.get(op) == 3
+    assert d.get(op2) is None
 
 # ____________________________________________________________
 
@@ -378,10 +397,11 @@
 
 class BaseTest(object):
 
-    def parse(self, s, boxkinds=None):
+    def parse(self, s, boxkinds=None, results=None):
         return parse(s, self.cpu, self.namespace,
                      type_system=self.type_system,
-                     boxkinds=boxkinds)
+                     boxkinds=boxkinds,
+                     results=results)
 
     def invent_fail_descr(self, model, fail_args):
         xxx
@@ -402,12 +422,10 @@
         assert equaloplists(optimized.operations,
                             expected.operations, False, remap, text_right)
 
-    def _do_optimize_loop(self, loop, call_pure_results):
+    def _do_optimize_loop(self, loop):
         from pypy.jit.metainterp.optimizeopt import optimize_trace
 
         self.loop = loop
-        if call_pure_results is not None:
-            loop.call_pure_results = call_pure_results.copy()
         metainterp_sd = FakeMetaInterpStaticData(self.cpu)
         if hasattr(self, 'vrefinfo'):
             metainterp_sd.virtualref_info = self.vrefinfo
@@ -421,7 +439,7 @@
                 op._rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args))
         optimize_trace(metainterp_sd, loop, self.enable_opts)
 
-    def unroll_and_optimize(self, loop, call_pure_results=None):
+    def unroll_and_optimize(self, loop):
         operations =  loop.operations
         jumpop = operations[-1]
         assert jumpop.getopnum() == rop.JUMP
@@ -440,7 +458,7 @@
                                             operations +  \
                               [create_resop(rop.LABEL, None, jump_args,
                                             descr=token)]
-        self._do_optimize_loop(preamble, call_pure_results)
+        self._do_optimize_loop(preamble)
 
         assert preamble.operations[-1].getopnum() == rop.LABEL
 
@@ -454,7 +472,7 @@
         assert loop.operations[0].getopnum() == rop.LABEL
         loop.inputargs = loop.operations[0].getarglist()
 
-        self._do_optimize_loop(loop, call_pure_results)
+        self._do_optimize_loop(loop)
         extra_same_as = []
         while loop.operations[0].getopnum() != rop.LABEL:
             extra_same_as.append(loop.operations[0])
diff --git a/pypy/jit/metainterp/optimizeopt/util.py 
b/pypy/jit/metainterp/optimizeopt/util.py
--- a/pypy/jit/metainterp/optimizeopt/util.py
+++ b/pypy/jit/metainterp/optimizeopt/util.py
@@ -87,35 +87,50 @@
 
 BUCKET_SIZE = 1024
 
-class ArgsDict(object):
-    """ An imprecise dict. If you look it up and it's there, it's correct,
-    however we don't care about collisions, so a colliding element can
-    kick someone else out
-    """
-    def __init__(self, bucket_size=BUCKET_SIZE):
-        self.buckets = [None] * bucket_size
-        self.bucket_size = bucket_size - 1
+def new_args_set(has_value=False):
+    class ArgsSet(object):
+        """ An imprecise dict. If you look it up and it's there, it's correct,
+        however we don't care about collisions, so a colliding element can
+        kick someone else out
+        """
+        def __init__(self, bucket_size=BUCKET_SIZE):
+            self.buckets = [None] * bucket_size
+            if has_value:
+                self.values = [None] * bucket_size
+            self.bucket_size = bucket_size - 1
 
-    def get(self, op):
-        hash = op._get_hash_() & self.bucket_size
-        candidate = self.buckets[hash]
-        if candidate is None:
+        def get(self, op):
+            hash = op._get_hash_() & self.bucket_size
+            candidate = self.buckets[hash]
+            if candidate is None:
+                return None
+            if candidate.__class__ != op.__class__:
+                return None # collision
+            if op.eq(candidate):
+                if has_value:
+                    return self.values[hash]
+                return candidate
             return None
-        if candidate.__class__ != op.__class__:
-            return None # collision
-        if op.eq(candidate):
-            return candidate
-        return None
 
-    def add(self, op):
-        hash = op._get_hash_() & self.bucket_size
-        self.buckets[hash] = op # don't care about collisions
+        if has_value:
+            def set(self, op, v):
+                hash = op._get_hash_() & self.bucket_size
+                self.buckets[hash] = op # don't care about collisions
+                self.values[hash] = v
+        else:
+            def add(self, op):
+                hash = op._get_hash_() & self.bucket_size
+                self.buckets[hash] = op # don't care about collisions
 
-    def copy(self):
-        a = ArgsDict()
-        a.buckets = self.buckets[:]
-        return a
-
+        def copy(self):
+            a = ArgsSet()
+            a.buckets = self.buckets[:]
+            if has_value:
+                a.values = self.values[:]
+            return a
+    return ArgsSet
+ArgsSet = new_args_set()
+ArgsDict = new_args_set(True)
 
 # ____________________________________________________________
 
diff --git a/pypy/jit/metainterp/resoperation.py 
b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -461,6 +461,9 @@
     def getint(self):
         return self.value
 
+    def eq_value(self, other):
+        return self.value == other.getint() # crash if incompatible type
+
     def getaddr(self):
         return heaptracker.int2adr(self.value)
 
@@ -499,6 +502,10 @@
     def getfloatstorage(self):
         return self.value
 
+    def eq_value(self, other):
+        return self.value == other.getfloatstorage()
+    # crash if incompatible type
+
     def _get_hash_(self):
         return longlong.gethash(self.value)
 
@@ -537,6 +544,10 @@
         return lltype.cast_opaque_ptr(PTR, self.getref_base())
     getref._annspecialcase_ = 'specialize:arg(1)'
 
+    def eq_value(self, other):
+        return self.value == other.getref_base()
+    # crash if incompatible type
+
     def _get_hash_(self):
         if self.value:
             return lltype.identityhash(self.value)
@@ -826,6 +837,9 @@
     def wrap_constant(intval):
         return ConstInt(intval)
 
+    def constbox(self):
+        return ConstInt(self.intval)
+
     def get_result_hash(self):
         return make_hashable_int(self.intval)
 
@@ -853,6 +867,9 @@
     def wrap_constant(floatval):
         return ConstFloat(floatval)
 
+    def constbox(self):
+        return ConstFloat(self.floatval)
+
     def get_result_hash(self):
         return longlong.gethash(self.floatval)
 
@@ -886,6 +903,9 @@
     def wrap_constant(pval):
         return ConstPtr(pval)
 
+    def constbox(self):
+        return ConstPtr(self.pval)
+
     def result_eq(self, other):
         assert isinstance(other, self.__class__)
         return self.pval == other.pval
@@ -990,7 +1010,9 @@
         pass        
 
     @specialize.arg(1)
-    def copy_and_change(self, newopnum, descr=None):
+    def copy_and_change(self, newopnum=-1, descr=None):
+        if newopnum == -1:
+            newopnum = self.getopnum()
         res = create_resop_0(newopnum, self.getresult(),
                              descr or self.getdescr())
         if self.is_guard():
@@ -1042,7 +1064,9 @@
         return res
 
     @specialize.arg(1)
-    def copy_and_change(self, newopnum, arg0=None, descr=None):
+    def copy_and_change(self, newopnum=-1, arg0=None, descr=None):
+        if newopnum == -1:
+            newopnum = self.getopnum()
         res = create_resop_1(newopnum, self.getresult(), arg0 or self._arg0,
                              descr or self.getdescr())
         if self.is_guard():
@@ -1099,7 +1123,9 @@
         return res
 
     @specialize.arg(1)
-    def copy_and_change(self, newopnum, arg0=None, arg1=None, descr=None):
+    def copy_and_change(self, newopnum=-1, arg0=None, arg1=None, descr=None):
+        if newopnum == -1:
+            newopnum = self.getopnum()
         res = create_resop_2(newopnum, self.getresult(), arg0 or self._arg0,
                              arg1 or self._arg1,
                              descr or self.getdescr())
@@ -1161,8 +1187,10 @@
                               self.getdescr())
 
     @specialize.arg(1)
-    def copy_and_change(self, newopnum, arg0=None, arg1=None, arg2=None,
+    def copy_and_change(self, newopnum=-1, arg0=None, arg1=None, arg2=None,
                         descr=None):
+        if newopnum == -1:
+            newopnum = self.getopnum()
         r = create_resop_3(newopnum, self.getresult(), arg0 or self._arg0,
                            arg1 or self._arg1, arg2 or self._arg2,
                            descr or self.getdescr())
@@ -1219,7 +1247,9 @@
                             newargs, self.getdescr())
 
     @specialize.arg(1)
-    def copy_and_change(self, newopnum, newargs=None, descr=None):
+    def copy_and_change(self, newopnum=-1, newargs=None, descr=None):
+        if newopnum == -1:
+            newopnum = self.getopnum()
         r = create_resop(newopnum, self.getresult(),
                          newargs or self.getarglist(),
                          descr or self.getdescr())
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to