[pypy-svn] r32567 - in pypy/dist/pypy/jit: hintannotator timeshifter timeshifter/test

arigo at codespeak.net arigo at codespeak.net
Thu Sep 21 18:53:49 CEST 2006


Author: arigo
Date: Thu Sep 21 18:53:47 2006
New Revision: 32567

Modified:
   pypy/dist/pypy/jit/hintannotator/bookkeeper.py
   pypy/dist/pypy/jit/timeshifter/rtimeshift.py
   pypy/dist/pypy/jit/timeshifter/rtyper.py
   pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py
   pypy/dist/pypy/jit/timeshifter/transform.py
Log:
(arre, arigo)

Small refactoring: moved the computation of the graph->tsgraph
correspondance into transform.py.  This is a further step towards making
rtyper.py independent of the hannotator's results, but based only on the
operations produced by transform.

More advanced normalization test.


Modified: pypy/dist/pypy/jit/hintannotator/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/bookkeeper.py	(original)
+++ pypy/dist/pypy/jit/hintannotator/bookkeeper.py	Thu Sep 21 18:53:47 2006
@@ -110,8 +110,11 @@
         return origin
 
     def compute_at_fixpoint(self):
+        pass
+
+    def compute_after_normalization(self):
         # compute and cache the green-ness of OriginFlags objects
-        # while we can do so (i.e. before the graphs are modified)
+        # while we can do so (i.e. before the graphs are modified).
         for origin in self.originflags.values():
             if origin.spaceop is not None:
                 origin.greenargs_cached = origin.greenargs()

Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py	Thu Sep 21 18:53:47 2006
@@ -485,7 +485,7 @@
     jitstate.frame = myframe.backframe
     return jitstate
 
-def leave_graph_void(jitstate):
+def leave_graph_gray(jitstate):
     jitstate = merge_returning_jitstates(jitstate)
     myframe = jitstate.frame
     jitstate.frame = myframe.backframe

