[pypy-svn] r32831 - in pypy/dist/pypy/jit/timeshifter: . test

arigo at codespeak.net arigo at codespeak.net
Mon Oct 2 21:24:24 CEST 2006


Author: arigo
Date: Mon Oct  2 21:24:22 2006
New Revision: 32831

Modified:
   pypy/dist/pypy/jit/timeshifter/rtimeshift.py
   pypy/dist/pypy/jit/timeshifter/test/test_promotion.py
Log:
(pedronis, arre, arigo)

A new test, and trying to do the "right thing" about promotion points.
Now they "should" work in all situations, including with merges all
around the place.

That check-in took quiiiiiiite a bit of time (basically, compare with
the timestamp of the previous check-in...).



Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py	Mon Oct  2 21:24:22 2006
@@ -191,6 +191,9 @@
         incoming[i].genvar = linkargs[i]
     return newblock
 
+def return_marker(jitstate):
+    raise AssertionError("shouldn't get here")
+
 def start_new_block(states_dic, jitstate, key, global_resumer):
     memo = rvalue.freeze_memo()
     frozen = jitstate.freeze(memo)
@@ -199,13 +202,15 @@
     res = frozen.exactmatch(jitstate, outgoingvarboxes, memo)
     assert res, "exactmatch() failed"
     newblock = enter_next_block(jitstate, outgoingvarboxes)
+    # XXX don't save newblock, or have rgenop produce None, when resuming
     states_dic[key] = frozen, newblock
-    if global_resumer:
+    if global_resumer is not None and global_resumer is not return_marker:
         greens_gv = jitstate.greens
         rgenop = jitstate.curbuilder.rgenop
         jitstate.promotion_path = PromotionPathRoot(greens_gv, rgenop,
                                                     frozen, newblock,
                                                     global_resumer)
+        # XXX put a PromotionPathMergesToSee too
 start_new_block._annspecialcase_ = "specialize:arglltype(2)"
 
 def retrieve_jitstate_for_merge(states_dic, jitstate, key, global_resumer):
@@ -233,9 +238,28 @@
     if replace_memo.boxes:
         jitstate.replace(replace_memo)
     start_new_block(states_dic, jitstate, key, global_resumer)
+    if global_resumer is None:
+        merge_generalized(jitstate)
     return False       # continue
 retrieve_jitstate_for_merge._annspecialcase_ = "specialize:arglltype(2)"
 
+def merge_generalized(jitstate):
+    resuming = jitstate.resuming
+    if resuming is None:
+        node = jitstate.promotion_path
+        while not node.cut_limit:
+            node = node.next
+        dispatch_queue = jitstate.frame.dispatch_queue
+        count = dispatch_queue.mergecounter + 1
+        dispatch_queue.mergecounter = count
+        node = PromotionPathMergesToSee(node, count)
+        jitstate.promotion_path = node
+    else:
+        if resuming.mergesleft != MC_IGNORE_UNTIL_RETURN:
+            assert resuming.mergesleft > 0
+            resuming.mergesleft -= 1
+
+
 def enter_block(jitstate):
     incoming = []
     memo = rvalue.enter_block_memo()
@@ -247,12 +271,18 @@
     if exitgvar.is_const:
         return exitgvar.revealconst(lltype.Bool)
     else:
-        if jitstate.resuming is None:
-            later_builder = jitstate.curbuilder.jump_if_false(exitgvar)
-            jitstate.split(later_builder, resumepoint, list(greens_gv))
-            return True
-        else:
-            return jitstate.resuming.path.pop().answer
+        resuming = jitstate.resuming
+        if resuming is not None and resuming.mergesleft == 0:
+            node = resuming.path.pop()
+            assert isinstance(node, PromotionPathSplit)
+            return node.answer
+        later_builder = jitstate.curbuilder.jump_if_false(exitgvar)
+        jitstate2 = jitstate.split(later_builder, resumepoint, list(greens_gv))
+        if resuming is None:
+            node = jitstate.promotion_path
+            jitstate2.promotion_path = PromotionPathNo(node)
+            jitstate .promotion_path = PromotionPathYes(node)
+        return True
 
 def collect_split(jitstate_chain, resumepoint, *greens_gv):
     greens_gv = list(greens_gv)
