[pypy-commit] pypy jit-targets: support for bridges in progress

hakanardo noreply at buildbot.pypy.org
Sun Nov 6 10:46:22 CET 2011


Author: Hakan Ardo <hakan at debian.org>
Branch: jit-targets
Changeset: r48811:5e84c483e93d
Date: 2011-11-06 09:15 +0100
http://bitbucket.org/pypy/pypy/changeset/5e84c483e93d/

Log:	support for bridges in progress

diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -119,12 +119,14 @@
     except InvalidLoop:
         return None
     loop.operations = part.operations
+    all_target_tokens = [part.operations[0].getdescr()]
     while part.operations[-1].getopnum() == rop.LABEL:
         inliner = Inliner(inputargs, jumpargs)
         part.operations = [part.operations[-1]] + \
                           [inliner.inline_op(h_ops[i]) for i in range(start, len(h_ops))] + \
                           [ResOperation(rop.LABEL, [inliner.inline_arg(a) for a in jumpargs],
                                         None, descr=TargetToken(procedure_token))]
+        all_target_tokens.append(part.operations[0].getdescr())
         inputargs = jumpargs
         jumpargs = part.operations[-1].getarglist()
 
@@ -139,7 +141,7 @@
         assert isinstance(box, Box)
 
     loop.token = procedure_token
-
+    procedure_token.target_tokens = all_target_tokens
     send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop")
     record_loop_or_bridge(metainterp_sd, loop)
     return procedure_token
@@ -206,10 +208,6 @@
     metainterp_sd.log("compiled new " + type)
     #
     metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n, type, ops_offset)
-    short = loop.token.short_preamble
-    if short:
-        metainterp_sd.logger_ops.log_short_preamble(short[-1].inputargs,
-                                                    short[-1].operations)
     #
     if metainterp_sd.warmrunnerdesc is not None:    # for tests
         metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(loop.token)
@@ -221,7 +219,8 @@
                                    original_loop_token, operations, n)
     if not we_are_translated():
         show_loop(metainterp_sd)
-        TreeLoop.check_consistency_of(inputargs, operations)
+        seen = dict.fromkeys(inputargs)
+        TreeLoop.check_consistency_of_branch(operations, seen)
     metainterp_sd.profiler.start_backend()
     operations = get_deep_immutable_oplist(operations)
     debug_start("jit-backend")
@@ -596,7 +595,6 @@
 class ResumeFromInterpDescr(ResumeDescr):
     def __init__(self, original_greenkey):
         self.original_greenkey = original_greenkey
-        self.procedure_token = ProcedureToken()
 
     def compile_and_attach(self, metainterp, new_loop):
         # We managed to create a bridge going from the interpreter
@@ -606,13 +604,13 @@
         metainterp_sd = metainterp.staticdata
         jitdriver_sd = metainterp.jitdriver_sd
         redargs = new_loop.inputargs
-        self.procedure_token.outermost_jitdriver_sd = jitdriver_sd
-        new_loop.token = self.procedure_token
+        procedure_token = make_procedure_token(jitdriver_sd)
+        new_loop.token = procedure_token
         send_loop_to_backend(self.original_greenkey, metainterp.jitdriver_sd,
                              metainterp_sd, new_loop, "entry bridge")
         # send the new_loop to warmspot.py, to be called directly the next time
         jitdriver_sd.warmstate.attach_procedure_to_interp(
-            self.original_greenkey, self.procedure_token)
+            self.original_greenkey, procedure_token)
 
     def reset_counter_from_failure(self):
         pass
@@ -626,15 +624,17 @@
     
     # The history contains new operations to attach as the code for the
     # failure of 'resumekey.guard_op'.
-    #
+    # 
     # Attempt to use optimize_bridge().  This may return None in case
     # it does not work -- i.e. none of the existing old_loop_tokens match.
     new_loop = create_empty_loop(metainterp)
     new_loop.inputargs = inputargs = metainterp.history.inputargs[:]
     # clone ops, as optimize_bridge can mutate the ops
-    procedure_token = resumekey.procedure_token
-    new_loop.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(procedure_token))] + \
-                          [op.clone() for op in metainterp.history.operations]
+
+    # A LABEL with descr=None will be killed by optimizer. Its only use
+    # is to pass along the inputargs to the optimizer
+    #[ResOperation(rop.LABEL, inputargs, None, descr=None)] + \
+    new_loop.operations = [op.clone() for op in metainterp.history.operations]
     metainterp_sd = metainterp.staticdata
     state = metainterp.jitdriver_sd.warmstate
     if isinstance(resumekey, ResumeAtPositionDescr):
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -734,7 +734,7 @@
     was compiled; but the LoopDescr remains alive and points to the
     generated assembler.
     """
-    short_preamble = None
+    target_tokens = None
     failed_states = None
     retraced_count = 0
     terminating = False # see TerminatingLoopToken in compile.py
diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py
--- a/pypy/jit/metainterp/optimizeopt/__init__.py
+++ b/pypy/jit/metainterp/optimizeopt/__init__.py
@@ -85,7 +85,7 @@
     """Optimize loop.operations to remove internal overheadish operations.
     """
 
-    optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, False, False)
+    optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts, True, False)
     if unroll:
         optimize_unroll(metainterp_sd, loop, optimizations)
     else:
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -65,46 +65,56 @@
             
     def propagate_all_forward(self):
         loop = self.optimizer.loop
-        start_targetop = loop.operations[0]
-        assert start_targetop.getopnum() == rop.LABEL
-        loop.operations = loop.operations[1:]
         self.optimizer.clear_newoperations()
-        self.optimizer.send_extra_operation(start_targetop)
+
+        import pdb; pdb.set_trace()
+
+        start_label = loop.operations[0]
+        if start_label.getopnum() == rop.LABEL:
+            loop.operations = loop.operations[1:]
+            # We need to emit the label op before import_state() as emitting it
+            # will clear heap caches
+            self.optimizer.send_extra_operation(start_label)
+        else:
+            start_label = None            
         
-        self.import_state(start_targetop)
-        
-        lastop = loop.operations[-1]
-        if lastop.getopnum() == rop.LABEL:
+        stop_label = loop.operations[-1]
+        if stop_label.getopnum() == rop.LABEL:
             loop.operations = loop.operations[:-1]
         else:
-            lastop = None
-        
+            stop_label = None
+
+        self.import_state(start_label)
         self.optimizer.propagate_all_forward(clear=False)
 
-        if not lastop:
+        if not stop_label:
             self.optimizer.flush()
             loop.operations = self.optimizer.get_newoperations()
-            return
-        
-        if not self.did_peel_one: # Enforce the previous behaviour of always peeling  exactly one iteration (for now)
+        elif not start_label:
+            #jumpop = ResOperation(rop.JUMP, stop_label.getarglist(), None, descr=stop_label.getdescr())
+            self.optimizer.send_extra_operation(stop_label)
+            self.optimizer.flush()
+            loop.operations = self.optimizer.get_newoperations()
+        elif not self.did_peel_one: # Enforce the previous behaviour of always peeling  exactly one iteration (for now)
             self.optimizer.flush()
             KillHugeIntBounds(self.optimizer).apply()
 
             loop.operations = self.optimizer.get_newoperations()
-            self.export_state(lastop)
-            loop.operations.append(lastop)
+            self.export_state(stop_label)
+            loop.operations.append(stop_label)
         else:
-            assert lastop.getdescr().procedure_token is start_targetop.getdescr().procedure_token
-            jumpop = ResOperation(rop.JUMP, lastop.getarglist(), None, descr=start_targetop.getdescr())
+            assert stop_label.getdescr().procedure_token is start_label.getdescr().procedure_token
+            jumpop = ResOperation(rop.JUMP, stop_label.getarglist(), None, descr=start_label.getdescr())
 
             self.close_loop(jumpop)
-            self.finilize_short_preamble(lastop)
-            start_targetop.getdescr().short_preamble = self.short
+            self.finilize_short_preamble(start_label)
+            start_label.getdescr().short_preamble = self.short
 
     def export_state(self, targetop):
         original_jump_args = targetop.getarglist()
         jump_args = [self.getvalue(a).get_key_box() for a in original_jump_args]
 
+        # FIXME: I dont thnik we need this anymore
         start_resumedescr = self.optimizer.loop.start_resumedescr.clone_if_mutable()
         assert isinstance(start_resumedescr, ResumeGuardDescr)
         start_resumedescr.rd_snapshot = self.fix_snapshot(jump_args, start_resumedescr.rd_snapshot)
@@ -139,12 +149,17 @@
         targetop.initarglist(inputargs)
         target_token.virtual_state = virtual_state
         target_token.short_preamble = [ResOperation(rop.LABEL, short_inputargs, None)]
+        target_token.start_resumedescr = start_resumedescr
         target_token.exported_state = ExportedState(constant_inputargs, short_boxes,
-                                                    inputarg_setup_ops, self.optimizer,
-                                                    start_resumedescr)
+                                                    inputarg_setup_ops, self.optimizer)
 
     def import_state(self, targetop):
+        if not targetop:
+            # FIXME: Set up some sort of empty state with no virtuals?
+            return
         target_token = targetop.getdescr()
+        if not target_token:
+            return
         assert isinstance(target_token, TargetToken)
         exported_state = target_token.exported_state
         if not exported_state:
@@ -160,7 +175,6 @@
             self.short_seen[box] = True
         self.imported_state = exported_state
         self.inputargs = targetop.getarglist()
-        self.start_resumedescr = exported_state.start_resumedescr
         self.initial_virtual_state = target_token.virtual_state
 
         seen = {}
@@ -275,9 +289,11 @@
             raise InvalidLoop
         debug_stop('jit-log-virtualstate')
 
-    def finilize_short_preamble(self, lastop):
+    def finilize_short_preamble(self, start_label):
         short = self.short
         assert short[-1].getopnum() == rop.JUMP
+        target_token = start_label.getdescr()
+        assert isinstance(target_token, TargetToken)
 
         # Turn guards into conditional jumps to the preamble
         for i in range(len(short)):
@@ -285,7 +301,7 @@
             if op.is_guard():
                 op = op.clone()
                 op.setfailargs(None)
-                descr = self.start_resumedescr.clone_if_mutable()
+                descr = target_token.start_resumedescr.clone_if_mutable()
                 op.setdescr(descr)
                 short[i] = op
 
@@ -306,10 +322,8 @@
         for i in range(len(short)):
             short[i] = inliner.inline_op(short[i])
 
-        self.start_resumedescr = self.start_resumedescr.clone_if_mutable()
-        inliner.inline_descr_inplace(self.start_resumedescr)
-        #short_loop.start_resumedescr = descr
-        # FIXME: move this to targettoken
+        target_token.start_resumedescr = target_token.start_resumedescr.clone_if_mutable()
+        inliner.inline_descr_inplace(target_token.start_resumedescr)
 
         # Forget the values to allow them to be freed
         for box in short[0].getarglist():
@@ -422,66 +436,76 @@
 
     def propagate_forward(self, op):
         if op.getopnum() == rop.JUMP:
-            loop_token = op.getdescr()
-            if not isinstance(loop_token, TargetToken):
+            self.emit_operation(op)
+            return
+        elif op.getopnum() == rop.LABEL:
+            target_token = op.getdescr()
+            assert isinstance(target_token, TargetToken)
+            procedure_token = target_token.procedure_token
+            if not procedure_token.target_tokens:
                 self.emit_operation(op)
                 return
-            short = loop_token.short_preamble
-            if short:
-                args = op.getarglist()
-                modifier = VirtualStateAdder(self.optimizer)
-                virtual_state = modifier.get_virtual_state(args)
-                debug_start('jit-log-virtualstate')
-                virtual_state.debug_print("Looking for ")
 
-                for sh in short:
-                    ok = False
-                    extra_guards = []
+            args = op.getarglist()
+            modifier = VirtualStateAdder(self.optimizer)
+            virtual_state = modifier.get_virtual_state(args)
+            debug_start('jit-log-virtualstate')
+            virtual_state.debug_print("Looking for ")
 
-                    bad = {}
-                    debugmsg = 'Did not match '
-                    if sh.virtual_state.generalization_of(virtual_state, bad):
-                        ok = True
-                        debugmsg = 'Matched '
-                    else:
-                        try:
-                            cpu = self.optimizer.cpu
-                            sh.virtual_state.generate_guards(virtual_state,
+            for target in procedure_token.target_tokens:
+                if not target.virtual_state:
+                    continue
+                ok = False
+                extra_guards = []
+
+                bad = {}
+                debugmsg = 'Did not match '
+                if target.virtual_state.generalization_of(virtual_state, bad):
+                    ok = True
+                    debugmsg = 'Matched '
+                else:
+                    try:
+                        cpu = self.optimizer.cpu
+                        target.virtual_state.generate_guards(virtual_state,
                                                              args, cpu,
                                                              extra_guards)
 
-                            ok = True
-                            debugmsg = 'Guarded to match '
-                        except InvalidLoop:
-                            pass
-                    sh.virtual_state.debug_print(debugmsg, bad)
-                    
-                    if ok:
-                        debug_stop('jit-log-virtualstate')
+                        ok = True
+                        debugmsg = 'Guarded to match '
+                    except InvalidLoop:
+                        pass
+                target.virtual_state.debug_print(debugmsg, bad)
 
-                        values = [self.getvalue(arg)
-                                  for arg in op.getarglist()]
-                        args = sh.virtual_state.make_inputargs(values, self.optimizer,
+                if ok:
+                    debug_stop('jit-log-virtualstate')
+
+                    values = [self.getvalue(arg)
+                              for arg in op.getarglist()]
+                    args = target.virtual_state.make_inputargs(values, self.optimizer,
                                                                keyboxes=True)
-                        inliner = Inliner(sh.inputargs, args)
-                        
-                        for guard in extra_guards:
-                            if guard.is_guard():
-                                descr = sh.start_resumedescr.clone_if_mutable()
-                                inliner.inline_descr_inplace(descr)
-                                guard.setdescr(descr)
-                            self.emit_operation(guard)
-                        
-                        try:
-                            for shop in sh.operations:
-                                newop = inliner.inline_op(shop)
-                                self.emit_operation(newop)
-                        except InvalidLoop:
-                            debug_print("Inlining failed unexpectedly",
-                                        "jumping to preamble instead")
-                            self.emit_operation(op)
-                        return
-                debug_stop('jit-log-virtualstate')
+                    short_inputargs = target.short_preamble[0].getarglist()
+                    inliner = Inliner(short_inputargs, args)
+
+                    for guard in extra_guards:
+                        if guard.is_guard():
+                            descr = target.start_resumedescr.clone_if_mutable()
+                            inliner.inline_descr_inplace(descr)
+                            guard.setdescr(descr)
+                        self.emit_operation(guard)
+
+                    try:
+                        for shop in target.short_preamble[1:]:
+                            newop = inliner.inline_op(shop)
+                            self.emit_operation(newop)
+                    except InvalidLoop:
+                        debug_print("Inlining failed unexpectedly",
+                                    "jumping to preamble instead")
+                        assert False, "FIXME: Construct jump op"
+                        self.emit_operation(op)
+                    return
+            debug_stop('jit-log-virtualstate')
+            
+            if False: # FIXME: retrace
                 retraced_count = loop_token.retraced_count
                 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit
                 if not self.retraced and retraced_count<limit:
@@ -518,11 +542,9 @@
 
 class ExportedState(object):
     def __init__(self, constant_inputargs,
-                 short_boxes, inputarg_setup_ops, optimizer,
-                 start_resumedescr):
+                 short_boxes, inputarg_setup_ops, optimizer):
         self.constant_inputargs = constant_inputargs
         self.short_boxes = short_boxes
         self.inputarg_setup_ops = inputarg_setup_ops
         self.optimizer = optimizer
-        self.start_resumedescr = start_resumedescr
         
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -8,7 +8,7 @@
 
 from pypy.jit.metainterp import history, compile, resume
 from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstFloat
-from pypy.jit.metainterp.history import Box
+from pypy.jit.metainterp.history import Box, TargetToken
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp import executor
 from pypy.jit.metainterp.logger import Logger
@@ -1928,10 +1928,9 @@
         #   that failed;
         # - if self.resumekey is a ResumeFromInterpDescr, it starts directly
         #   from the interpreter.
-        if False: # FIXME
-          if not self.retracing_loop_from:
+        if not self.retracing_loop_from:
             try:
-                self.compile_bridge(live_arg_boxes)
+                self.compile_trace(live_arg_boxes)
             except RetraceLoop:
                 start = len(self.history.operations)
                 self.current_merge_points.append((live_arg_boxes, start))
@@ -2042,22 +2041,20 @@
     def compile_trace(self, live_arg_boxes):
         num_green_args = self.jitdriver_sd.num_green_args
         greenkey = live_arg_boxes[:num_green_args]
-        old_loop_tokens = self.get_compiled_merge_points(greenkey)
-        if len(old_loop_tokens) == 0:
+        target_procedure = self.get_procedure_token(greenkey)
+        if not target_procedure:
             return
-        #if self.resumekey.guard_opnum == rop.GUARD_CLASS:
-        #    return # Kepp tracing for another iteration
-        self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None)
+
+        self.history.record(rop.LABEL, live_arg_boxes[num_green_args:], None,
+                            descr=TargetToken(target_procedure))
         try:
-            target_loop_token = compile.compile_new_bridge(self,
-                                                           old_loop_tokens,
-                                                           self.resumekey)
+            target_token = compile.compile_new_bridge(self, self.resumekey)
         finally:
             self.history.operations.pop()     # remove the JUMP
-        if target_loop_token is not None: # raise if it *worked* correctly
+        if target_token is not None: # raise if it *worked* correctly
             self.history.inputargs = None
             self.history.operations = None
-            raise GenerateMergePoint(live_arg_boxes, target_loop_token)
+            raise GenerateMergePoint(live_arg_boxes, target_token.procedure_token)
 
     def compile_bridge_and_loop(self, original_boxes, live_arg_boxes, start,
                                 bridge_arg_boxes, start_resumedescr):
@@ -2119,6 +2116,7 @@
         else:
             assert False
         # FIXME: kill TerminatingLoopToken?
+        # FIXME: can we call compile_trace?
         self.history.record(rop.FINISH, exits, None, descr=loop_tokens[0].finishdescr)
         target_loop_token = compile.compile_new_bridge(self, self.resumekey)
         if not target_loop_token:
diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py
--- a/pypy/jit/metainterp/warmstate.py
+++ b/pypy/jit/metainterp/warmstate.py
@@ -328,7 +328,7 @@
                 # set counter to -2, to mean "tracing in effect"
                 cell.counter = -2
                 try:
-                    loop_token = metainterp.compile_and_run_once(jitdriver_sd,
+                    procedure_token = metainterp.compile_and_run_once(jitdriver_sd,
                                                                  *args)
                 finally:
                     if cell.counter == -2:
@@ -341,8 +341,8 @@
                 assert cell.counter == -1
                 if not confirm_enter_jit(*args):
                     return
-                loop_token = cell.get_entry_loop_token()
-                if loop_token is None:   # it was a weakref that has been freed
+                procedure_token = cell.get_procedure_token()
+                if procedure_token is None:   # it was a weakref that has been freed
                     cell.counter = 0
                     return
                 # machine code was already compiled for these greenargs
@@ -353,14 +353,14 @@
             while True:     # until interrupted by an exception
                 metainterp_sd.profiler.start_running()
                 #debug_start("jit-running")
-                fail_descr = warmrunnerdesc.execute_token(loop_token)
+                fail_descr = warmrunnerdesc.execute_token(procedure_token)
                 #debug_stop("jit-running")
                 metainterp_sd.profiler.end_running()
-                loop_token = None     # for test_memmgr
+                procedure_token = None     # for test_memmgr
                 if vinfo is not None:
                     vinfo.reset_vable_token(virtualizable)
-                loop_token = fail_descr.handle_fail(metainterp_sd,
-                                                    jitdriver_sd)
+                procedure_token = fail_descr.handle_fail(metainterp_sd,
+                                                         jitdriver_sd)
 
         maybe_compile_and_run._dont_inline_ = True
         self.maybe_compile_and_run = maybe_compile_and_run


More information about the pypy-commit mailing list