[pypy-svn] r52577 - in pypy/branch/jit-hotpath/pypy/jit/rainbow: . test

arigo at codespeak.net arigo at codespeak.net
Sun Mar 16 12:00:26 CET 2008


Author: arigo
Date: Sun Mar 16 12:00:24 2008
New Revision: 52577

Modified:
   pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py
   pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py
   pypy/branch/jit-hotpath/pypy/jit/rainbow/interpreter.py
   pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hp_interpreter.py
Log:
Indirect calls.


Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py	Sun Mar 16 12:00:24 2008
@@ -578,6 +578,7 @@
         
     def register_redvar(self, arg, where=-1, verbose=True):
         assert arg not in self.redvar_positions
+        assert getattr(arg, 'concretetype', '?') is not lltype.Void
         if where == -1:
             where = self.free_red[self.current_block]
             self.free_red[self.current_block] += 1
@@ -591,6 +592,7 @@
 
     def register_greenvar(self, arg, where=None, check=True, verbose=True):
         assert isinstance(arg, flowmodel.Variable) or not check
+        assert getattr(arg, 'concretetype', '?') is not lltype.Void
         if where is None:
             where = self.free_green[self.current_block]
             self.free_green[self.current_block] += 1
@@ -825,11 +827,15 @@
         return handler(op, arg, result)
 
     def handle_concrete_hint(self, op, arg, result):
+        if arg.concretetype is lltype.Void:
+            return
         assert self.hannotator.binding(arg).is_green()
         assert self.hannotator.binding(result).is_green()
         self.register_greenvar(result, self.green_position(arg))
 
     def handle_variable_hint(self, op, arg, result):
+        if arg.concretetype is lltype.Void:
+            return
         assert not self.hannotator.binding(result).is_green()
         if self.hannotator.binding(arg).is_green():
             resultindex = self.convert_to_red(arg)
@@ -838,12 +844,16 @@
             self.register_redvar(result, self.redvar_position(arg))
 
     def handle_deepfreeze_hint(self, op, arg, result):
+        if arg.concretetype is lltype.Void:
+            return
         if self.varcolor(result) == "red":
             self.register_redvar(result, self.redvar_position(arg))
         else:
             self.register_greenvar(result, self.green_position(arg))
 
     def handle_promote_hint(self, op, arg, result):
+        if arg.concretetype is lltype.Void:
+            return
         if self.varcolor(arg) == "green":
             self.register_greenvar(result, self.green_position(arg))
             return
@@ -912,6 +922,37 @@
         has_result = (self.varcolor(op.result) != "gray" and
                       op.result.concretetype != lltype.Void)
 
+        if self.hannotator.policy.hotpath:
+            if not targets:
+                self.handle_residual_call(op, withexc)
+                return
+            if not has_result:
+                kind = "gray"
+            # for now, let's try to promote all indirect calls
+            self.emit("hp_promote")
+            self.emit(fnptrindex)
+            self.emit(self.promotiondesc_position(op.args[0].concretetype))
+            greenfnptrindex = self.register_greenvar(("promoted fnptr", op),
+                                                     check=False)
+            args = targets.values()[0].getargs()
+            emitted_args = self.args_of_call(op.args[1:-1], args)
+            self.emit("hp_%s_indirect_call" % (kind,))
+            self.emit(*emitted_args)
+            setdescindex = self.indirectcalldesc_position(targets)
+            self.emit(greenfnptrindex, setdescindex)
+            if has_result:
+                assert self.varcolor(op.result) == "red"
+                if kind != "red":
+                    assert kind == "yellow"
+                    tmpindex = self.register_greenvar(("tmpresult", op),
+                                                      check=False)
+                    self.emit("make_redbox")
+                    self.emit(tmpindex)
+                    self.emit(self.type_position(op.result.concretetype))
+                self.register_redvar(op.result)
+            return
+
+        # ---------- non-hotpath logic follows ----------
         emitted_args = []
         for v in op.args[1:-1]:
             if v.concretetype == lltype.Void:
