Author: Hakan Ardo <ha...@debian.org> Branch: jit-targets Changeset: r48780:0e0764aac5be Date: 2011-11-05 14:36 +0100 http://bitbucket.org/pypy/pypy/changeset/0e0764aac5be/
Log: refactoring in progress diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py --- a/pypy/jit/backend/llgraph/llimpl.py +++ b/pypy/jit/backend/llgraph/llimpl.py @@ -391,7 +391,8 @@ def compile_add_jump_target(loop, targettoken): loop = _from_opaque(loop) - if isinstance(targettoken, history.LoopToken): + if isinstance(targettoken, history.ProcedureToken): + assert False loop_target = _from_opaque(targettoken.compiled_loop_token.compiled_version) target_opindex = 0 target_inputargs = loop_target.inputargs diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -180,10 +180,11 @@ if isinstance(descr, Descr): llimpl.compile_add_descr(c, descr.ofs, descr.typeinfo, descr.arg_types) - if isinstance(descr, history.LoopToken): + if isinstance(descr, history.ProcedureToken): + assert False if op.getopnum() != rop.JUMP: llimpl.compile_add_loop_token(c, descr) - if isinstance(descr, history.TargetToken) and op.getopnum() == rop.TARGET: + if isinstance(descr, history.TargetToken) and op.getopnum() == rop.LABEL: llimpl.compile_add_target_token(c, descr) if self.is_oo and isinstance(descr, (OODescr, MethDescr)): # hack hack, not rpython 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 @@ -9,12 +9,13 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.jit.metainterp.resoperation import ResOperation, rop, get_deep_immutable_oplist -from pypy.jit.metainterp.history import TreeLoop, Box, History, LoopToken +from pypy.jit.metainterp.history import TreeLoop, Box, History, ProcedureToken, TargetToken from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const from pypy.jit.metainterp import history from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.jit.metainterp.optimize import InvalidLoop +from pypy.jit.metainterp.inliner import Inliner from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP from pypy.jit.codewriter import heaptracker, longlong @@ -45,10 +46,10 @@ return loop -def make_loop_token(nb_args, jitdriver_sd): - loop_token = LoopToken() - loop_token.outermost_jitdriver_sd = jitdriver_sd - return loop_token +def make_procedure_token(jitdriver_sd): + procedure_token = ProcedureToken() + procedure_token.outermost_jitdriver_sd = jitdriver_sd + return procedure_token def record_loop_or_bridge(metainterp_sd, loop): """Do post-backend recordings and cleanups on 'loop'. @@ -67,16 +68,18 @@ n = descr.index if n >= 0: # we also record the resumedescr number looptoken.compiled_loop_token.record_faildescr_index(n) - elif isinstance(descr, LoopToken): + elif isinstance(descr, ProcedureToken): + assert False, "FIXME" + elif isinstance(descr, TargetToken): # for a JUMP or a CALL_ASSEMBLER: record it as a potential jump. # (the following test is not enough to prevent more complicated # cases of cycles, but at least it helps in simple tests of # test_memgr.py) - if descr is not looptoken: - looptoken.record_jump_to(descr) + if descr.procedure_token is not looptoken: + looptoken.record_jump_to(descr.procedure_token) op._descr = None # clear reference, mostly for tests if not we_are_translated(): - op._jumptarget_number = descr.number + op._jumptarget_number = descr.procedure_token.number # record this looptoken on the QuasiImmut used in the code if loop.quasi_immutable_deps is not None: for qmut in loop.quasi_immutable_deps: @@ -89,47 +92,60 @@ # ____________________________________________________________ -def compile_new_loop(metainterp, old_loop_tokens, greenkey, start, - start_resumedescr, full_preamble_needed=True): - """Try to compile a new loop by closing the current history back +def compile_procedure(metainterp, greenkey, start, + inputargs, jumpargs, + start_resumedescr, full_preamble_needed=True): + """Try to compile a new procedure by closing the current history back to the first operation. """ - from pypy.jit.metainterp.optimize import optimize_loop + from pypy.jit.metainterp.optimizeopt import optimize_trace history = metainterp.history + metainterp_sd = metainterp.staticdata + jitdriver_sd = metainterp.jitdriver_sd + loop = create_empty_loop(metainterp) - loop.inputargs = history.inputargs[:] + loop.inputargs = inputargs[:] + + procedure_token = make_procedure_token(jitdriver_sd) + part = create_empty_loop(metainterp) + h_ops = history.operations + part.start_resumedescr = start_resumedescr + part.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(procedure_token))] + \ + [h_ops[i].clone() for i in range(start, len(h_ops))] + \ + [ResOperation(rop.LABEL, jumpargs, None, descr=TargetToken(procedure_token))] + try: + optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts) + except InvalidLoop: + return None + loop.operations = part.operations + 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))] + inputargs = jumpargs + jumpargs = part.operations[-1].getarglist() + + try: + optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts) + except InvalidLoop: + return None + + loop.operations = loop.operations[:-1] + part.operations + for box in loop.inputargs: assert isinstance(box, Box) - # make a copy, because optimize_loop can mutate the ops and descrs - h_ops = history.operations - loop.operations = [h_ops[i].clone() for i in range(start, len(h_ops))] - metainterp_sd = metainterp.staticdata - jitdriver_sd = metainterp.jitdriver_sd - loop_token = make_loop_token(len(loop.inputargs), jitdriver_sd) - loop.token = loop_token - loop.operations[-1].setdescr(loop_token) # patch the target of the JUMP - loop.preamble = create_empty_loop(metainterp, 'Preamble ') - loop.preamble.inputargs = loop.inputargs - loop.preamble.token = make_loop_token(len(loop.inputargs), jitdriver_sd) - loop.preamble.start_resumedescr = start_resumedescr + loop.token = procedure_token - try: - old_loop_token = optimize_loop(metainterp_sd, old_loop_tokens, loop, - jitdriver_sd.warmstate.enable_opts) - except InvalidLoop: - debug_print("compile_new_loop: got an InvalidLoop") - return None - if old_loop_token is not None: - metainterp.staticdata.log("reusing old loop") - return old_loop_token + send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop") + record_loop_or_bridge(metainterp_sd, loop) + return loop.token - if loop.preamble.operations is not None: - send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, - "loop") - record_loop_or_bridge(metainterp_sd, loop) - token = loop.preamble.token + + if False: # FIXME: full_preamble_needed?? if full_preamble_needed: send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop.preamble, "entry bridge") @@ -263,7 +279,7 @@ raise metainterp_sd.ExitFrameWithExceptionRef(cpu, value) -class TerminatingLoopToken(LoopToken): +class TerminatingLoopToken(ProcedureToken): # FIXME:!! terminating = True def __init__(self, nargs, finishdescr): 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 @@ -727,7 +727,7 @@ # of operations. Each branch ends in a jump which can go either to # the top of the same loop, or to another TreeLoop; or it ends in a FINISH. -class LoopToken(AbstractDescr): +class ProcedureToken(AbstractDescr): """Used for rop.JUMP, giving the target of the jump. This is different from TreeLoop: the TreeLoop class contains the whole loop, including 'operations', and goes away after the loop @@ -766,8 +766,8 @@ self.compiled_loop_token.cpu.dump_loop_token(self) class TargetToken(AbstractDescr): - def __init__(self, merge_point): - self.merge_point = merge_point + def __init__(self, procedure_token): + self.procedure_token = procedure_token self.virtual_state = None self.exported_state = None @@ -870,7 +870,7 @@ if operations[-1].getopnum() == rop.JUMP: target = operations[-1].getdescr() if target is not None: - assert isinstance(target, LoopToken) + assert isinstance(target, TargetToken) def dump(self): # RPython-friendly diff --git a/pypy/jit/metainterp/inliner.py b/pypy/jit/metainterp/inliner.py new file mode 100644 --- /dev/null +++ b/pypy/jit/metainterp/inliner.py @@ -0,0 +1,57 @@ +from pypy.jit.metainterp.history import Const +from pypy.jit.metainterp.resume import Snapshot + +class Inliner(object): + def __init__(self, inputargs, jump_args): + assert len(inputargs) == len(jump_args) + self.argmap = {} + for i in range(len(inputargs)): + if inputargs[i] in self.argmap: + assert self.argmap[inputargs[i]] == jump_args[i] + else: + self.argmap[inputargs[i]] = jump_args[i] + self.snapshot_map = {None: None} + + def inline_op(self, newop, ignore_result=False, clone=True, + ignore_failargs=False): + if clone: + newop = newop.clone() + args = newop.getarglist() + newop.initarglist([self.inline_arg(a) for a in args]) + + if newop.is_guard(): + args = newop.getfailargs() + if args and not ignore_failargs: + newop.setfailargs([self.inline_arg(a) for a in args]) + else: + newop.setfailargs([]) + + if newop.result and not ignore_result: + old_result = newop.result + newop.result = newop.result.clonebox() + self.argmap[old_result] = newop.result + + self.inline_descr_inplace(newop.getdescr()) + + return newop + + def inline_descr_inplace(self, descr): + from pypy.jit.metainterp.compile import ResumeGuardDescr + if isinstance(descr, ResumeGuardDescr): + descr.rd_snapshot = self.inline_snapshot(descr.rd_snapshot) + + def inline_arg(self, arg): + if arg is None: + return None + if isinstance(arg, Const): + return arg + return self.argmap[arg] + + def inline_snapshot(self, snapshot): + if snapshot in self.snapshot_map: + return self.snapshot_map[snapshot] + boxes = [self.inline_arg(a) for a in snapshot.boxes] + new_snapshot = Snapshot(self.inline_snapshot(snapshot.prev), boxes) + self.snapshot_map[snapshot] = new_snapshot + return new_snapshot + 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 @@ -1,11 +1,12 @@ from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.virtualstate import VirtualStateAdder, ShortBoxes from pypy.jit.metainterp.compile import ResumeGuardDescr -from pypy.jit.metainterp.history import TreeLoop, LoopToken, TargetToken +from pypy.jit.metainterp.history import TreeLoop, TargetToken from pypy.jit.metainterp.jitexc import JitException from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.optimizeopt.generalize import KillHugeIntBounds +from pypy.jit.metainterp.inliner import Inliner from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.resume import Snapshot from pypy.rlib.debug import debug_print @@ -17,59 +18,6 @@ opt = UnrollOptimizer(metainterp_sd, loop, optimizations) opt.propagate_all_forward() -class Inliner(object): - def __init__(self, inputargs, jump_args): - assert len(inputargs) == len(jump_args) - self.argmap = {} - for i in range(len(inputargs)): - if inputargs[i] in self.argmap: - assert self.argmap[inputargs[i]] == jump_args[i] - else: - self.argmap[inputargs[i]] = jump_args[i] - self.snapshot_map = {None: None} - - def inline_op(self, newop, ignore_result=False, clone=True, - ignore_failargs=False): - if clone: - newop = newop.clone() - args = newop.getarglist() - newop.initarglist([self.inline_arg(a) for a in args]) - - if newop.is_guard(): - args = newop.getfailargs() - if args and not ignore_failargs: - newop.setfailargs([self.inline_arg(a) for a in args]) - else: - newop.setfailargs([]) - - if newop.result and not ignore_result: - old_result = newop.result - newop.result = newop.result.clonebox() - self.argmap[old_result] = newop.result - - self.inline_descr_inplace(newop.getdescr()) - - return newop - - def inline_descr_inplace(self, descr): - if isinstance(descr, ResumeGuardDescr): - descr.rd_snapshot = self.inline_snapshot(descr.rd_snapshot) - - def inline_arg(self, arg): - if arg is None: - return None - if isinstance(arg, Const): - return arg - return self.argmap[arg] - - def inline_snapshot(self, snapshot): - if snapshot in self.snapshot_map: - return self.snapshot_map[snapshot] - boxes = [self.inline_arg(a) for a in snapshot.boxes] - new_snapshot = Snapshot(self.inline_snapshot(snapshot.prev), boxes) - self.snapshot_map[snapshot] = new_snapshot - return new_snapshot - class UnrollableOptimizer(Optimizer): def setup(self): self.importable_values = {} @@ -143,7 +91,7 @@ self.export_state(lastop) loop.operations.append(lastop) else: - assert lastop.getdescr().merge_point is start_targetop.getdescr().merge_point + assert lastop.getdescr().procedure_token is start_targetop.getdescr().procedure_token jumpop = ResOperation(rop.JUMP, lastop.getarglist(), None, descr=start_targetop.getdescr()) self.close_loop(jumpop) @@ -474,7 +422,9 @@ def propagate_forward(self, op): if op.getopnum() == rop.JUMP: loop_token = op.getdescr() - assert isinstance(loop_token, TargetToken) + if not isinstance(loop_token, TargetToken): + self.emit_operation(op) + return short = loop_token.short_preamble if short: args = op.getarglist() diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py --- a/pypy/jit/metainterp/optimizeopt/util.py +++ b/pypy/jit/metainterp/optimizeopt/util.py @@ -171,3 +171,4 @@ assert len(oplist1) == len(oplist2) print '-'*totwidth return True + 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 @@ -1928,7 +1928,8 @@ # that failed; # - if self.resumekey is a ResumeFromInterpDescr, it starts directly # from the interpreter. - if not self.retracing_loop_from: + if False: # FIXME + if not self.retracing_loop_from: try: self.compile_bridge(live_arg_boxes) except RetraceLoop: @@ -1964,7 +1965,7 @@ live_arg_boxes, start, bridge_arg_boxes, resumedescr) else: - self.compile(original_boxes, live_arg_boxes, start, resumedescr) + self.compile_procedure(original_boxes, live_arg_boxes, start, resumedescr) # creation of the loop was cancelled! self.staticdata.log('cancelled, tracing more...') #self.staticdata.log('cancelled, stopping tracing') @@ -2020,36 +2021,25 @@ from pypy.jit.metainterp.resoperation import opname raise NotImplementedError(opname[opnum]) - def get_compiled_merge_points(self, greenkey): - """Get the list of looptokens corresponding to the greenkey. - Turns the (internal) list of weakrefs into regular refs. - """ + def get_procedure_token(self, greenkey): cell = self.jitdriver_sd.warmstate.jit_cell_at_key(greenkey) - return cell.get_compiled_merge_points() - - def set_compiled_merge_points(self, greenkey, looptokens): - cell = self.jitdriver_sd.warmstate.jit_cell_at_key(greenkey) - cell.set_compiled_merge_points(looptokens) - - def compile(self, original_boxes, live_arg_boxes, start, start_resumedescr): + return cell.get_procedure_token() + + def compile_procedure(self, original_boxes, live_arg_boxes, start, start_resumedescr): num_green_args = self.jitdriver_sd.num_green_args - original_inputargs = self.history.inputargs - self.history.inputargs = original_boxes[num_green_args:] greenkey = original_boxes[:num_green_args] - old_loop_tokens = self.get_compiled_merge_points(greenkey) - self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None) - loop_token = compile.compile_new_loop(self, old_loop_tokens, - greenkey, start, start_resumedescr) - if loop_token is not None: # raise if it *worked* correctly - self.set_compiled_merge_points(greenkey, old_loop_tokens) + assert self.get_procedure_token(greenkey) == None # FIXME: recursion? + procedure_token = compile.compile_procedure(self, greenkey, start, + original_boxes[num_green_args:], + live_arg_boxes[num_green_args:], + start_resumedescr) + if procedure_token is not None: # raise if it *worked* correctly + self.jitdriver_sd.attach_procedure_to_interp(greenkey, procedure_token) self.history.inputargs = None self.history.operations = None - raise GenerateMergePoint(live_arg_boxes, loop_token) + raise GenerateMergePoint(live_arg_boxes, procedure_token) - self.history.inputargs = original_inputargs - self.history.operations.pop() # remove the JUMP - - def compile_bridge(self, live_arg_boxes): + 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) 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 @@ -169,34 +169,20 @@ # counter == -1: there is an entry bridge for this cell # counter == -2: tracing is currently going on for this cell counter = 0 - compiled_merge_points_wref = None # list of weakrefs to LoopToken dont_trace_here = False - wref_entry_loop_token = None # (possibly) one weakref to LoopToken + wref_procedure_token = None - def get_compiled_merge_points(self): - result = [] - if self.compiled_merge_points_wref is not None: - for wref in self.compiled_merge_points_wref: - looptoken = wref() - if looptoken is not None and not looptoken.invalidated: - result.append(looptoken) - return result - - def set_compiled_merge_points(self, looptokens): - self.compiled_merge_points_wref = [self._makeref(token) - for token in looptokens] - - def get_entry_loop_token(self): - if self.wref_entry_loop_token is not None: - return self.wref_entry_loop_token() + def get_procedure_token(self): + if self.wref_procedure_token is not None: + return self.wref_procedure_token() return None - def set_entry_loop_token(self, looptoken): - self.wref_entry_loop_token = self._makeref(looptoken) + def set_procedure_token(self, token): + self.wref_procedure_token = self._makeref(token) - def _makeref(self, looptoken): - assert looptoken is not None - return weakref.ref(looptoken) + def _makeref(self, token): + assert token is not None + return weakref.ref(token) # ____________________________________________________________ @@ -283,18 +269,17 @@ debug_print("disabled inlining", loc) debug_stop("jit-disableinlining") - def attach_unoptimized_bridge_from_interp(self, greenkey, - entry_loop_token): + def attach_procedure_to_interp(self, greenkey, procedure_token): cell = self.jit_cell_at_key(greenkey) - old_token = cell.get_entry_loop_token() - cell.set_entry_loop_token(entry_loop_token) - cell.counter = -1 # valid entry bridge attached + old_token = cell.get_procedure_token() + cell.set_procedure_token(procedure_token) + cell.counter = -1 # valid procedure bridge attached if old_token is not None: - self.cpu.redirect_call_assembler(old_token, entry_loop_token) - # entry_loop_token is also kept alive by any loop that used + self.cpu.redirect_call_assembler(old_token, procedure_token) + # procedure_token is also kept alive by any loop that used # to point to old_token. Actually freeing old_token early # is a pointless optimization (it is tiny). - old_token.record_jump_to(entry_loop_token) + old_token.record_jump_to(procedure_token) # ---------- @@ -617,16 +602,16 @@ def get_assembler_token(greenkey, redboxes): # 'redboxes' is only used to know the types of red arguments cell = self.jit_cell_at_key(greenkey) - entry_loop_token = cell.get_entry_loop_token() - if entry_loop_token is None: + procedure_token = cell.get_procedure_token() + if procedure_token is None: from pypy.jit.metainterp.compile import compile_tmp_callback if cell.counter == -1: # used to be a valid entry bridge, cell.counter = 0 # but was freed in the meantime. memmgr = warmrunnerdesc.memory_manager - entry_loop_token = compile_tmp_callback(cpu, jd, greenkey, - redboxes, memmgr) - cell.set_entry_loop_token(entry_loop_token) - return entry_loop_token + procedure_token = compile_tmp_callback(cpu, jd, greenkey, + redboxes, memmgr) + cell.set_procedure_token(procedure_token) + return procedure_token self.get_assembler_token = get_assembler_token # _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit