[pypy-svn] r25205 - in pypy/dist/pypy: jit jit/test rpython

arigo at codespeak.net arigo at codespeak.net
Sat Apr 1 15:57:42 CEST 2006


Author: arigo
Date: Sat Apr  1 15:57:41 2006
New Revision: 25205

Modified:
   pypy/dist/pypy/jit/hinttimeshift.py
   pypy/dist/pypy/jit/rtimeshift.py
   pypy/dist/pypy/jit/test/test_hint_timeshift.py
   pypy/dist/pypy/rpython/rgenop.py
Log:
(pedronis, arre, arigo)

Merging of virtual red boxes, plus a lot of small bugs found
along this path.



Modified: pypy/dist/pypy/jit/hinttimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/hinttimeshift.py	(original)
+++ pypy/dist/pypy/jit/hinttimeshift.py	Sat Apr  1 15:57:41 2006
@@ -1,3 +1,4 @@
+import py
 from pypy.rpython.lltypesystem import lltype
 from pypy.objspace.flow import model as flowmodel
 from pypy.annotation import model as annmodel
@@ -90,6 +91,9 @@
 
         reenter_vars = [v_jitstate]
         for var in link.args[1:]:
+            if isinstance(var, flowmodel.Constant):
+                reenter_vars.append(var)
+                continue
             i = inputargs.index(var)
             r = args_r[i]
             v_box = self.read_out_box(llops, v_boxes, i)
@@ -126,6 +130,7 @@
     def timeshift_graph(self, graph):
         self.graph = graph
         self.dispatch_to = []
+        self.statecaches = []
         entering_links = flowmodel.mkentrymap(graph)
 
         originalblocks = list(graph.iterblocks())
@@ -160,6 +165,20 @@
         # fix its concretetypes
         self.insert_dispatch_logic(returnblock)
 
+        # hack to allow the state caches to be cleared
+        miniglobals = {}
+        source = ["def clearcaches():"]
+        if self.statecaches:
+            for i, cache in enumerate(self.statecaches):
+                source.append("    c%d.clear()" % i)
+                miniglobals["c%d" % i] = cache
+        else:
+            source.append("    pass")
+        exec py.code.Source('\n'.join(source)).compile() in miniglobals
+        clearcaches = miniglobals['clearcaches']
+        self.ll_clearcaches = self.annhelper.getgraph(clearcaches, [],
+                                                      annmodel.s_None)
+
     def insert_jitstate_arg(self, block):
         # pass 'jitstate' as an extra argument around the whole graph
         if block.operations != ():
@@ -315,6 +334,8 @@
         v_oldjitstate = newinputargs[0]
 
         cache = {}
+        self.statecaches.append(cache)
+
         def merge_point(jitstate, key, boxes):
             return rtimeshift.retrieve_jitstate_for_merge(cache, jitstate,
                                                           key, boxes, TYPES_gv)

Modified: pypy/dist/pypy/jit/rtimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/rtimeshift.py	(original)
+++ pypy/dist/pypy/jit/rtimeshift.py	Sat Apr  1 15:57:41 2006
@@ -41,6 +41,23 @@
         except KeyError:
             return self._copybox(newblock, gv_type, memo)
 
+    def match(self, jitstate, newbox, incoming, memo):
+        if self in memo:
+            return memo[self] is newbox
+        if newbox in memo:
+            return memo[newbox] is self
+        memo[self] = newbox
+        memo[newbox] = self
+        return self._match(jitstate, newbox, incoming, memo)
+
+    def union_for_new_block(self, jitstate, newbox, newblock,
+                            gv_type, incoming, memo):
+        try:
+            return memo[newbox]
+        except KeyError:
+            return self._union_for_new_block(jitstate, newbox, newblock,
+                                             gv_type, incoming, memo)
+
     # generic implementation of some operations
     def op_getfield(self, jitstate, fielddesc):
         op_args = lltype.malloc(VARLIST.TO, 2)
@@ -86,6 +103,20 @@
         memo[self] = newbox = VarRedBox(newgenvar)
         return newbox
 