@@ -351,6 +381,16 @@
         path[0] = node
         self.promotion_point = promotion_point
         self.path = path
+        self.mergesleft = 0
+
+    def merges_to_see(self):
+        node = self.path[-1]
+        if isinstance(node, PromotionPathMergesToSee):
+            self.mergesleft = node.count
+            del self.path[-1]
+        else:
+            self.mergesleft = MC_IGNORE_UNTIL_RETURN
+
 
 class PromotionPoint(object):
     def __init__(self, flexswitch, switchblock, promotion_path):
@@ -360,9 +400,11 @@
         self.promotion_path = promotion_path
 
 class AbstractPromotionPath(object):
-    pass
+    cut_limit = False
 
 class PromotionPathRoot(AbstractPromotionPath):
+    cut_limit = True
+
     def __init__(self, greens_gv, rgenop, frozen, portalblock, global_resumer):
         self.greens_gv = greens_gv
         self.rgenop = rgenop
@@ -395,28 +437,40 @@
         path.append(self)
         return self.next.follow_path(path)
 
-class PromotionPathYes(PromotionPathNode):
+class PromotionPathSplit(PromotionPathNode):
+    pass
+
+class PromotionPathYes(PromotionPathSplit):
     answer = True
 
-class PromotionPathNo(PromotionPathNode):
+class PromotionPathNo(PromotionPathSplit):
     answer = False
 
-class PromotionPathNoWithArg(PromotionPathNo):
-
-    def __init__(self, next, arg):
-        self.next = next
-        self.arg = arg
-
-    def follow_path(self, path):
-        path.append(self)
-        return PromotionPathNo.follow_path(self, path)
+class PromotionPathCallNotTaken(PromotionPathNode):
+    pass
 
 class PromotionPathPromote(PromotionPathNode):
+    cut_limit = True
+
     def __init__(self, next, promotion_point, gv_value):
         self.next = next
         self.promotion_point = promotion_point
         self.gv_value = gv_value
 
+class PromotionPathCall(PromotionPathNode):
+    cut_limit = True
+
+class PromotionPathBackFromReturn(PromotionPathNode):
+    cut_limit = True
+
+class PromotionPathMergesToSee(PromotionPathNode):
+    def __init__(self, next, count):
+        self.next = next
+        self.count = count
+
+MC_IGNORE_UNTIL_RETURN = -1
+MC_CALL_NOT_TAKEN      = -2
+
 
 def ll_continue_compilation(promotion_point_ptr, value):
     try:
@@ -450,9 +504,9 @@
     def _freeze_(self):
         return True
 
-def ll_promote(jitstate, box, promotiondesc):
+def ll_promote(jitstate, promotebox, promotiondesc):
     builder = jitstate.curbuilder
-    gv_switchvar = box.getgenvar(builder)
+    gv_switchvar = promotebox.getgenvar(builder)
     if gv_switchvar.is_const:
         return False
     else:
@@ -462,7 +516,7 @@
         switchblock = enter_next_block(jitstate, incoming)
 
         if jitstate.resuming is None:
-            gv_switchvar = box.genvar
+            gv_switchvar = promotebox.genvar
             flexswitch = builder.flexswitch(gv_switchvar)
             # default case of the switch:
             enter_block(jitstate)
@@ -470,7 +524,7 @@
                                 jitstate.promotion_path)
             ll_pm = cast_instance_to_base_ptr(pm)
             gv_pm = builder.rgenop.genconst(ll_pm)
-            gv_switchvar = box.genvar
+            gv_switchvar = promotebox.genvar
             builder.genop_call(promotiondesc.sigtoken,
                                promotiondesc.gv_continue_compilation,
                                [gv_pm, gv_switchvar])
@@ -482,11 +536,20 @@
         else:
             assert jitstate.promotion_path is None
             resuming = jitstate.resuming