@@ -1019,8 +1060,8 @@
         func = self.serialize_oparg("red", fnptr)
         emitted_args = []
         for v in op.args[1:]:
-            if v.concretetype == lltype.Void:
-                continue
+            if v.concretetype == lltype.Void:   # for indirect_call, this also
+                continue                        # skips the last argument
             emitted_args.append(self.serialize_oparg("red", v))
         if self.hannotator.policy.hotpath:
             self.emit("hp_residual_call")

Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py	Sun Mar 16 12:00:24 2008
@@ -85,10 +85,13 @@
             Xxx("capture_exception")
 
     def run_directly(self, greenargs, redargs, targetbytecode):
-        calldesc = targetbytecode.owncalldesc
+        return self.perform_call_mixed(greenargs, redargs,
+                                       targetbytecode.gv_ownfnptr,
+                                       targetbytecode.owncalldesc)
+
+    def perform_call_mixed(self, greenargs, redargs, gv_func, calldesc):
         try:
-            gv_res = calldesc.perform_call_mixed(self.rgenop,
-                                                 targetbytecode.gv_ownfnptr,
+            gv_res = calldesc.perform_call_mixed(self.rgenop, gv_func,
                                                  greenargs, redargs)
         except Exception, e:
             self.capture_exception(e)
@@ -304,11 +307,6 @@
         gv_res = calldesc.perform_call(self.rgenop, gv_fnptr, greenargs)
         self.green_result(gv_res)
 
-    @arguments("green_varargs", "red_varargs", "red", "indirectcalldesc")
-    def opimpl_indirect_call_const(self, greenargs, redargs,
-                                      gv_funcptr, callset):
-        Xxx("indirect_call_const")
-
     @arguments("oopspec", "bool", returns="red")
     def opimpl_red_oopspec_call_0(self, oopspec, deepfrozen):
         return self.oopspec_call(oopspec, [])
@@ -441,7 +439,10 @@
 
     @arguments("red", "green", "green", returns="green")
     def opimpl_is_constant(self, arg, true, false):
-        Xxx("is_constant")
+        # we could return either true or false here, but 'false' is probably
+        # better because there is no point in fallback-interpreting the clever
+        # logic that typically follows the 'true' case.
+        return false
 
     # hotpath-specific operations
 
@@ -479,6 +480,26 @@
         gv_res = self.run_directly(greenargs, redargs, targetbytecode)
         self.green_result(gv_res)
 
+    @arguments("green_varargs", "red_varargs", "green", "indirectcalldesc")
+    def opimpl_hp_red_indirect_call(self, greenargs, redargs, gv_funcptr,
+                                    callset):
+        gv_res = self.perform_call_mixed(greenargs, redargs, gv_funcptr,
+                                         callset.calldesc)
+        self.red_result(gv_res)
+
+    @arguments("green_varargs", "red_varargs", "green", "indirectcalldesc")
+    def opimpl_hp_gray_indirect_call(self, greenargs, redargs, gv_funcptr,
+                                     callset):
+        self.perform_call_mixed(greenargs, redargs, gv_funcptr,
+                                callset.calldesc)
+
+    @arguments("green_varargs", "red_varargs", "green", "indirectcalldesc")
+    def opimpl_hp_yellow_indirect_call(self, greenargs, redargs, gv_funcptr,
+                                       callset):
+        gv_res = self.perform_call_mixed(greenargs, redargs, gv_funcptr,
+                                         callset.calldesc)
+        self.green_result(gv_res)
+
     @arguments("red", "calldesc", "bool", "bool", "red_varargs")
     def opimpl_hp_residual_call(self, gv_func, calldesc, withexc, has_result,
                                 redargs_gv):

Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/interpreter.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/rainbow/interpreter.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/rainbow/interpreter.py	Sun Mar 16 12:00:24 2008
@@ -896,8 +896,7 @@
                                 promotebox, promotiondesc)
             assert False, "unreachable"
 