+        incoming.append(newbox.getgenvar(jitstate))
+        return True
+
+    def _match(self, jitstate, newbox, incoming, memo):
+        incoming.append(newbox.getgenvar(jitstate))
+        return True
+
+    def _union_for_new_block(self, jitstate, newbox, newblock,
+                             gv_type, incoming, memo):
+        incoming.append(newbox.getgenvar(jitstate))
+        newgenvar = rgenop.geninputarg(newblock, gv_type)
+        memo[newbox] = newnewbox = VarRedBox(newgenvar)
+        return newnewbox
+
 
 VCONTAINER = lltype.GcStruct("vcontainer")
 
@@ -186,6 +217,47 @@
                                                                     memo)
         return bigbox
 
+    def _match(self, jitstate, newbox, incoming, memo):
+        if self.genvar:
+            incoming.append(newbox.getgenvar(jitstate))
+            return True
+        if not isinstance(newbox, VirtualRedBox):
+            return False
+        for i in range(len(self.content_boxes)):
+            mysmallbox  = self.content_boxes[i]
+            newsmallbox = newbox.content_boxes[i]
+            if not mysmallbox.match(jitstate, newsmallbox, incoming, memo):
+                return False
+        else:
+            return True
+
+    def inlined_structs_are_compatible(self, newbox):
+        return (isinstance(newbox, VirtualRedBox) and
+                self.typedesc.compare_content_boxes(self.content_boxes,
+                                                    newbox.content_boxes))
+
+    def _union_for_new_block(self, jitstate, newbox, newblock,
+                             gv_type, incoming, memo):
+        if self.genvar or not self.inlined_structs_are_compatible(newbox):
+            incoming.append(newbox.getgenvar(jitstate))
+            newgenvar = rgenop.geninputarg(newblock, gv_type)
+            memo[newbox] = newnewbox = VarRedBox(newgenvar)
+            return newnewbox
+        bigbox = VirtualRedBox(self.typedesc)
+        memo[newbox] = bigbox
+        for i in range(len(bigbox.content_boxes)):
+            gv_fldtype = self.typedesc.fielddescs[i].gv_resulttype
+            box = self.content_boxes[i]
+            bigbox.content_boxes[i] = box.union_for_new_block(
+                jitstate,
+                newbox.content_boxes[i],
+                newblock,
+                gv_fldtype,
+                incoming,
+                memo)
+        return bigbox
+
+
 class SubVirtualRedBox(BigRedBox):
 
     def __init__(self, parentbox, fielddesc):
@@ -233,6 +305,62 @@
                                                                     memo)
         return bigbox
 
+    def _match(self, jitstate, newbox, incoming, memo):
+        if self.is_forced():
+            incoming.append(newbox.getgenvar(jitstate))
+            return True
+        if not (isinstance(newbox, SubVirtualRedBox) and
+                self.fielddesc is newbox.fielddesc and
+                self.parentbox.match(jitstate, newbox.parentbox,
+                                     incoming, memo)):
+            return False
+        for i in range(len(self.content_boxes)):
+            mysmallbox  = self.content_boxes[i]
+            newsmallbox = newbox.content_boxes[i]
+            if not mysmallbox.match(jitstate, newsmallbox, incoming, memo):
+                return False
+        else:
+            return True
+
+    def inlined_structs_are_compatible(self, newbox):
+        if (isinstance(newbox, SubVirtualRedBox) and
+            self.fielddesc is newbox.fielddesc):
+            return self.parentbox.inlined_structs_are_compatible(
+                newbox.parentbox)
+        else:
+            return False
+
+    def _union_for_new_block(self, jitstate, newbox, newblock,
+                             gv_type, incoming, memo):
+        if self.is_forced() or not self.inlined_structs_are_compatible(newbox):
+            incoming.append(newbox.getgenvar(jitstate))
+            newgenvar = rgenop.geninputarg(newblock, gv_type)
+            memo[newbox] = newnewbox = VarRedBox(newgenvar)
+            return newnewbox
+        assert isinstance(newbox, SubVirtualRedBox)
+        bigbox = SubVirtualRedBox(None, self.fielddesc)
+        memo[newbox] = bigbox
+        gv_parenttype = self.fielddesc.parenttypedesc.gv_ptrtype
+        parentcopybox = self.parentbox.union_for_new_block(jitstate,
+                                                           newbox.parentbox,
+                                                           newblock,
+                                                           gv_parenttype,
+                                                           incoming,
+                                                           memo)
+        bigbox.parentbox = parentcopybox
+        typedesc = self.fielddesc.inlined_typedesc
+        for i in range(len(bigbox.content_boxes)):
+            gv_fldtype = typedesc.fielddescs[i].gv_resulttype
+            box = self.content_boxes[i]
+            bigbox.content_boxes[i] = box.union_for_new_block(
+                jitstate,
+                newbox.content_boxes[i],
+                newblock,
+                gv_fldtype,
+                incoming,
+                memo)
+        return bigbox
+
 
 class ConstRedBox(RedBox):
     "A red box that contains a run-time constant."
@@ -246,6 +374,20 @@
     def copybox(self, newblock, gv_type, memo):
         return self
 
+    def match(self, jitstate, newbox, incoming, memo):
+        return self.same_constant(newbox)
+
+    def _union_for_new_block(self, jitstate, newbox, newblock,
+                             gv_type, incoming, memo):
+        if self.same_constant(newbox):
+            newnewbox = newbox
+        else:
+            incoming.append(newbox.getgenvar(jitstate))
+            newgenvar = rgenop.geninputarg(newblock, gv_type)
+            newnewbox = VarRedBox(newgenvar)
+        memo[newbox] = newnewbox
+        return newnewbox
+
     def ll_fromvalue(value):
         T = lltype.typeOf(value)
         gv = rgenop.genconst(value)
@@ -406,6 +548,20 @@
             clist.append(box)
         return clist
 
+    def compare_content_boxes(self, content_boxes_1, content_boxes_2):
+        for i in range(len(self.fielddescs)):
+            fielddesc = self.fielddescs[i]
+            if fielddesc.inlined_typedesc:
+                box1 = content_boxes_1[i]
+                box2 = content_boxes_2[i]
+                assert isinstance(box1, BigRedBox)
+                assert isinstance(box2, BigRedBox)
+                if not fielddesc.inlined_typedesc.compare_content_boxes(
+                    box1.content_boxes, box2.content_boxes):
+                    return False
+        else:
+            return True
+
     def materialize_content(self, jitstate, gv, boxes):
         for i in range(len(boxes)):
             smallbox = boxes[i]
@@ -545,48 +701,56 @@
 # other jitstate/graph level operations
 
 
-def retrieve_jitstate_for_merge(states_dic, jitstate, key, redboxes, TYPES):
+def retrieve_jitstate_for_merge(states_dic, jitstate, key, redboxes, types_gv):
     if key not in states_dic:
-        jitstate = enter_block(jitstate, redboxes, TYPES)
-        states_dic[key] = redboxes[:], jitstate.curblock
+        jitstate = enter_block(jitstate, redboxes, types_gv)
+        states_dic[key] = redboxes, jitstate.curblock
         return jitstate
 
     oldboxes, oldblock = states_dic[key]
+    memo = {}
     incoming = []
     for i in range(len(redboxes)):
         oldbox = oldboxes[i]
         newbox = redboxes[i]
-        if isinstance(oldbox, VarRedBox):  # Always a match
-            incoming.append(newbox.getgenvar(jitstate))
-            continue
-        if oldbox.same_constant(newbox):
-            continue
-        # Mismatch. Generalize to a var
-        break
+        if not oldbox.match(jitstate, newbox, incoming, memo):
+            break   # mismatch
+##        if isinstance(oldbox, VarRedBox):  # Always a match
+##            incoming.append(newbox.getgenvar(jitstate))
+##            continue
+##        if oldbox.same_constant(newbox):
+##            continue
+##        # Mismatch. Generalize to a var
+##        break
     else:
         rgenop.closelink(jitstate.curoutgoinglink, incoming, oldblock)
         return None
     
     # Make a more general block