Modified: pypy/dist/pypy/jit/timeshifter/rtyper.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtyper.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtyper.py	Thu Sep 21 18:53:47 2006
@@ -142,20 +142,20 @@
         Driver for running the timeshifter.
         """
         self.type_system.perform_normalizations(self)
-        graphs = self.annotator.translator.graphs
+        self.annotator.bookkeeper.compute_after_normalization()
+        entrygraph = self.annotator.translator.graphs[0]
+        pending = [entrygraph]
+        seen = {entrygraph: True}
+        while pending:
+            graph = pending.pop()
+            for nextgraph in self.transform_graph(graph):
+                if nextgraph not in seen:
+                    pending.append(nextgraph)
+                    seen[nextgraph] = True
         if view:
-            for graph in graphs:
-                self.transform_graph(graph)
             self.annotator.translator.view()     # in the middle
-            for graph in graphs:
-                self.timeshift_graph(graph)
-
-        else:
-            # do the whole transformation graph-by-graph if there is no
-            # need to view the intermediate result
-            for graph in graphs:
-                self.transform_graph(graph)
-                self.timeshift_graph(graph)
+        for graph in seen:
+            self.timeshift_graph(graph)
 
     def transform_graph(self, graph):
         # prepare the graphs by inserting all bookkeeping/dispatching logic
@@ -164,6 +164,7 @@
         transformer = HintGraphTransformer(self.annotator, graph)
         transformer.transform()
         flowmodel.checkgraph(graph)    # for now
+        return transformer.tsgraphs_seen
 
     def timeshift_graph(self, graph):
         # specialize all blocks of this graph
@@ -232,66 +233,69 @@
             self.dispatchsubclasses[mergepointfamily] = subclass
             return subclass
 
-    def get_timeshifted_fnptr(self, graph, specialization_key):
-        bk = self.annotator.bookkeeper
-        tsgraph = bk.get_graph_by_key(graph, specialization_key)
+    def get_args_r(self, tsgraph):
         args_hs, hs_res = self.get_sig_hs(tsgraph)
-        args_r = [self.getrepr(hs_arg) for hs_arg in args_hs]
+        return [self.getrepr(hs_arg) for hs_arg in args_hs]
+
+    def gettscallable(self, tsgraph):
+        args_r = self.get_args_r(tsgraph)
         ARGS = [self.r_JITState.lowleveltype]
         ARGS += [r.lowleveltype for r in args_r]
         RESULT = self.r_JITState.lowleveltype
-        fnptr = lltype.functionptr(lltype.FuncType(ARGS, RESULT),
-                                   tsgraph.name,
-                                   graph=tsgraph,
-                                   _callable = graph.func)
-        return fnptr, args_r
-
-    def get_timeshift_mapper(self, FUNC, specialization_key, graphs):
-        key = FUNC, specialization_key
+        return lltype.functionptr(lltype.FuncType(ARGS, RESULT),
+                                  tsgraph.name,
+                                  graph=tsgraph)
+
+    def get_timeshift_mapper(self, graph2ts):
+        # XXX try to share the results between "similar enough" graph2ts'es
+        key = graph2ts.items()
+        key.sort()
+        key = tuple(key)
         try:
-            timeshift_mapper, values, keys = self.timeshift_mapping[key]
+            return self.timeshift_mapping[key]
         except KeyError:
-            values = []
-            keys = []
-            fnptrmap = {}
-
-            def getter(fnptrmap, fnptr):
-                # indirection needed to defeat the flow object space
-                return fnptrmap[llmemory.cast_ptr_to_adr(fnptr)]
-
-            def fill_dict(fnptrmap, values, keys):
-                for i in range(len(values)):
-                    fnptrmap[llmemory.cast_ptr_to_adr(keys[i])] = values[i]
-
-            def timeshift_mapper(fnptr):
-                try:
-                    return getter(fnptrmap, fnptr)
-                except KeyError:
-                    fill_dict(fnptrmap, values, keys)
-                    return getter(fnptrmap, fnptr)   # try again
-
-            self.timeshift_mapping[key] = timeshift_mapper, values, keys
+            pass
 
         bk = self.annotator.bookkeeper
+        keys = []
+        values = []
         common_args_r = None
         COMMON_TS_FUNC = None
-        tsgraphs = []
-        for graph in graphs:
-            fnptr = self.rtyper.getcallable(graph)
-            ts_fnptr, args_r = self.get_timeshifted_fnptr(graph,
-                                                          specialization_key)
-            tsgraphs.append(ts_fnptr._obj.graph)
-            TS_FUNC = lltype.typeOf(ts_fnptr)
+        for graph, tsgraph in graph2ts.items():
+            fnptr    = self.rtyper.getcallable(graph)
+            ts_fnptr = self.gettscallable(tsgraph)
+            args_r   = self.get_args_r(tsgraph)
+            TS_FUNC  = lltype.typeOf(ts_fnptr)
             if common_args_r is None:
                 common_args_r = args_r
                 COMMON_TS_FUNC = TS_FUNC
             else:
-                # XXX for now
+                # should be ensured by normalization
                 assert COMMON_TS_FUNC == TS_FUNC
                 assert common_args_r == args_r
             keys.append(fnptr)
             values.append(ts_fnptr)
-        return timeshift_mapper, COMMON_TS_FUNC, common_args_r, tsgraphs
+
+        fnptrmap = {}
+
+        def getter(fnptrmap, fnptr):
+            # indirection needed to defeat the flow object space
+            return fnptrmap[llmemory.cast_ptr_to_adr(fnptr)]
+
+        def fill_dict(fnptrmap, values, keys):
+            for i in range(len(values)):
+                fnptrmap[llmemory.cast_ptr_to_adr(keys[i])] = values[i]
+
+        def timeshift_mapper(fnptr):
+            try:
+                return getter(fnptrmap, fnptr)
+            except KeyError:
+                fill_dict(fnptrmap, values, keys)
+                return getter(fnptrmap, fnptr)   # try again
+
+        result = timeshift_mapper, COMMON_TS_FUNC, common_args_r
+        self.timeshift_mapping[key] = result
+        return result
 
     def insert_v_jitstate_everywhere(self, graph):
         from pypy.translator.unsimplify import varoftype
@@ -589,9 +593,9 @@
                                                   self.s_JITState)
         hop.llops.setjitstate(v_newjs)
 
-    def translate_op_leave_graph_void(self, hop):
+    def translate_op_leave_graph_gray(self, hop):
         v_jitstate = hop.llops.getjitstate()
-        v_newjs = hop.llops.genmixlevelhelpercall(rtimeshift.leave_graph_void,
+        v_newjs = hop.llops.genmixlevelhelpercall(rtimeshift.leave_graph_gray,
                                                   [self.s_JITState],
                                                   [v_jitstate     ],
                                                   self.s_JITState)
@@ -840,49 +844,40 @@
     def translate_op_red_call(self, hop):
         bk = self.annotator.bookkeeper
         v_jitstate = hop.llops.getjitstate()
-        c_func = hop.args_v[0]
-        fnobj = c_func.value._obj
+        tsgraph = hop.args_v[0].value
         hop.r_s_popfirstarg()
-        args_hs = hop.args_s[:]
-        # fixed is always false here
-        specialization_key = bk.specialization_key(False, args_hs)
-        fnptr, args_r = self.get_timeshifted_fnptr(fnobj.graph,
-                                                   specialization_key)
-        args_v = hop.inputargs(*args_r)
+        args_v = hop.inputargs(*self.get_args_r(tsgraph))
+        fnptr = self.gettscallable(tsgraph)
         args_v[:0] = [hop.llops.genconst(fnptr), v_jitstate]
         RESULT = lltype.typeOf(fnptr).TO.RESULT
         v_newjitstate = hop.genop('direct_call', args_v, RESULT)
         hop.llops.setjitstate(v_newjitstate)
 
-    translate_op_yellow_call = translate_op_red_call
-
-    def translate_op_red_indirect_call(self, hop):
+    def translate_op_indirect_red_call(self, hop):
         bk = self.annotator.bookkeeper
         v_jitstate = hop.llops.getjitstate()
-
         FUNC = originalconcretetype(hop.args_s[0])
         v_func = hop.inputarg(self.getgreenrepr(FUNC), arg=0)
-        graph_list = hop.args_v[-1].value
+        graph2ts = hop.args_v[-1].value
         hop.r_s_pop(0)
         hop.r_s_pop()
-        args_hs = hop.args_s[:]
-        # fixed is always false here
-        specialization_key = bk.specialization_key(False, args_hs)
-
-        mapper, TS_FUNC, args_r, tsgraphs = self.get_timeshift_mapper(
-            FUNC, specialization_key, graph_list)
-        args_v = hop.inputargs(*args_r)
-
+        mapper, TS_FUNC, args_r = self.get_timeshift_mapper(graph2ts)
         v_tsfunc = hop.llops.genmixlevelhelpercall(mapper,
                                                    [annmodel.SomePtr(FUNC)],
                                                    [v_func                ],
                                                    annmodel.SomePtr(TS_FUNC))
-        args_v[:0] = [v_tsfunc, v_jitstate]
+        args_v = [v_tsfunc, v_jitstate] + hop.inputargs(*args_r)
         RESULT = v_tsfunc.concretetype.TO.RESULT
-        args_v.append(hop.inputconst(lltype.Void, tsgraphs))
+        args_v.append(hop.inputconst(lltype.Void, graph2ts.values()))
         v_newjitstate = hop.genop('indirect_call', args_v, RESULT)
         hop.llops.setjitstate(v_newjitstate)
 
+    translate_op_gray_call            = translate_op_red_call
+    translate_op_indirect_gray_call   = translate_op_indirect_red_call
+
+    translate_op_yellow_call          = translate_op_red_call
+    translate_op_indirect_yellow_call = translate_op_indirect_red_call
+
 
 class HintLowLevelOpList(LowLevelOpList):
     """Warning: the HintLowLevelOpList's rtyper is the *original*

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	Thu Sep 21 18:53:47 2006
@@ -971,4 +971,38 @@
 
         res = self.timeshift(f, [True, 40], [0])
         assert res == -17
