[pypy-commit] pypy guard-compatible: try to implement the backend/guard_compatible interface

cfbolz pypy.commits at gmail.com
Fri May 20 06:03:01 EDT 2016


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: guard-compatible
Changeset: r84524:b4c9f5681460
Date: 2016-05-20 12:01 +0200
http://bitbucket.org/pypy/pypy/changeset/b4c9f5681460/

Log:	try to implement the backend/guard_compatible interface

	(needs new code in the graph viewer, because of the different ways
	that bridges can be attached now).

diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -24,6 +24,7 @@
     def __init__(self, lltrace):
         self.ops_offset = None
         self.lltrace = lltrace
+        self.asmaddr = lltrace
 
 class LLTrace(object):
     has_been_freed = False
@@ -356,10 +357,13 @@
 
     def compile_bridge(self, faildescr, inputargs, operations,
                        original_loop_token, log=True, logger=None):
+        from rpython.jit.metainterp.compile import GuardCompatibleDescr
         clt = original_loop_token.compiled_loop_token
         clt.compiling_a_bridge()
         lltrace = LLTrace(inputargs, operations)
-        faildescr._llgraph_bridge = lltrace
+        if not isinstance(faildescr, GuardCompatibleDescr):
+            # don't patch GuardCompatibleDescr
+            faildescr._llgraph_bridge = lltrace
         clt._llgraph_alltraces.append(lltrace)
         self._record_labels(lltrace)
         return LLAsmInfo(lltrace)
@@ -470,12 +474,6 @@
         assert deadframe._saved_data is not None
         return deadframe._saved_data
 
-    def grow_guard_compatible_switch(self, compiled_loop_token, descr, ref):
-        assert isinstance(compiled_loop_token, model.CompiledLoopToken)
-        if not hasattr(descr, '_guard_compatible_llgraph_lst'):
-            descr._guard_compatible_llgraph_lst = []
-        descr._guard_compatible_llgraph_lst.append(ref)
-
 
     # ------------------------------------------------------------
 
@@ -1292,9 +1290,19 @@
         if arg1 != arg2:
             if hasattr(descr, '_guard_compatible_llgraph_lst'):
                 lst = descr._guard_compatible_llgraph_lst
-                for ref in lst:
+                for ref, target in lst:
                     if ref == arg1:
-                        return
+                        if target == -1:
+                            return
+                        XXX
+            else:
+                descr._guard_compatible_llgraph_lst = []
+            target = descr.find_compatible(self.cpu, arg1)
+            if target:
+                descr._guard_compatible_llgraph_lst.append((arg1, target))
+                if target == -1:
+                    return
+                XXX
             self.fail_guard(descr, extra_value=arg1)
 
     def execute_int_add_ovf(self, _, x, y):
diff --git a/rpython/jit/metainterp/compatible.py b/rpython/jit/metainterp/compatible.py
--- a/rpython/jit/metainterp/compatible.py
+++ b/rpython/jit/metainterp/compatible.py
@@ -30,6 +30,8 @@
         self.known_valid = ptr
         self.conditions = []
         self.last_quasi_immut_field_op = None
+        # -1 means "stay on the original trace"
+        self.jump_target = -1
 
     def record_condition(self, cond, res, optimizer):
         for oldcond in self.conditions:
@@ -43,7 +45,7 @@
     def register_quasi_immut_field(self, op):
         self.last_quasi_immut_field_op = op
 
-    def check_compat(self, cpu, ref, loop_token):
+    def check_compat_and_activate(self, cpu, ref, loop_token):
         for cond in self.conditions:
             if not cond.check(cpu, ref):
                 return False
diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -797,13 +797,14 @@
         new_loop.original_jitcell_token = metainterp.resumekey_original_loop_token
         inputargs = new_loop.inputargs
         if not we_are_translated():
-            self._debug_subinputargs = new_loop.inputargs
-            self._debug_suboperations = new_loop.operations
+            if not hasattr(self, "_debug_bridges"):
+                self._debug_bridges = []
+            self._debug_bridges.append((new_loop.inputargs, new_loop.operations))
         propagate_original_jitcell_token(new_loop)
-        send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata,
-                               self, inputargs, new_loop.operations,
-                               new_loop.original_jitcell_token,
-                               metainterp.box_names_memo)
+        return send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata,
+                                      self, inputargs, new_loop.operations,
+                                      new_loop.original_jitcell_token,
+                                      metainterp.box_names_memo)
 
     def make_a_counter_per_value(self, guard_value_op, index):
         assert guard_value_op.getopnum() in (rop.GUARD_VALUE, rop.GUARD_COMPATIBLE)
@@ -1084,37 +1085,27 @@
         # XXX think about what is being kept alive here
         self._compatibility_conditions = None
         self.failarg_index = -1
-        # list of descrs about the same variable, potentially shared with
-        # subsequent guards in bridges
-        self.guard_descrs_list = [self]
+        # list of compatibility conditions about the same variable, with
+        # bridges attached to them
+        self.other_compat_conditions = []
 
-    def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
-        index = intmask(self.status >> self.ST_SHIFT)
-        typetag = intmask(self.status & self.ST_TYPE_MASK)
-        assert typetag == self.TY_REF # for now
-        refval = metainterp_sd.cpu.get_value_direct(deadframe, 'r', index)
-        if not we_are_translated():
-            assert self in self.guard_descrs_list
+    def find_compatible(self, cpu, ref):
+        """ callback for the CPU: given a value ref, it returns:
+            -1 to stay on the trace
+            0 to say that there isn't one
+            the address of the compatible bridge to jump to
+        """
         # need to do the checking oldest to newest, to check the most specific
         # condition first
-        for curr in self.guard_descrs_list:
-            if curr.is_compatible(metainterp_sd.cpu, refval):
-                from rpython.jit.metainterp.blackhole import resume_in_blackhole
-                metainterp_sd.cpu.grow_guard_compatible_switch(
-                    curr.rd_loop_token, curr, refval)
-                resume_in_blackhole(metainterp_sd, jitdriver_sd, self, deadframe)
-                return
-        # a real failure
-        return ResumeGuardDescr.handle_fail(self, deadframe, metainterp_sd, jitdriver_sd)
-
-    def is_compatible(self, cpu, ref):
-        const = history.newconst(ref)
         if self._compatibility_conditions:
-            if self._compatibility_conditions.check_compat(
+            if self._compatibility_conditions.check_compat_and_activate(
                     cpu, ref, self.rd_loop_token):
-                return True
-            return False
-        return True # no conditions, everything works
+                return self._compatibility_conditions.jump_target
+        for _compatibility_conditions in self.other_compat_conditions:
+            if _compatibility_conditions.check_compat_and_activate(
+                    cpu, ref, self.rd_loop_token):
+                return self._compatibility_conditions.jump_target
+        return 0
 
     def compile_and_attach(self, metainterp, new_loop, orig_inputargs):
         # if new_loop starts with another guard_compatible on the same argument
@@ -1123,15 +1114,21 @@
         assert self.failarg_index != -1
         arg = new_loop.inputargs[self.failarg_index]
         firstop = new_loop.operations[0]
+        compat_cond = None
         if (firstop.getopnum() == rop.GUARD_COMPATIBLE and
                 firstop.getarg(0) is arg):
             # a guard_compatible about the same box
+            # remove it, it doesn't have to be checked in the bridge
+            del new_loop.operations[0]
             newdescr = firstop.getdescr()
             assert isinstance(newdescr, GuardCompatibleDescr)
-            newdescr.guard_descrs_list = self.guard_descrs_list
-            self.guard_descrs_list.append(newdescr)
-        ResumeGuardDescr.compile_and_attach(
+            compat_cond = newdescr._compatibility_conditions
+            self.other_compat_conditions.append(compat_cond)
+        asminfo = ResumeGuardDescr.compile_and_attach(
             self, metainterp, new_loop, orig_inputargs)
+        if compat_cond:
+            compat_cond.jump_target = asminfo.asmaddr
+        return asminfo
 
     def make_a_counter_per_value(self, guard_value_op, index):
         self.failarg_index = guard_value_op.getfailargs().index(
diff --git a/rpython/jit/metainterp/graphpage.py b/rpython/jit/metainterp/graphpage.py
--- a/rpython/jit/metainterp/graphpage.py
+++ b/rpython/jit/metainterp/graphpage.py
@@ -4,10 +4,10 @@
 from rpython.jit.metainterp.resoperation import rop
 
 class SubGraph:
-    def __init__(self, op):
+    def __init__(self, op, inputargs, suboperations):
         self.failargs = op.getfailargs()
-        self.subinputargs = op.getdescr()._debug_subinputargs
-        self.suboperations = op.getdescr()._debug_suboperations
+        self.subinputargs = inputargs
+        self.suboperations = suboperations
     def get_operations(self):
         return self.suboperations
     def get_display_text(self, memo):
@@ -26,13 +26,14 @@
               for procedure in procedures]
     for graph, highlight in graphs:
         for op in graph.get_operations():
-            if is_interesting_guard(op):
-                graphs.append((SubGraph(op), highlight))
+            bridges = getattr(op.getdescr(), '_debug_bridges', [])
+            for inputargs, suboperations in bridges:
+                graphs.append((SubGraph(op, inputargs, suboperations), highlight))
     graphpage = ResOpGraphPage(graphs, errmsg, metainterp_sd)
     graphpage.display()
 
 def is_interesting_guard(op):
-    return hasattr(op.getdescr(), '_debug_suboperations')
+    return hasattr(op.getdescr(), '_debug_bridges')
 
 def getdescr(op):
     if op._descr is not None:
@@ -178,8 +179,9 @@
                     s = s.replace(',', '.') # we use comma for argument splitting
                     op_repr = "debug_merge_point(%d, %d, '%s')" % (op.getarg(1).getint(), op.getarg(2).getint(), s)
             lines.append(op_repr)
-            if is_interesting_guard(op):
-                tgt = op.getdescr()._debug_suboperations[0]
+            bridges = getattr(op.getdescr(), '_debug_bridges', [])
+            for inputargs, suboperations in bridges:
+                tgt = suboperations[0]
                 tgt_g, tgt_i = self.all_operations[tgt]
                 self.genedge((graphindex, opstartindex),
                              (tgt_g, tgt_i),
diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py
--- a/rpython/jit/metainterp/history.py
+++ b/rpython/jit/metainterp/history.py
@@ -548,9 +548,9 @@
                     assert box in seen
             if op.is_guard() and check_descr:
                 assert op.getdescr() is not None
-                if hasattr(op.getdescr(), '_debug_suboperations'):
-                    ops = op.getdescr()._debug_suboperations
-                    TreeLoop.check_consistency_of_branch(ops, seen.copy())
+                if hasattr(op.getdescr(), '_debug_bridges'):
+                    for _, ops in op.getdescr()._debug_bridges:
+                        TreeLoop.check_consistency_of_branch(ops, seen.copy())
                 for box in op.getfailargs() or []:
                     if box is not None:
                         assert not isinstance(box, Const)
@@ -600,9 +600,9 @@
     result.extend(operations)
     for op in operations:
         if op.is_guard() and op.getdescr():
-            if hasattr(op.getdescr(), '_debug_suboperations'):
-                ops = op.getdescr()._debug_suboperations
-                _list_all_operations(result, ops, omit_finish)
+            if hasattr(op.getdescr(), '_debug_bridges'):
+                for _, ops in op.getdescr()._debug_bridges:
+                    _list_all_operations(result, ops, omit_finish)
 
 # ____________________________________________________________
 
diff --git a/rpython/jit/metainterp/test/test_compatible.py b/rpython/jit/metainterp/test/test_compatible.py
--- a/rpython/jit/metainterp/test/test_compatible.py
+++ b/rpython/jit/metainterp/test/test_compatible.py
@@ -41,7 +41,7 @@
 
         x = self.meta_interp(main, [])
 
-        assert x < 25
+        assert x < 30
         # trace, two bridges, a finish bridge
         self.check_trace_count(4)
 


More information about the pypy-commit mailing list