+    jitstate = enter_block(jitstate, redboxes, types_gv)
     newblock = rgenop.newblock()
     incoming = []
+    memo = {}
     for i in range(len(redboxes)):
         oldbox = oldboxes[i]
         newbox = redboxes[i]
-        if not oldbox.same_constant(newbox):
-            incoming.append(newbox.getgenvar(jitstate))
-            newgenvar = rgenop.geninputarg(newblock, TYPES[i])
-            redboxes[i] = VarRedBox(newgenvar)
-
-    rgenop.closelink(jitstate.curoutgoinglink, incoming, newblock)
+        redboxes[i] = oldbox.union_for_new_block(jitstate, newbox, newblock,
+                                                 types_gv[i], incoming, memo)
+##        if not oldbox.same_constant(newbox):
+##            incoming.append(newbox.getgenvar(jitstate))
+##            newgenvar = rgenop.geninputarg(newblock, TYPES[i])
+##            redboxes[i] = VarRedBox(newgenvar)
+    link = rgenop.closeblock1(jitstate.curblock)
+    rgenop.closelink(link, incoming, newblock)
     jitstate.curblock = newblock
-    jitstate.curoutgoinglink = lltype.nullptr(rgenop.LINK.TO)
-    states_dic[key] = redboxes[:], newblock
+    #jitstate.curoutgoinglink = lltype.nullptr(rgenop.LINK.TO)
+    states_dic[key] = redboxes, newblock
     return jitstate
 retrieve_jitstate_for_merge._annspecialcase_ = "specialize:arglltype(2)"
     
 def enter_block(jitstate, redboxes, types_gv):
     newblock = rgenop.newblock()
+    jitstate.curblock = newblock
     incoming = []
     memo1 = {}
     memo2 = {}
@@ -595,7 +759,6 @@
         redbox.getallvariables(jitstate, incoming, memo1)
         redboxes[i] = redbox.copybox(newblock, types_gv[i], memo2)
     rgenop.closelink(jitstate.curoutgoinglink, incoming, newblock)
-    jitstate.curblock = newblock
     jitstate.curoutgoinglink = lltype.nullptr(rgenop.LINK.TO)
     return jitstate
 
@@ -622,7 +785,7 @@
 
 novars = lltype.malloc(VARLIST.TO, 0)
 
-def dispatch_next(jitstate, outredboxes, RETURN_TYPE):
+def dispatch_next(jitstate, outredboxes, gv_return_type):
     split_queue = jitstate.split_queue
     if split_queue:
         exitindex, later_jitstate, redboxes = split_queue.pop()
@@ -635,26 +798,35 @@
     return_queue = jitstate.return_queue
     first_redbox = return_queue[0][1]
     finalblock = rgenop.newblock()
-    jitstate.curblock = finalblock
-    if isinstance(first_redbox, ConstRedBox):
-        for link, redbox in return_queue:
-            if not redbox.same_constant(first_redbox):
-                break
-        else:
-            for link, _ in return_queue:
-                rgenop.closelink(link, novars, finalblock)
-            finallink = rgenop.closeblock1(finalblock)
-            jitstate.curoutgoinglink = finallink
-            jitstate.curvalue = first_redbox
-            return -1
+##    jitstate.curblock = finalblock
+##    if isinstance(first_redbox, ConstRedBox):
+##        for link, redbox in return_queue:
+##            if not redbox.match(first_redbox):
+##                break
+##        else:
+##            for link, _ in return_queue:
+##                rgenop.closelink(link, novars, finalblock)
+##            finallink = rgenop.closeblock1(finalblock)
+##            jitstate.curoutgoinglink = finallink
+##            jitstate.curvalue = first_redbox
+##            return -1
 
-    finalvar = rgenop.geninputarg(finalblock, RETURN_TYPE)
+    finalvar = rgenop.geninputarg(finalblock, gv_return_type)
     for link, redbox in return_queue:
-        genvar = redbox.getgenvar(jitstate)
-        rgenop.closelink(link, [genvar], finalblock)
+        newblock = rgenop.newblock()
+        jitstate.curblock = newblock
+        incoming = []
+        memo1 = {}
+        memo2 = {}
+        redbox.getallvariables(jitstate, incoming, memo1)
+        newbox = redbox.copybox(newblock, gv_return_type, memo2)
+        gv_retval = newbox.getgenvar(jitstate)
+        rgenop.closelink(link, incoming, newblock)
+        newlink = rgenop.closeblock1(newblock)
+        rgenop.closelink(newlink, [gv_retval], finalblock)
     finallink = rgenop.closeblock1(finalblock)
     jitstate.curoutgoinglink = finallink
-    jitstate.curvalue = VarRedBox(finalvar)
+    jitstate.curvalue = finalvar
     return -1
 
 def ll_gvar_from_redbox(jitstate, redbox):
@@ -672,7 +844,7 @@
         self.return_queue = []
         self.split_queue = []
         self.curblock = rgenop.newblock()
-        self.curvalue = None
+        self.curvalue = rgenop.nullvar
 
     def end_setup(self):
         self.curoutgoinglink = rgenop.closeblock1(self.curblock)
@@ -712,5 +884,5 @@
     return jitstate.curblock
 
 def ll_close_jitstate(jitstate):
-    result_genvar = jitstate.curvalue.getgenvar(jitstate)
+    result_genvar = jitstate.curvalue
     jitstate.close(result_genvar)

Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py
==============================================================================
--- pypy/dist/pypy/jit/test/test_hint_timeshift.py	(original)
+++ pypy/dist/pypy/jit/test/test_hint_timeshift.py	Sat Apr  1 15:57:41 2006
@@ -19,11 +19,14 @@
 P_NOVIRTUAL = AnnotatorPolicy()
 P_NOVIRTUAL.novirtualcontainer = True
 
+def getargtypes(annotator, values):
+    return [annotation(annotator, x) for x in values]
+
 def hannotate(func, values, policy=None, inline=None):
     # build the normal ll graphs for ll_function
     t = TranslationContext()
     a = t.buildannotator()
-    argtypes = [annotation(a, x) for x in values]
+    argtypes = getargtypes(a, values)
     a.build_types(func, argtypes)
     rtyper = t.buildrtyper()
     rtyper.specialize()
@@ -40,20 +43,40 @@
         hannotator.translator.view()
     return hs, hannotator, rtyper
 
+_cache = {}
+_cache_order = []
+def timeshift_cached(ll_function, values, inline, policy):
+    key = ll_function, inline, policy
+    try:
+        result, argtypes = _cache[key]
+    except KeyError:
+        if len(_cache_order) >= 3:
+            del _cache[_cache_order.pop(0)]
+        hs, ha, rtyper = hannotate(ll_function, values,
+                                   inline=inline, policy=policy)
+        htshift = HintTimeshift(ha, rtyper)
+        htshift.timeshift()
+        t = rtyper.annotator.translator
+        for graph in ha.translator.graphs:
+            checkgraph(graph)
+            t.graphs.append(graph)
+        if conftest.option.view:
+            t.view()
+        result = hs, ha, rtyper, htshift
+        _cache[key] = result, getargtypes(rtyper.annotator, values)
+        _cache_order.append(key)
+    else:
+        hs, ha, rtyper, htshift = result
+        assert argtypes == getargtypes(rtyper.annotator, values)
+    return result
+
 def timeshift(ll_function, values, opt_consts=[], inline=None, policy=None):
-    hs, ha, rtyper = hannotate(ll_function, values,
-                               inline=inline, policy=policy)
-    htshift = HintTimeshift(ha, rtyper)
-    htshift.timeshift()
-    t = rtyper.annotator.translator
-    for graph in ha.translator.graphs:
-        checkgraph(graph)
-        t.graphs.append(graph)
-    if conftest.option.view:
-        t.view()
+    hs, ha, rtyper, htshift = timeshift_cached(ll_function, values,
+                                               inline, policy)
     # run the time-shifted graph-producing graphs
     graph1 = ha.translator.graphs[0]
     llinterp = LLInterpreter(rtyper)