-    @arguments("green_varargs", "red_varargs", "bytecode")
-    def opimpl_hp_red_direct_call(self, greenargs, redargs, targetbytecode):
+    def hp_direct_call(self, greenargs, redargs, targetbytecode):
         frame = rtimeshift.VirtualFrame(self.frame, None)
         self.frame = self.jitstate.frame = frame
         frame.pc = 0
@@ -905,9 +904,23 @@
         frame.local_boxes = redargs
         frame.local_green = greenargs
 
+    @arguments("green_varargs", "red_varargs", "bytecode")
+    def opimpl_hp_red_direct_call(self, greenargs, redargs, targetbytecode):
+        self.hp_direct_call(greenargs, redargs, targetbytecode)
+
     opimpl_hp_gray_direct_call = opimpl_hp_red_direct_call
     opimpl_hp_yellow_direct_call = opimpl_hp_red_direct_call
 
+    @arguments("green_varargs", "red_varargs", "green", "indirectcalldesc")
+    def opimpl_hp_red_indirect_call(self, greenargs, redargs, gv_funcptr,
+                                    callset):
+        addr = gv_funcptr.revealconst(llmemory.Address)
+        bytecode = callset.bytecode_for_address(addr)
+        self.hp_direct_call(greenargs, redargs, bytecode)
+
+    opimpl_hp_gray_indirect_call = opimpl_hp_red_indirect_call
+    opimpl_hp_yellow_indirect_call = opimpl_hp_red_indirect_call
+
     @arguments("red", "calldesc", "bool", "bool", "red_varargs")
     def opimpl_hp_residual_call(self, funcbox, calldesc, withexc, has_result,
                                 redargs):

Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hp_interpreter.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hp_interpreter.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hp_interpreter.py	Sun Mar 16 12:00:24 2008
@@ -12,6 +12,7 @@
 #
 #    i = 1024
 #    while i > 0:
+#        i >>= 1
 #        ...real test code here...
 #        MyJitDriver.jit_merge_point(...)
 #        MyJitDriver.can_enter_jit(...)
@@ -879,10 +880,14 @@
         res = self.interpret(f, [4, 212], [])
         assert res == 212
 
-    def test_simple_meth(self):
+    def test_simple_yellow_meth(self):
+        class MyJitDriver(JitDriver):
+            greens = []
+            reds = ['flag', 'res', 'i']
+
         class Base(object):
             def m(self):
-                raise NotImplementedError
+                return 21
             pass  # for inspect.getsource() bugs
 
         class Concrete(Base):
@@ -891,43 +896,61 @@
             pass  # for inspect.getsource() bugs
 
         def f(flag):
-            if flag:
-                o = Base()
-            else:
-                o = Concrete()
-            return o.m()
-
-        res = self.interpret(f, [0], [0])
-        assert res == 42
-        self.check_insns({})
+            i = 1024
+            while i > 0:
+                i >>= 1
+                if flag:
+                    o = Base()
+                else:
+                    o = Concrete()
+                res = o.m()        # yellow call
+                MyJitDriver.jit_merge_point(flag=flag, res=res, i=i)
+                MyJitDriver.can_enter_jit(flag=flag, res=res, i=i)
+            return res
 
-        res = self.interpret(f, [0], [])
+        res = self.run(f, [0], threshold=2)
         assert res == 42
-        self.check_insns(indirect_call=0)
+        self.check_insns_in_loops({'int_is_true': 1,
+                                   'int_gt': 1, 'int_rshift': 1})
 
     def test_simple_red_meth(self):
+        class MyJitDriver(JitDriver):
+            greens = []
+            reds = ['flag', 'res', 'i']
+
         class Base(object):
-            def m(self, n):
-                raise NotImplementedError
+            def m(self, i):
+                return 21 + i
             pass  # for inspect.getsource() bugs
 
         class Concrete(Base):
-            def m(self, n):
-                return 21*n
+            def m(self, i):
+                return 42 - i
             pass  # for inspect.getsource() bugs
 
