[pypy-svn] r37006 - in pypy/dist/pypy/jit: codegen/llgraph timeshifter timeshifter/test

pedronis at codespeak.net pedronis at codespeak.net
Fri Jan 19 16:38:35 CET 2007


Author: pedronis
Date: Fri Jan 19 16:38:09 2007
New Revision: 37006

Modified:
   pypy/dist/pypy/jit/codegen/llgraph/llimpl.py
   pypy/dist/pypy/jit/timeshifter/hrtyper.py
   pypy/dist/pypy/jit/timeshifter/rcontainer.py
   pypy/dist/pypy/jit/timeshifter/rtimeshift.py
   pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py
   pypy/dist/pypy/jit/timeshifter/test/test_virtualizable.py
   pypy/dist/pypy/jit/timeshifter/transform.py
Log:
(arre, pedronis) progress on virtualizable:  first test with outside-the-jit code forcing a virtual struct and checking that returning in the jit code
takes that into account generating code that matches the forced state of the structure.

quite a bit of xxx for now and cleanups needed.

We need to start thinking about the problems from the PyPy and rtyping side of things, to know which issues need a solution and which can wait longer.



Modified: pypy/dist/pypy/jit/codegen/llgraph/llimpl.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llgraph/llimpl.py	(original)
+++ pypy/dist/pypy/jit/codegen/llgraph/llimpl.py	Fri Jan 19 16:38:09 2007
@@ -123,11 +123,16 @@
     TYPE = from_opaque_object(gv_TYPE).value
     v = from_opaque_object(gv_var)
     if TYPE != v.concretetype:
-        assert v.concretetype == lltype.erasedType(TYPE)
+        if TYPE is llmemory.GCREF or v.concretetype is llmemory.GCREF:
+            lltype.cast_opaque_ptr(TYPE, v.concretetype._defl()) # sanity check
+            opname = 'cast_opaque_ptr'
+        else:
+            assert v.concretetype == lltype.erasedType(TYPE)
+            opname = 'cast_pointer'
         block = from_opaque_object(block)
         v2 = flowmodel.Variable()
         v2.concretetype = TYPE
-        op = flowmodel.SpaceOperation('cast_pointer', [v], v2)
+        op = flowmodel.SpaceOperation(opname, [v], v2)
         block.operations.append(op)
         v = v2
     return to_opaque_object(v)

Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/hrtyper.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/hrtyper.py	Fri Jan 19 16:38:09 2007
@@ -156,15 +156,17 @@
         self.v_queue = varoftype(self.r_Queue.lowleveltype, 'queue')
         #self.void_red_repr = VoidRedRepr(self)
 
+        # XXX use helpers, factor out perhaps?
         annhelper = self.annhelper
-        def make_vinfo():
-            vinfo = rcontainer.VirtualInfo(RGenOp)
+        def make_vinfo(bitmask):
+            vinfo = rcontainer.VirtualInfo(RGenOp, bitmask)
             return cast_instance_to_base_ptr(vinfo)
 
         s_vableinfoptr = annmodel.lltype_to_annotation(rcontainer.VABLEINFOPTR)
-        s_info = annmodel.lltype_to_annotation(llmemory.GCREF)
+        s_gcref = annmodel.lltype_to_annotation(llmemory.GCREF)
+        s_info = s_gcref
         
-        make_vinfo_ptr = annhelper.delayedfunction(make_vinfo, [],
+        make_vinfo_ptr = annhelper.delayedfunction(make_vinfo, [annmodel.SomeInteger()],
                                                    s_vableinfoptr,
                                                    needtype=True)
         self.gv_make_vinfo_ptr = RGenOp.constPrebuiltGlobal(make_vinfo_ptr)
@@ -215,9 +217,51 @@
             vinfo_skip_vinfo_ptr)
         self.vinfo_skip_vinfo_token = RGenOp.sigToken(
                                      lltype.typeOf(vinfo_skip_vinfo_ptr).TO)