+    llinterp.eval_graph(htshift.ll_clearcaches, [])
     jitstate = llinterp.eval_graph(htshift.ll_build_jitstate_graph, [])
     graph1args = [jitstate]
     residual_graph_args = []
@@ -238,7 +261,30 @@
     insns, res = timeshift(ll_function, [70, 4], [0])
     assert res == 66
     assert insns['int_add'] == 1
-    assert insns['int_add'] == 1
+    assert insns['int_sub'] == 1
+
+def test_merge_const_before_return():
+    def ll_function(x):
+        if x > 0:
+            y = 17
+        else:
+            y = 22
+        x -= 1
+        y += 1
+        return y+x
+    insns, res = timeshift(ll_function, [-70], [])
+    assert res == 23-71
+    assert insns == {'int_gt': 1, 'int_add': 2, 'int_sub': 2}
+
+def test_merge_const_at_return():
+    def ll_function(x):
+        if x > 0:
+            return 17
+        else:
+            return 22
+    insns, res = timeshift(ll_function, [-70], [])
+    assert res == 22
+    assert insns == {'int_gt': 1}
 
 def test_arith_plus_minus():
     def ll_plus_minus(encoded_insn, nb_insn, x, y):
@@ -324,13 +370,31 @@
     assert res == 7
     assert insns == {}    
 
-def test_degenerated_merge_substructure():
-    py.test.skip("re in-progress")
+def test_degenerated_before_return():
+    S = lltype.GcStruct('S', ('n', lltype.Signed))
+    T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float))
+
+    def ll_function(flag):
+        t = lltype.malloc(T)
+        t.s.n = 3
+        s = lltype.malloc(S)
+        s.n = 4
+        if flag:
+            s = t.s
+        s.n += 1
+        return s.n * t.s.n
+    insns, res = timeshift(ll_function, [0], [])
+    assert res == 5 * 3
+    insns, res = timeshift(ll_function, [1], [])
+    assert res == 4 * 4
+
+def test_degenerated_at_return():
     S = lltype.GcStruct('S', ('n', lltype.Signed))
     T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float))
 
     def ll_function(flag):
         t = lltype.malloc(T)
+        t.n = 3.25
         t.s.n = 3
         s = lltype.malloc(S)
         s.n = 4
@@ -339,7 +403,12 @@
         return s
     insns, res = timeshift(ll_function, [0], [])
     assert res.n == 4
-    assert insns == {'getsubstruct': 2, 'int_is_true': 1, 'malloc': 2, 'setfield': 2}
+    assert lltype.parentlink(res._obj) == (None, None)
+    insns, res = timeshift(ll_function, [1], [])
+    assert res.n == 3
+    parent, parentindex = lltype.parentlink(res._obj)
+    assert parentindex == 's'
+    assert parent.n == 3.25
 
 def test_plus_minus_all_inlined():
     def ll_plus_minus(s, x, y):

Modified: pypy/dist/pypy/rpython/rgenop.py
==============================================================================
--- pypy/dist/pypy/rpython/rgenop.py	(original)
+++ pypy/dist/pypy/rpython/rgenop.py	Sat Apr  1 15:57:41 2006
@@ -25,6 +25,8 @@
 
 def geninputarg(blockcontainer, gv_CONCRETE_TYPE):
     block = from_opaque_object(blockcontainer.obj)
+    assert not block.operations, "block already contains operations"
+    assert block.exits == [], "block already closed"
     CONCRETE_TYPE = from_opaque_object(gv_CONCRETE_TYPE).value
     v = flowmodel.Variable()
     v.concretetype = CONCRETE_TYPE
@@ -49,6 +51,7 @@
     if not isinstance(opname, str):
         opname = from_rstr(opname)
     block = from_opaque_object(blockcontainer.obj)
+    assert block.exits == [], "block already closed"
     RESULT_TYPE = from_opaque_object(gv_RESULT_TYPE).value
     opvars = _inputvars(vars)    
     v = flowmodel.Variable()



More information about the Pypy-commit mailing list