-        self.check_insns()
+        self.check_insns({})
+
+    def test_normalize_indirect_call_more(self):
+        def g1(v):
+            if v >= 0:
+                return -17
+            else:
+                return -155
+
+        def g2(v):
+            return v + 2
+
+        def f(flag, v):
+            w = g1(v)
+            if hint(flag, concrete=True):
+                g = g1
+            else:
+                g = g2
+            return g(v) + w
+
+        res = self.timeshift(f, [False, 40], [0])
+        assert res == 25
+        self.check_insns({'int_add': 2, 'int_ge': 1})
+
+        res = self.timeshift(f, [True, 40], [0])
+        assert res == -34
+        self.check_insns({'int_ge': 2, 'int_add': 1})
+
+        res = self.timeshift(f, [False, -1000], [0])
+        assert res == f(False, -1000)
+        self.check_insns({'int_add': 2, 'int_ge': 1})
+
+        res = self.timeshift(f, [True, -1000], [0])
+        assert res == f(True, -1000)
+        self.check_insns({'int_ge': 2, 'int_add': 1})

Modified: pypy/dist/pypy/jit/timeshifter/transform.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/transform.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/transform.py	Thu Sep 21 18:53:47 2006
@@ -28,9 +28,11 @@
     def __init__(self, hannotator, graph):
         self.hannotator = hannotator
         self.graph = graph