-            node = resuming.path.pop()
-            #debug_view(node, resuming, incoming)
-            assert isinstance(node, PromotionPathPromote)
-            pm = node.promotion_point
-            assert pm.promotion_path is node.next
+            if resuming.mergesleft != 0:
+                return True
+
+            promotenode = resuming.path.pop()
+            assert isinstance(promotenode, PromotionPathPromote)
+            #debug_view(promotenode, resuming, incoming)
+            pm = promotenode.promotion_point
+            assert pm.promotion_path is promotenode.next
+
+            # clear the complete state of dispatch queues
+            f = jitstate.frame
+            while f is not None:
+                f.dispatch_queue.clear()
+                f = f.backframe
 
             if len(resuming.path) == 0:
                 # XXX we need to do something around the switch in the 'else'
@@ -497,24 +560,30 @@
                     kinds)
                 for i in range(len(incoming)):
                     incoming[i].genvar = vars_gv[i]
-                newbuilder = pm.flexswitch.add_case(node.gv_value)
+                promotebox.genvar = promotenode.gv_value
+                newbuilder = pm.flexswitch.add_case(promotenode.gv_value)
                 jitstate.resuming = None
+                node = PromotionPathMergesToSee(promotenode, 0)
                 jitstate.promotion_path = node
                 jitstate.curbuilder = newbuilder
+            else:
+                resuming.merges_to_see()
+                promotebox.genvar = promotenode.gv_value
 
-            box.genvar = node.gv_value
             enter_block(jitstate)
             return False
 
 # ____________________________________________________________
 
 class BaseDispatchQueue(object):
-    parent_promotion_path = None
-    parent_resuming = None
-    
+
     def __init__(self):
         self.split_chain = None
         self.return_chain = None
+        self.mergecounter = 0
+
+    def clear(self):
+        self.__init__()
 
 def build_dispatch_subclass(attrnames):
     if len(attrnames) == 0:
@@ -633,17 +702,17 @@
 class JITState(object):
     returnbox = None
     next      = None   # for linked lists
-    resuming  = None   # or a ResumingInfo
+    promotion_path = None
 
     def __init__(self, builder, frame, exc_type_box, exc_value_box,
-                 resumepoint=-1, newgreens=[], promotion_path=None):
+                 resumepoint=-1, newgreens=[], resuming=None):
         self.curbuilder = builder
         self.frame = frame
         self.exc_type_box = exc_type_box
         self.exc_value_box = exc_value_box
         self.resumepoint = resumepoint
         self.greens = newgreens
-        self.promotion_path = promotion_path
+        self.resuming = resuming   # None or a ResumingInfo
 
     def split(self, newbuilder, newresumepoint, newgreens):
         memo = rvalue.copy_memo()
@@ -653,12 +722,12 @@
                                   self.exc_value_box.copy(memo),
                                   newresumepoint,
                                   newgreens,
-                                  PromotionPathNo(self.promotion_path))
-        self.promotion_path = PromotionPathYes(self.promotion_path)
+                                  self.resuming)
         # add the later_jitstate to the chain of pending-for-dispatch_next()
         dispatch_queue = self.frame.dispatch_queue
         later_jitstate.next = dispatch_queue.split_chain
         dispatch_queue.split_chain = later_jitstate
+        return later_jitstate
 
     def enter_block(self, incoming, memo):
         self.frame.enter_block(incoming, memo)
@@ -684,17 +753,25 @@
 enter_graph._annspecialcase_ = 'specialize:arg(1)'
 
 def enter_frame(jitstate, dispatchqueue):
+    jitstate.frame = VirtualFrame(jitstate.frame, dispatchqueue)
     resuming = jitstate.resuming
     if resuming is None:
-        dispatchqueue.parent_promotion_path = jitstate.promotion_path
-        jitstate.promotion_path = PromotionPathYes(jitstate.promotion_path)
+        node = PromotionPathCall(jitstate.promotion_path)
+        node = PromotionPathMergesToSee(node, 0)
+        jitstate.promotion_path = node
     else:
-        taking = resuming.path.pop().answer
-        if not taking:
-            dispatchqueue.parent_resuming = resuming
-            jitstate.resuming = None
-    jitstate.frame = VirtualFrame(jitstate.frame, dispatchqueue)
-                
+        parent_mergesleft = resuming.mergesleft
+        resuming.mergesleft = MC_IGNORE_UNTIL_RETURN
+        if parent_mergesleft == 0:
+            node = resuming.path.pop()
+            if isinstance(node, PromotionPathCall):
+                resuming.merges_to_see()
+            else:
+                assert isinstance(node, PromotionPathCallNotTaken)
+                parent_mergesleft = MC_CALL_NOT_TAKEN
+        dispatchqueue.mergecounter = parent_mergesleft
+
+
 class CompilationInterrupted(Exception):
     pass
 
@@ -705,7 +782,8 @@
     while return_chain is not None:
         jitstate = return_chain
         return_chain = return_chain.next
-        res = retrieve_jitstate_for_merge(return_cache, jitstate, (), None)
+        res = retrieve_jitstate_for_merge(return_cache, jitstate, (),
+                                          return_marker)
         if res is False:    # not finished
             jitstate.next = still_pending
             still_pending = jitstate
@@ -716,7 +794,8 @@
     while still_pending is not None:
         jitstate = still_pending
         still_pending = still_pending.next
-        res = retrieve_jitstate_for_merge(return_cache, jitstate, (), None)
+        res = retrieve_jitstate_for_merge(return_cache, jitstate, (),
+                                          return_marker)
         assert res is True   # finished
     return most_general_jitstate
 
@@ -735,17 +814,32 @@
 
 def leave_frame(jitstate):
     myframe = jitstate.frame
-    jitstate.frame = myframe.backframe
-    assert jitstate.resuming is None
+    backframe = myframe.backframe
+    jitstate.frame = backframe
     mydispatchqueue = myframe.dispatch_queue
-    resuming = mydispatchqueue.parent_resuming
+    resuming = jitstate.resuming
     if resuming is None:
-        parent_promotion_path = mydispatchqueue.parent_promotion_path
-        jitstate.promotion_path = PromotionPathNo(parent_promotion_path)
+        #debug_view(jitstate)
+        node = jitstate.promotion_path
+        while not node.cut_limit:
+            node = node.next
+        if isinstance(node, PromotionPathCall):
+            node = PromotionPathCallNotTaken(node.next)
+        else:
+            node = PromotionPathBackFromReturn(node)
+            node = PromotionPathMergesToSee(node, 0)
+        jitstate.promotion_path = node
     else:
-        jitstate.resuming = resuming
-        jitstate.promotion_path = None
-    
+        parent_mergesleft = mydispatchqueue.mergecounter
+        if parent_mergesleft == 0:
+            node = resuming.path.pop()
+            assert isinstance(node, PromotionPathBackFromReturn)
+            resuming.merges_to_see()
+        elif parent_mergesleft == MC_CALL_NOT_TAKEN:
+            resuming.mergesleft = 0
+        else:
+            resuming.mergesleft = parent_mergesleft
+
 def leave_graph_yellow(jitstate):
     mydispatchqueue = jitstate.frame.dispatch_queue
     return_chain = mydispatchqueue.return_chain

Modified: pypy/dist/pypy/jit/timeshifter/test/test_promotion.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/test/test_promotion.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/test/test_promotion.py	Mon Oct  2 21:24:22 2006
@@ -106,6 +106,25 @@
         assert res == 42
         self.check_insns(int_add=0)
 
+    def test_merge_then_promote(self):
+        S = lltype.GcStruct('S', ('x', lltype.Signed))
+        def ll_two(n):
+            s = lltype.malloc(S)
+            if n < 0:
+                s.x = 10
+            else:
+                s.x = 20
+            k = hint(s.x, promote=True)
+            k *= 17
+            return hint(k, variable=True)
+        def ll_function(n):
+            return ll_two(n)
+        ll_function._global_merge_points_ = True
+
+        res = self.timeshift(ll_function, [3], [], policy=P_NOVIRTUAL)
+        assert res == 340
+        self.check_insns(int_lt=1, int_mul=0)
+
 
     def test_method_call_nonpromote(self):
         class Base(object):



More information about the Pypy-commit mailing list