-        def f(flag, x):
-            if flag:
-                o = Base()
-            else:
-                o = Concrete()
-            return o.m(x)
+        def f(flag):
+            i = 1024
+            while i > 0:
+                i >>= 1
+                if flag:
+                    o = Base()
+                else:
+                    o = Concrete()
+                res = o.m(i)        # red call
+                MyJitDriver.jit_merge_point(flag=flag, res=res, i=i)
+                MyJitDriver.can_enter_jit(flag=flag, res=res, i=i)
+            return res
 
-        res = self.interpret(f, [0, 2], [0])
+        res = self.run(f, [0], threshold=2)
         assert res == 42
-        self.check_insns({'int_mul': 1})
+        self.check_insns_in_loops({'int_is_true': 1, 'int_sub': 1,
+                                   'int_gt': 1, 'int_rshift': 1})
 
     def test_simple_red_meth_vars_around(self):
+        class MyJitDriver(JitDriver):
+            greens = ['y']
+            reds = ['flag', 'x', 'z', 'res', 'i']
+
         class Base(object):
             def m(self, n):
                 raise NotImplementedError
@@ -939,27 +962,48 @@
             pass  # for inspect.getsource() bugs
 
         def f(flag, x, y, z):
-            if flag:
-                o = Base()
-            else:
-                o = Concrete()
-            return (o.m(x)+y)-z
+            i = 1024
+            while i > 0:
+                i >>= 1
+                if flag:
+                    o = Base()
+                else:
+                    o = Concrete()
+                hint(y, concrete=True)
+                res = (o.m(x)+y)-z
+                MyJitDriver.jit_merge_point(flag=flag, res=res, i=i,
+                                            x=x, y=y, z=z)
+                MyJitDriver.can_enter_jit(flag=flag, res=res, i=i,
+                                          x=x, y=y, z=z)
+            return res
 
-        res = self.interpret(f, [0, 2, 7, 5], [0])
+        res = self.run(f, [0, 2, 7, 5], threshold=2)
         assert res == 44
-        self.check_insns({'int_mul': 1, 'int_add': 1, 'int_sub': 1})
+        self.check_insns_in_loops({'int_is_true': 1,
+                                   'int_mul': 1, 'int_add': 1, 'int_sub': 1,
+                                   'int_gt': 1, 'int_rshift': 1})
 
     def test_green_red_mismatch_in_call(self):
+        class MyJitDriver(JitDriver):
+            greens = ['x', 'y']
+            reds = ['u', 'res', 'i']
+
         def add(a,b, u):
             return a+b
 
         def f(x, y, u):
-            r = add(x+1,y+1, u)
-            z = x+y
-            z = hint(z, concrete=True) + r   # this checks that 'r' is green
-            return hint(z, variable=True)
+            i = 1024
+            while i > 0:
+                i >>= 1
+                r = add(x+1,y+1, u)
+                z = x+y
+                z = hint(z, concrete=True) + r  # this checks that 'r' is green
+                res = hint(z, variable=True)
+                MyJitDriver.jit_merge_point(x=x, y=y, u=u, res=res, i=i)
+                MyJitDriver.can_enter_jit(x=x, y=y, u=u, res=res, i=i)
+            return res
 
-        res = self.interpret(f, [4, 5, 0], [])
+        res = self.run(f, [4, 5, 0], threshold=2)
         assert res == 20
 
 
@@ -976,6 +1020,10 @@
         assert res == 120
         
     def test_simple_indirect_call(self):
+        class MyJitDriver(JitDriver):
+            greens = ['flag']
+            reds = ['v', 'res', 'i']
+
         def g1(v):
             return v * 2
 
@@ -983,17 +1031,28 @@
             return v + 2
 
         def f(flag, v):
-            if hint(flag, concrete=True):
-                g = g1
-            else:
-                g = g2
-            return g(v)
+            i = 1024
+            while i > 0:
+                i >>= 1
+                if hint(flag, concrete=True):
+                    g = g1
+                else:
+                    g = g2
+                res = g(v)
+                MyJitDriver.jit_merge_point(flag=flag, v=v, res=res, i=i)
+                MyJitDriver.can_enter_jit(flag=flag, v=v, res=res, i=i)
+            return res
 