-        
+
+        def vinfo_get_shape(vinfo):
+            vinfo = cast_base_ptr_to_instance(rcontainer.VirtualInfo,
+                                              vinfo)
+            return vinfo.get_shape()
+        vinfo_get_shape_ptr = annhelper.delayedfunction(vinfo_get_shape,
+                                                        [s_vableinfoptr],
+                                                        annmodel.SomeInteger(),
+                                                        needtype=True)
+        self.gv_vinfo_get_shape_ptr = RGenOp.constPrebuiltGlobal(
+            vinfo_get_shape_ptr)
+        self.vinfo_get_shape_token = RGenOp.sigToken(
+                                     lltype.typeOf(vinfo_get_shape_ptr).TO)
 
 
+        def vinfo_get_vinfo(vinfo, index):
+            vinfo = cast_base_ptr_to_instance(rcontainer.VirtualInfo,
+                                              vinfo)
+            childvinfo = vinfo.vinfos[index]
+            return cast_instance_to_base_ptr(childvinfo)            
+
+        vinfo_get_vinfo_ptr = annhelper.delayedfunction(vinfo_get_vinfo,
+                              [s_vableinfoptr, annmodel.SomeInteger()],
+                              s_vableinfoptr,
+                              needtype=True)
+        self.gv_vinfo_get_vinfo_ptr = RGenOp.constPrebuiltGlobal(
+            vinfo_get_vinfo_ptr)
+        self.vinfo_get_vinfo_token = RGenOp.sigToken(
+                                     lltype.typeOf(vinfo_get_vinfo_ptr).TO)
+
+        def vinfo_read_forced(vinfo):
+            vinfo = cast_base_ptr_to_instance(rcontainer.VirtualInfo,
+                                              vinfo)
+            return vinfo.read_forced()
+
+        vinfo_read_forced_ptr = annhelper.delayedfunction(vinfo_read_forced,
+                              [s_vableinfoptr],
+                              s_gcref,
+                              needtype=True)
+        self.gv_vinfo_read_forced_ptr = RGenOp.constPrebuiltGlobal(
+            vinfo_read_forced_ptr)
+        self.vinfo_read_forced_token = RGenOp.sigToken(
+                                     lltype.typeOf(vinfo_read_forced_ptr).TO)
+        
+         
     def specialize(self, origportalgraph=None, view=False):
         """
         Driver for running the timeshifter.
@@ -1397,6 +1441,28 @@
     def translate_op_residual_gray_call(self, hop):
         self.translate_op_residual_red_call(hop, color='gray')
 
+    def translate_op_prepare_residual_call(self, hop):
+        v_jitstate = hop.llops.getjitstate()        
+        return hop.llops.genmixlevelhelpercall(rtimeshift.prepare_residual_call,
+                                               [self.s_JITState],
+                                               [v_jitstate],
+                                               annmodel.s_None)
+
+    def translate_op_after_residual_call(self, hop):
+        v_jitstate = hop.llops.getjitstate()        
+        return hop.llops.genmixlevelhelpercall(rtimeshift.after_residual_call,
+                                               [self.s_JITState],
+                                               [v_jitstate],
+                                               self.s_RedBox)
+        
+    def translate_op_reshape(self, hop):
+        v_jitstate = hop.llops.getjitstate()                
+        v_shape, = hop.inputargs(self.getredrepr(lltype.Signed))
+        return hop.llops.genmixlevelhelpercall(rtimeshift.reshape,
+                                               [self.s_JITState, self.s_RedBox],
+                                               [v_jitstate     , v_shape      ],
+                                               annmodel.s_None)        
+
     def translate_op_reverse_split_queue(self, hop):
         hop.llops.genmixlevelhelpercall(rtimeshift.reverse_split_queue,
                                         [self.s_Queue],

Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rcontainer.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rcontainer.py	Fri Jan 19 16:38:09 2007
@@ -156,6 +156,7 @@
 
             self.materialize = materialize
 
+        # xxx
         self.gv_make_vinfo_ptr = hrtyper.gv_make_vinfo_ptr
         self.make_vinfo_token = hrtyper.make_vinfo_token
 
@@ -165,6 +166,15 @@
         self.vinfo_append_vinfo_token = hrtyper.vinfo_append_vinfo_token
         self.gv_vinfo_skip_vinfo_ptr = hrtyper.gv_vinfo_skip_vinfo_ptr
         self.vinfo_skip_vinfo_token = hrtyper.vinfo_skip_vinfo_token
+
+        self.gv_vinfo_get_vinfo_ptr = hrtyper.gv_vinfo_get_vinfo_ptr
+        self.vinfo_get_vinfo_token = hrtyper.vinfo_get_vinfo_token
+
+        self.gv_vinfo_get_shape_ptr = hrtyper.gv_vinfo_get_shape_ptr
+        self.vinfo_get_shape_token = hrtyper.vinfo_get_shape_token
+
+        self.gv_vinfo_read_forced_ptr = hrtyper.gv_vinfo_read_forced_ptr
+        self.vinfo_read_forced_token = hrtyper.vinfo_read_forced_token
         
     def getfielddesc(self, name):
         return self.fielddesc_by_name[name]
@@ -434,9 +444,11 @@
         typedesc = self.typedesc
         assert typedesc is not None
         builder = jitstate.curbuilder
+        gv_bitmask = builder.rgenop.genconst(1<<memo.bitcount)
+        memo.bitcount += 1
         gv_vinfo = builder.genop_call(typedesc.make_vinfo_token,
                            typedesc.gv_make_vinfo_ptr,
-                           [])
+                           [gv_bitmask])
         memo.containers[self] = gv_vinfo
         vars_gv = []
         for box in self.content_boxes:
@@ -463,12 +475,45 @@
                            [gv_vinfo, gv_info])
         return gv_vinfo
 
+
+    def reshape(self, jitstate, gv_vinfo, shapemask, memo):
+        if self in memo.containers:
+            return
+        typedesc = self.typedesc
+        assert typedesc is not None
+        builder = jitstate.curbuilder        
+        memo.containers[self] = None
+        bitmask = 1<<memo.bitcount
+        memo.bitcount += 1
+        boxes = self.content_boxes
+        if bitmask&shapemask:
+            gv_ptr = builder.genop_call(typedesc.vinfo_read_forced_token,
+                                        typedesc.gv_vinfo_read_forced_ptr,
+                                        [gv_vinfo])
+            self.content_boxes = None
+            self.ownbox.genvar = gv_ptr
+            self.ownbox.content = None
+
+        for i in range(len(boxes)): # xxx duplication
+            box = boxes[i]
+            if not box.genvar:
+                gv_vinfo1 = builder.genop_call(typedesc.vinfo_get_vinfo_token,
+                                               typedesc.gv_vinfo_get_vinfo_ptr,
+                                               [gv_vinfo, builder.rgenop.genconst(i)])
+                assert isinstance(box, rvalue.PtrRedBox)
+                content = box.content
+                assert isinstance(content, VirtualStruct) # xxx for now
+                content.reshape(jitstate, gv_vinfo1, shapemask, memo)        
+        
+
+
 class VirtualInfo(object):
 
-    def __init__(self, RGenOp):
+    def __init__(self, RGenOp, bitmask):
         self.RGenOp = RGenOp
         self.vinfos = []
         self.s = lltype.nullptr(llmemory.GCREF.TO)
+        self.bitmask = bitmask
         
     def read_field(self, fielddesc, base, index):
         T = fielddesc.RESTYPE
@@ -491,7 +536,16 @@
         fielddesc.fill_into(s, base, self)
         return s
     get_forced._annspecialcase_ = "specialize:arg(1)"
-        
+
+    def read_forced(self):
+        assert self.s
+        return self.s
+    
+    def get_shape(self):
+        if self.s:
+            return self.bitmask
+        else:
+            return 0
 
 class VirtualizableStruct(VirtualStruct):
 
@@ -543,9 +597,10 @@
             boxes = self.content_boxes
             vars_gv = []
             n = len(boxes)
+            gv_zeromask = builder.rgenop.genconst(0)
             gv_vinfo = builder.genop_call(typedesc.make_vinfo_token,
                                typedesc.gv_make_vinfo_ptr,
-                               [])
+                               [gv_zeromask])
             memo.containers[self] = gv_vinfo
             
             for i in range(NVABLEFIELDS, n-1):
@@ -589,12 +644,38 @@
             info_token = typedesc.info_desc.fieldtoken
             access_token = typedesc.access_desc.fieldtoken
             gv_base_null = typedesc.base_desc.gv_default
-            gv_info_null = typedesc.info_desc.gv_default
             gv_access_null = typedesc.access_desc.gv_default
             builder.genop_setfield(base_token, gv_outside, gv_base_null)
-            builder.genop_setfield(info_token, gv_outside, gv_info_null)
             builder.genop_setfield(access_token, gv_outside, gv_access_null)
-                                   
+
+    def reshape(self, jitstate, gv_vinfo, shapemask, memo):
+        typedesc = self.typedesc
+        builder = jitstate.curbuilder
+        gv_outside = self.content_boxes[-1].genvar
+        if gv_outside is not typedesc.gv_null:
+            info_desc = typedesc.info_desc
+            assert info_desc is not None
+            if self in memo.containers:
+                return
+            # xxx we can avoid traversing the full tree
+            memo.containers[self] = None
+
+            assert gv_vinfo is None # xxx
+            info_token = info_desc.fieldtoken
+            gv_vinfo = builder.genop_getfield(info_token, gv_outside)            
+            boxes = self.content_boxes
+            n = len(boxes)
+            for i in range(NVABLEFIELDS, n-1):
+                box = boxes[i]
+                if not box.genvar:
+                    gv_vinfo1 = builder.genop_call(typedesc.vinfo_get_vinfo_token,
+                                                   typedesc.gv_vinfo_get_vinfo_ptr,
+                                                   [gv_vinfo, builder.rgenop.genconst(i-NVABLEFIELDS)])
+                    assert isinstance(box, rvalue.PtrRedBox)
+                    content = box.content
+                    assert isinstance(content, VirtualStruct) # xxx for now
+                    content.reshape(jitstate, gv_vinfo1, shapemask, memo)
+                    
 # ____________________________________________________________
 
 class FrozenPartialDataStruct(AbstractContainer):

Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py	Fri Jan 19 16:38:09 2007
@@ -463,14 +463,22 @@
 
 def ll_gen_residual_call(jitstate, calldesc, funcbox):
     builder = jitstate.curbuilder
-    jitstate.prepare_for_residual_call()
     gv_funcbox = funcbox.getgenvar(jitstate)
     argboxes = jitstate.frame.local_boxes
     args_gv = [argbox.getgenvar(jitstate) for argbox in argboxes]
     gv_result = builder.genop_call(calldesc.sigtoken, gv_funcbox, args_gv)
-    jitstate.after_residual_call()
     return calldesc.redboxbuilder(calldesc.result_kind, gv_result)
 
+def prepare_residual_call(jitstate):
+    jitstate.prepare_for_residual_call()
+
+def after_residual_call(jitstate):
+    return jitstate.after_residual_call()
+
+def reshape(jitstate, shapebox):
+    shapemask = rvalue.ll_getvalue(shapebox, lltype.Signed)
+    jitstate.reshape(shapemask)
+
 
 class ResumingInfo(object):
     def __init__(self, promotion_point, gv_value, path):
@@ -895,20 +903,47 @@
             builder = self.curbuilder            
             gv_base = builder.get_frame_base()
             memo = rvalue.make_vinfo_memo()
+            memo.bitcount = 0
             for virtualizable_box in virtualizables:
                 content = virtualizable_box.content
                 assert isinstance(content, rcontainer.VirtualizableStruct)
                 content.prepare_for_residual_call(self, gv_base, memo)
+            assert memo.bitcount < 32
+            self.make_vinfo_memo = memo
                 
     def after_residual_call(self):
         virtualizables = self.virtualizables
+        builder = self.curbuilder
+        gv_shape = builder.rgenop.genconst(0)
         if virtualizables:
-            builder = self.curbuilder            
             for virtualizable_box in virtualizables:
                 content = virtualizable_box.content
                 assert isinstance(content, rcontainer.VirtualizableStruct)
                 content.after_residual_call(self)
+            memo = self.make_vinfo_memo
+            self.make_vinfo_memo = None
+            for container, gv_vinfo in memo.containers.iteritems():
+                if isinstance(container, rcontainer.VirtualizableStruct):
+                    continue
+                assert isinstance(container, rcontainer.VirtualStruct)
+                typedesc = container.typedesc # xxx
+                gv_new_shape = builder.genop_call(typedesc.vinfo_get_shape_token,
+                                                  typedesc.gv_vinfo_get_shape_ptr,
+                                                  [gv_vinfo])
+                gv_shape = builder.genop2('int_or', gv_shape, gv_new_shape)
+        return rvalue.IntRedBox(builder.rgenop.kindToken(lltype.Signed), gv_shape)
 
+    def reshape(self, shapemask):
+        virtualizables = self.virtualizables
+        builder = self.curbuilder
+        if virtualizables and shapemask:
+            memo = rvalue.make_vinfo_memo()
+            memo.bitcount = 0            
+            for virtualizable_box in virtualizables:
+                content = virtualizable_box.content
+                assert isinstance(content, rcontainer.VirtualizableStruct)
+                content.reshape(self, None, shapemask, memo) # xxx gv_vinfo argument
+                
     def freeze(self, memo):
         result = FrozenJITState()
         result.fz_frame = self.frame.freeze(memo)

Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py	Fri Jan 19 16:38:09 2007
@@ -1126,7 +1126,29 @@
 
         res = self.timeshift(f, [0, 2], [0], policy=P_NOVIRTUAL)
         assert res == 42
-        self.check_insns({'int_mul': 1})        
+        self.check_insns({'int_mul': 1})
+
+    def test_simple_red_meth_vars_around(self):
+        class Base(object):
+            def m(self, n):
+                raise NotImplementedError
+            pass  # for inspect.getsource() bugs
+
+        class Concrete(Base):
+            def m(self, n):
+                return 21*n
+            pass  # for inspect.getsource() bugs
+
+        def f(flag, x, y, z):
+            if flag:
+                o = Base()
+            else:
+                o = Concrete()
+            return (o.m(x)+y)-z
+
+        res = self.timeshift(f, [0, 2, 7, 5], [0], policy=P_NOVIRTUAL)
+        assert res == 44
+        self.check_insns({'int_mul': 1, 'int_add': 1, 'int_sub': 1})              
 
     def test_compile_time_const_tuple(self):
         d = {(4, 5): 42, (6, 7): 12}

Modified: pypy/dist/pypy/jit/timeshifter/test/test_virtualizable.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/test/test_virtualizable.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/test/test_virtualizable.py	Fri Jan 19 16:38:09 2007
@@ -2,6 +2,7 @@
 from pypy.jit.timeshifter.test.test_portal import PortalTest, P_NOVIRTUAL
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.jit.timeshifter.rcontainer import VABLEINFOPTR
+from pypy.rlib.objectmodel import hint
 import py
 
 S = lltype.GcStruct('s', ('a', lltype.Signed), ('b', lltype.Signed))
@@ -502,6 +503,7 @@
             e.w = y
 
         def f(e):
+            hint(None, global_merge_point=True)
             xy = e.xy
             xy_access = xy.vable_access
             if xy_access:
@@ -553,6 +555,7 @@
             e.w = y
 
         def f(e):
+            hint(None, global_merge_point=True)
             xy = e.xy
             xy_access = xy.vable_access
             if xy_access:
@@ -610,6 +613,7 @@
             e.w = p.a + p.b + x
 
         def f(e, a, b):
+            hint(None, global_merge_point=True)
             xp = e.xp
             s = lltype.malloc(S)
             s.a = a
@@ -674,6 +678,7 @@
             e.w = int(p1 == p2)
 
         def f(e, a, b):
+            hint(None, global_merge_point=True)
             xp = e.xp
             s = lltype.malloc(S)
             s.a = a
@@ -747,6 +752,7 @@
             e.w = int(p != q)
 
         def f(e, a, b):
+            hint(None, global_merge_point=True)
             pq = e.pq
             s = lltype.malloc(S)
             s.a = a
@@ -816,6 +822,7 @@
             e.w = int(p == q)
 
         def f(e, a, b):
+            hint(None, global_merge_point=True)            
             pq = e.pq
             s = lltype.malloc(S)
             s.a = a
@@ -858,3 +865,72 @@
         res = self.timeshift_from_portal(main, f, [2, 20, 10],
                                          policy=StopAtGPolicy())
         assert res == 1
+
+    def test_explicit_force_in_residual_red_call_with_more_use(self):
+        def g(e):
+            xp = e.xp
+            xp_access = xp.vable_access
+            if xp_access:
+                p = xp_access.get_p(xp)
+            else:
+                p = xp.p
+            xp_access = xp.vable_access
+            if xp_access:
+                x = xp_access.get_x(xp)
+            else:
+                x = xp.x                
+            e.w = p.a + p.b + x
+            p.b, p.a = p.a, p.b
+
+        def f(e, a, b):
+            hint(None, global_merge_point=True)
+            xp = e.xp
+            s = lltype.malloc(S)
+            s.a = a
+            s.b = b            
+            xp_access = xp.vable_access
+            if xp_access:
+                xp_access.set_p(xp, s)
+            else:
+                xp.p = s
+            xp_access = xp.vable_access
+            
+            xp_access = xp.vable_access
+            if xp_access:
+                x = xp_access.get_x(xp)
+            else:
+                x = xp.x
+            xp_access = xp.vable_access
+            newx = 2*x
+            if xp_access:
+                xp_access.set_x(xp, newx)
+            else:
+                xp.x = newx
+            g(e)
+            s.a = s.a*7
+            s.b = s.b*5
+            return xp.x
+            
+        def main(a, b, x):
+            xp = lltype.malloc(XP)
+            xp.vable_access = lltype.nullptr(XP_ACCESS)
+            xp.x = x
+            xp.p = lltype.nullptr(S)
+            e = lltype.malloc(E2)
+            e.xp = xp
+            f(e, a, b)
+            return e.w + xp.p.a + xp.p.b
+
+
+        class StopAtGPolicy(HintAnnotatorPolicy):
+            def __init__(self):
+                HintAnnotatorPolicy.__init__(self, novirtualcontainer=True)
+
+            def look_inside_graph(self, graph):
+                if graph.name == 'g':
+                    return False
+                return True
+
+        res = self.timeshift_from_portal(main, f, [2, 20, 10],
+                                         policy=StopAtGPolicy())
+        assert res == 42 + 140 + 10

Modified: pypy/dist/pypy/jit/timeshifter/transform.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/transform.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/transform.py	Fri Jan 19 16:38:09 2007
@@ -151,12 +151,15 @@
 
     # __________ helpers __________
 
-    def genop(self, block, opname, args, resulttype=None, result_like=None):
+    def genop(self, block, opname, args, resulttype=None, result_like=None, red=False):
         # 'result_like' can be a template variable whose hintannotation is
         # copied
         if resulttype is not None:
             v_res = varoftype(resulttype)
-            hs = hintmodel.SomeLLAbstractConstant(resulttype, {})
+            if red:
+                hs = hintmodel.SomeLLAbstractVariable(resulttype)
+            else:
+                hs = hintmodel.SomeLLAbstractConstant(resulttype, {})
             self.hannotator.setbinding(v_res, hs)
         elif result_like is not None:
             v_res = copyvar(self.hannotator, result_like)
@@ -615,19 +618,15 @@
         postconstantblock.recloseblock(Link([], resumeblock))
 
         if nonconstantblock is not None:
-            args_v = op.args[1:]
-            if op.opname == 'indirect_call':
-                del args_v[-1]
-            # pseudo-obscure: the arguments for the call go in save_locals
-            args_v = [v for v in args_v if v.concretetype is not lltype.Void]
-            self.genop(nonconstantblock, 'save_locals', args_v)
-            v_res = self.genop(nonconstantblock, 'residual_%s_call' % (color,),
-                               [op.args[0]], result_like = op.result)
+            v_res, nonconstantblock2 = self.handle_residual_call_details(nonconstantblock, 0,
+                                                                         op, color,
+                                                                         preserve_res = False)
 
             if color == 'red':
                 linkargs[0] = v_res
-            
-            nonconstantblock.closeblock(Link(linkargs, nextblock))
+
+            blockset[nonconstantblock2] = False            
+            nonconstantblock2.recloseblock(Link(linkargs, nextblock))
 
         blockset[block] = True     # reachable from outside
         blockset[nextblock] = True # reachable from outside
@@ -700,25 +699,49 @@
                     postblock: False}, self.hannotator)
 
     def handle_residual_call(self, block, pos):
-        op = block.operations[pos]
+        op = block.operations[pos]        
+        if op.result.concretetype is lltype.Void:
+            color = 'gray'
+        else:
+            color = 'red'
+        v_res, _ = self.handle_residual_call_details(block, pos, op, color)
+        return v_res
+                    
+    def handle_residual_call_details(self, block, pos, op, color, preserve_res=True):
         if op.opname == 'direct_call':
             args_v = op.args[1:]
         elif op.opname == 'indirect_call':
             args_v = op.args[1:-1]
         else:
             raise AssertionError(op.opname)
-        if op.result.concretetype is lltype.Void:
-            color = 'gray'
-        else:
-            color = 'red'
         newops = []
         # pseudo-obscure: the arguments for the call go in save_locals
         args_v = [v for v in args_v if v.concretetype is not lltype.Void]
         self.genop(newops, 'save_locals', args_v)
-        self.genop(newops, 'residual_%s_call' % (color,),
-                   [op.args[0]], result_like = op.result)
-        newops[-1].result = op.result
+        self.genop(newops, 'prepare_residual_call', [])
+        call_index = len(newops)
+        v_res = self.genop(newops, 'residual_%s_call' % (color,),
+                           [op.args[0]], result_like = op.result)
+        v_shape = self.genop(newops, 'after_residual_call', [], resulttype=lltype.Signed, red=True)
+        reshape_index = len(newops)
+        self.genop(newops, 'reshape', [v_shape])
+        reshape_pos = pos+reshape_index
         block.operations[pos:pos+1] = newops
+        if preserve_res:
+            v_res = newops[call_index].result = op.result
+
+        link = split_block(self.hannotator, block, reshape_pos)
+        nextblock = link.target
+
+        reds, greens = self.sort_by_color(link.args)
+        self.genop(block, 'save_locals', reds)
+        v_finished_flag = self.genop(block, 'promote', [v_shape],
+                                     resulttype = lltype.Bool)
+        self.go_to_dispatcher_if(block, v_finished_flag)
+
+            
+        return v_res, nextblock
+
 
     # __________ hints __________
 
@@ -764,7 +787,6 @@
         block.operations[i] = newop
 
         link = split_block(self.hannotator, block, i)
-        nextblock = link.target
 
         reds, greens = self.sort_by_color(link.args)
         self.genop(block, 'save_locals', reds)



More information about the Pypy-commit mailing list