+        self.graphcolor = self.graph_calling_color(graph)
         self.resumepoints = {}
         self.mergepointfamily = MergePointFamily()
         self.c_mpfamily = inputconst(lltype.Void, self.mergepointfamily)
+        self.tsgraphs_seen = []
 
     def transform(self):
         mergepoints = list(self.enumerate_merge_points())
@@ -49,6 +51,24 @@
             if len(links) > 1 and block is not self.graph.returnblock:
                 yield block
 
+    def graph_calling_color(self, tsgraph):
+        args_hs, hs_res = self.hannotator.bookkeeper.tsgraphsigs[tsgraph]
+        if originalconcretetype(hs_res) is lltype.Void:
+            return 'gray'
+        elif hs_res.is_green():
+            return 'yellow'
+        else:
+            return 'red'
+
+    def timeshifted_graph_of(self, graph, args_v):
+        bk = self.hannotator.bookkeeper
+        args_hs = [self.hannotator.binding(v) for v in args_v]
+        # fixed is always false here
+        specialization_key = bk.specialization_key(False, args_hs)
+        tsgraph = bk.get_graph_by_key(graph, specialization_key)
+        self.tsgraphs_seen.append(tsgraph)
+        return tsgraph
+
     # __________ helpers __________
 
     def genop(self, block, opname, args, result_type=None, result_like=None):
@@ -114,11 +134,13 @@
                 used[v] = True
         return [v for v in used if v in created_before]
 
-    def sort_by_color(self, vars):
+    def sort_by_color(self, vars, by_color_of_vars=None):
         reds = []
         greens = []
-        for v in vars:
-            if self.hannotator.binding(v).is_green():
+        if by_color_of_vars is None:
+            by_color_of_vars = vars
+        for v, bcv in zip(vars, by_color_of_vars):
+            if self.hannotator.binding(bcv).is_green():
                 greens.append(v)
             else:
                 reds.append(v)
@@ -169,7 +191,7 @@
         constant_block.exitswitch = v_greenswitch
         constant_block.closeblock(link_f, link_t)
 
-        reds, greens = self.sort_by_color(link_f.args)
+        reds, greens = self.sort_by_color(link_f.args, link_f.target.inputargs)
         self.genop(nonconstant_block, 'save_locals', reds)
         resumepoint = self.get_resume_point(link_f.target)
         c_resumepoint = inputconst(lltype.Signed, resumepoint)
@@ -262,16 +284,15 @@
     def insert_save_return(self):
         block = self.before_return_block()
         [v_retbox] = block.inputargs
-        hs_retbox = self.hannotator.binding(v_retbox)
-        if originalconcretetype(hs_retbox) is lltype.Void:
-            self.leave_graph_opname = 'leave_graph_void'
+        if self.graphcolor == 'gray':
             self.genop(block, 'save_locals', [])
-        elif hs_retbox.is_green():
-            self.leave_graph_opname = 'leave_graph_yellow'
+        elif self.graphcolor == 'yellow':
             self.genop(block, 'save_greens', [v_retbox])
-        else:
+        elif self.graphcolor == 'red':
             self.leave_graph_opname = 'leave_graph_red'
             self.genop(block, 'save_locals', [v_retbox])
+        else:
+            raise AssertionError(self.graph, self.graphcolor)
         self.genop(block, 'save_return', [])
 
     def insert_enter_graph(self):
@@ -284,28 +305,47 @@
 
     def insert_leave_graph(self):
         block = self.before_return_block()
-        self.genop(block, self.leave_graph_opname, [])
+        self.genop(block, 'leave_graph_%s' % (self.graphcolor,), [])
 
     # __________ handling of the various kinds of calls __________
 
+    def graphs_from(self, spaceop):
+        if spaceop.opname == 'direct_call':
+            c_func = spaceop.args[0]
+            fnobj = c_func.value._obj
+            graphs = [fnobj.graph]
+            args_v = spaceop.args[1:]
+        elif spaceop.opname == 'indirect_call':
+            graphs = spaceop.args[-1].value
+            args_v = spaceop.args[1:-1]
+        else:
+            raise AssertionError(spaceop.opname)
+        for graph in graphs:
+            tsgraph = self.timeshifted_graph_of(graph, args_v)
+            yield graph, tsgraph
+
     def guess_call_kind(self, spaceop):