-        res = self.interpret(f, [0, 40], [0])
+        res = self.run(f, [0, 40], threshold=2)
         assert res == 42
-        self.check_insns({'int_add': 1})
+        self.check_insns_in_loops({'int_add': 1,
+                                   'int_gt': 1, 'int_rshift': 1})
 
     def test_normalize_indirect_call(self):
+        class MyJitDriver(JitDriver):
+            greens = ['flag']
+            reds = ['v', 'res', 'i']
+
         def g1(v):
             return -17
 
@@ -1001,21 +1060,32 @@
             return v + 2
 
         def f(flag, v):
-            if hint(flag, concrete=True):
-                g = g1
-            else:
-                g = g2
-            return g(v)
+            i = 1024
+            while i > 0:
+                i >>= 1
+                if hint(flag, concrete=True):
+                    g = g1
+                else:
+                    g = g2
+                res = g(v)
+                MyJitDriver.jit_merge_point(flag=flag, v=v, res=res, i=i)
+                MyJitDriver.can_enter_jit(flag=flag, v=v, res=res, i=i)
+            return res
 
-        res = self.interpret(f, [0, 40], [0])
+        res = self.run(f, [0, 40], threshold=2)
         assert res == 42
-        self.check_insns({'int_add': 1})
+        self.check_insns_in_loops({'int_add': 1,
+                                   'int_gt': 1, 'int_rshift': 1})
 
-        res = self.interpret(f, [1, 40], [0])
+        res = self.run(f, [1, 40], threshold=2)
         assert res == -17
-        self.check_insns({})
+        self.check_insns_in_loops({'int_gt': 1, 'int_rshift': 1})
 
     def test_normalize_indirect_call_more(self):
+        class MyJitDriver(JitDriver):
+            greens = ['flag']
+            reds = ['v', 'res', 'i']
+
         def g1(v):
             if v >= 0:
                 return -17
@@ -1026,28 +1096,38 @@
             return v + 2
 
         def f(flag, v):
-            w = g1(v)
-            if hint(flag, concrete=True):
-                g = g1
-            else:
-                g = g2
-            return g(v) + w
+            i = 1024
+            while i > 0:
+                i >>= 1
+                w = g1(v)
+                if hint(flag, concrete=True):
+                    g = g1
+                else:
+                    g = g2
+                res = g(v) + w
+                MyJitDriver.jit_merge_point(flag=flag, v=v, res=res, i=i)
+                MyJitDriver.can_enter_jit(flag=flag, v=v, res=res, i=i)
+            return res
 
-        res = self.interpret(f, [0, 40], [0])
+        res = self.run(f, [0, 40], threshold=2)
         assert res == 25
-        self.check_insns({'int_add': 2, 'int_ge': 1})
+        self.check_insns_in_loops({'int_add': 2, 'int_ge': 1,
+                                   'int_gt': 1, 'int_rshift': 1})
 
-        res = self.interpret(f, [1, 40], [0])
+        res = self.run(f, [1, 40], threshold=2)
         assert res == -34
-        self.check_insns({'int_ge': 2, 'int_add': 1})
+        self.check_insns_in_loops({'int_ge': 2,
+                                   'int_gt': 1, 'int_rshift': 1})
 
-        res = self.interpret(f, [0, -1000], [0])
+        res = self.run(f, [0, -1000], threshold=2)
         assert res == f(False, -1000)
-        self.check_insns({'int_add': 2, 'int_ge': 1})
+        self.check_insns_in_loops({'int_add': 2, 'int_ge': 1,
+                                   'int_gt': 1, 'int_rshift': 1})
 
-        res = self.interpret(f, [1, -1000], [0])
+        res = self.run(f, [1, -1000], threshold=2)
         assert res == f(True, -1000)
-        self.check_insns({'int_ge': 2, 'int_add': 1})
+        self.check_insns_in_loops({'int_ge': 2,
+                                   'int_gt': 1, 'int_rshift': 1})
 
     def test_green_char_at_merge(self):
         def f(c, x):



More information about the Pypy-commit mailing list