-        if spaceop.opname == 'indirect_call':
-            return 'red'  # for now
-        assert spaceop.opname == 'direct_call'
-        c_func = spaceop.args[0]
-        fnobj = c_func.value._obj
-        s_result = self.hannotator.binding(spaceop.result)
-        if hasattr(fnobj._callable, 'oopspec'):
-            return 'oopspec'
-        elif (originalconcretetype(s_result) is not lltype.Void and
-              s_result.is_green()):
-            for v in spaceop.args:
-                s_arg = self.hannotator.binding(v)
-                if not s_arg.is_green():
-                    return 'yellow'
-            return 'green'
+        if spaceop.opname == 'direct_call':
+            c_func = spaceop.args[0]
+            fnobj = c_func.value._obj
+            if hasattr(fnobj._callable, 'oopspec'):
+                return 'oopspec'
+
+        for v in spaceop.args:
+            hs_arg = self.hannotator.binding(v)
+            if not hs_arg.is_green():
+                break
         else:
-            return 'red'
+            hs_res = self.hannotator.binding(spaceop.result)
+            if hs_res.is_green():
+                # all-green arguments and result
+                return 'green'
+        colors = {}
+        for graph, tsgraph in self.graphs_from(spaceop):
+            color = self.graph_calling_color(tsgraph)
+            colors[color] = tsgraph
+        assert len(colors) == 1, colors   # buggy normalization?
+        return color
 
     def split_after_calls(self):
         for block in list(self.graph.iterblocks()):
@@ -316,7 +356,21 @@
                     handler = getattr(self, 'handle_%s_call' % (call_kind,))
                     handler(block, i)
 
-    def handle_red_call(self, block, pos):
+    def make_call(self, block, op, save_locals_vars, color='red'):
+        self.genop(block, 'save_locals', save_locals_vars)
+        targets = dict(self.graphs_from(op))
+        if len(targets) == 1:
+            [tsgraph] = targets.values()
+            c_tsgraph = inputconst(lltype.Void, tsgraph)
+            self.genop(block, '%s_call' % (color,), [c_tsgraph] + op.args[1:])
+            # Void result, because the call doesn't return its redbox result,
+            # but only has the hidden side-effect of putting it in the jitstate
+        else:
+            c_targets = inputconst(lltype.Void, targets)
+            self.genop(block, 'indirect_%s_call' % (color,),
+                       op.args[:-1] + [c_targets])
+
+    def handle_red_call(self, block, pos, color='red'):
         # the 'save_locals' pseudo-operation is used to save all
         # alive local variables into the current JITState
         beforeops = block.operations[:pos]
@@ -331,14 +385,9 @@
             uses_retval = False
         reds, greens = self.sort_by_color(varsalive)
 
-        newopname = {'direct_call'  : 'red_call',
-                     'indirect_call': 'red_indirect_call'}[op.opname]
-
         newops = []
-        self.genop(newops, 'save_locals', reds)
-        self.genop(newops, newopname, op.args)    # Void result,
-        # because the call doesn't return its redbox result, but only
-        # has the hidden side-effect of putting it in the jitstate
+        self.make_call(newops, op, reds, color)
+
         mapping = {}
         for i, var in enumerate(reds):
             c_index = Constant(i, concretetype=lltype.Signed)
@@ -346,7 +395,8 @@
                                 result_like = var)
             mapping[var] = newvar
 
-        if uses_retval and not self.hannotator.binding(op.result).is_green():
+        if uses_retval:
+            assert not self.hannotator.binding(op.result).is_green()
             var = op.result
             newvar = self.genop(newops, 'fetch_return', [],
                                 result_like = var)
@@ -359,6 +409,9 @@
         block.inputargs = saved
         block.operations[:0] = beforeops + newops
 
+    def handle_gray_call(self, block, pos):
+        self.handle_red_call(block, pos, color='gray')
+
     def handle_oopspec_call(self, block, pos):
         op = block.operations[pos]
         assert op.opname == 'direct_call'
@@ -388,8 +441,7 @@
         nextblock.inputargs.insert(0, v_result)
 
         reds, greens = self.sort_by_color(varsalive)
-        self.genop(block, 'save_locals', reds)
-        self.genop(block, 'yellow_call', op.args)  # Void result, like red_call
+        self.make_call(block, op, reds, 'yellow')
 
         resumepoint = self.get_resume_point(nextblock)
         c_resumepoint = inputconst(lltype.Signed, resumepoint)



More information about the Pypy-commit mailing list