[pypy-commit] pypy small-unroll-improvements: intermediate checkin: start removing resume_at_jump_descr
cfbolz
noreply at buildbot.pypy.org
Sat Apr 5 18:40:34 CEST 2014
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: small-unroll-improvements
Changeset: r70470:3d10aa7553c0
Date: 2014-04-05 18:39 +0200
http://bitbucket.org/pypy/pypy/changeset/3d10aa7553c0/
Log: intermediate checkin: start removing resume_at_jump_descr
it was used in unroll.py as the target to jump to for newly created
guards. this was hugely complicated and I suspect actually wrong in
some cases. Instead, generate a dummy guard before a jump. This
guard is removed by optimizeopt, but its descr can be used by unroll
when inventing new guards.
almost finished, but some tests show differences in the loop enter
count, still to be investigated.
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
@@ -106,7 +106,7 @@
def compile_loop(metainterp, greenkey, start,
inputargs, jumpargs,
- resume_at_jump_descr, full_preamble_needed=True,
+ full_preamble_needed=True,
try_disabling_unroll=False):
"""Try to compile a new procedure by closing the current history back
to the first operation.
@@ -128,7 +128,6 @@
part = create_empty_loop(metainterp)
part.inputargs = inputargs[:]
h_ops = history.operations
- part.resume_at_jump_descr = resume_at_jump_descr
part.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(jitcell_token))] + \
[h_ops[i].clone() for i in range(start, len(h_ops))] + \
[ResOperation(rop.LABEL, jumpargs, None, descr=jitcell_token)]
@@ -187,7 +186,7 @@
def compile_retrace(metainterp, greenkey, start,
inputargs, jumpargs,
- resume_at_jump_descr, partial_trace, resumekey):
+ partial_trace, resumekey):
"""Try to compile a new procedure by closing the current history back
to the first operation.
"""
@@ -203,7 +202,6 @@
part = create_empty_loop(metainterp)
part.inputargs = inputargs[:]
- part.resume_at_jump_descr = resume_at_jump_descr
h_ops = history.operations
part.operations = [partial_trace.operations[-1]] + \
@@ -764,7 +762,7 @@
metainterp_sd.stats.add_jitcell_token(jitcell_token)
-def compile_trace(metainterp, resumekey, resume_at_jump_descr=None):
+def compile_trace(metainterp, resumekey):
"""Try to compile a new bridge leading from the beginning of the history
to some existing place.
"""
@@ -780,7 +778,6 @@
# clone ops, as optimize_bridge can mutate the ops
new_trace.operations = [op.clone() for op in metainterp.history.operations]
- new_trace.resume_at_jump_descr = resume_at_jump_descr
metainterp_sd = metainterp.staticdata
state = metainterp.jitdriver_sd.warmstate
if isinstance(resumekey, ResumeAtPositionDescr):
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
@@ -628,7 +628,6 @@
call_pure_results = None
logops = None
quasi_immutable_deps = None
- resume_at_jump_descr = None
def _token(*args):
raise Exception("TreeLoop.token is killed")
diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py
--- a/rpython/jit/metainterp/optimizeopt/rewrite.py
+++ b/rpython/jit/metainterp/optimizeopt/rewrite.py
@@ -543,6 +543,9 @@
return
self.emit_operation(op)
+ def optimize_GUARD_FUTURE_CONDITION(self, op):
+ pass # just remove it
+
def optimize_INT_FLOORDIV(self, op):
v1 = self.getvalue(op.getarg(0))
v2 = self.getvalue(op.getarg(1))
diff --git a/rpython/jit/metainterp/optimizeopt/simplify.py b/rpython/jit/metainterp/optimizeopt/simplify.py
--- a/rpython/jit/metainterp/optimizeopt/simplify.py
+++ b/rpython/jit/metainterp/optimizeopt/simplify.py
@@ -61,6 +61,9 @@
op.setdescr(descr.target_tokens[0])
self.emit_operation(op)
+ def optimize_GUARD_FUTURE_CONDITION(self, op):
+ pass
+
dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_',
default=OptSimplify.emit_operation)
OptSimplify.propagate_forward = dispatch_opt
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_multilabel.py b/rpython/jit/metainterp/optimizeopt/test/test_multilabel.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_multilabel.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_multilabel.py
@@ -1,6 +1,6 @@
from __future__ import with_statement
from rpython.jit.metainterp.optimizeopt.test.test_util import (
- LLtypeMixin, BaseTest, Storage, _sortboxes, FakeDescrWithSnapshot,
+ LLtypeMixin, BaseTest, Storage, _sortboxes,
FakeMetaInterpStaticData)
from rpython.jit.metainterp.history import TreeLoop, JitCellToken, TargetToken
from rpython.jit.metainterp.resoperation import rop, opname, ResOperation
@@ -8,6 +8,8 @@
from py.test import raises
from rpython.jit.metainterp.optimizeopt.optimizer import Optimization
from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
+from rpython.jit.metainterp.optimizeopt.heap import OptHeap
+from rpython.jit.metainterp.optimizeopt.rewrite import OptRewrite
class BaseTestMultiLabel(BaseTest):
@@ -20,7 +22,6 @@
part = TreeLoop('part')
part.inputargs = loop.inputargs
- part.resume_at_jump_descr = FakeDescrWithSnapshot()
token = loop.original_jitcell_token
optimized = TreeLoop('optimized')
@@ -42,6 +43,7 @@
operations.append(label)
part.operations = operations
+ self.add_guard_future_condition(part)
self._do_optimize_loop(part, None)
if part.operations[-1].getopnum() == rop.LABEL:
last_label = [part.operations.pop()]
@@ -502,7 +504,7 @@
self.loop = loop
loop.call_pure_results = args_dict()
metainterp_sd = FakeMetaInterpStaticData(self.cpu)
- optimize_unroll(metainterp_sd, loop, [OptRenameStrlen(), OptPure()], True)
+ optimize_unroll(metainterp_sd, loop, [OptRewrite(), OptRenameStrlen(), OptHeap(), OptPure()], True)
def test_optimizer_renaming_boxes1(self):
ops = """
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -51,7 +51,8 @@
if expected_preamble:
expected_preamble = self.parse(expected_preamble)
if expected_short:
- expected_short = self.parse(expected_short)
+ # the short preamble doesn't have fail descrs, they are patched in when it is used
+ expected_short = self.parse(expected_short, want_fail_descr=False)
preamble = self.unroll_and_optimize(loop, call_pure_results)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -355,11 +355,21 @@
class BaseTest(object):
- def parse(self, s, boxkinds=None):
+ def parse(self, s, boxkinds=None, want_fail_descr=True):
+ if want_fail_descr:
+ invent_fail_descr = self.invent_fail_descr
+ else:
+ invent_fail_descr = lambda *args: None
return parse(s, self.cpu, self.namespace,
type_system=self.type_system,
boxkinds=boxkinds,
- invent_fail_descr=self.invent_fail_descr)
+ invent_fail_descr=invent_fail_descr)
+
+ def add_guard_future_condition(self, res):
+ # invent a GUARD_FUTURE_CONDITION to not have to change all tests
+ if res.operations[-1].getopnum() == rop.JUMP:
+ guard = ResOperation(rop.GUARD_FUTURE_CONDITION, [], None, descr=self.invent_fail_descr(None, -1, []))
+ res.operations.insert(-1, guard)
def invent_fail_descr(self, model, opnum, fail_args):
if fail_args is None:
@@ -397,6 +407,7 @@
optimize_trace(metainterp_sd, loop, self.enable_opts)
def unroll_and_optimize(self, loop, call_pure_results=None):
+ self.add_guard_future_condition(loop)
operations = loop.operations
jumpop = operations[-1]
assert jumpop.getopnum() == rop.JUMP
@@ -408,7 +419,6 @@
preamble = TreeLoop('preamble')
preamble.inputargs = inputargs
- preamble.resume_at_jump_descr = FakeDescrWithSnapshot()
token = JitCellToken()
preamble.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(token))] + \
@@ -419,7 +429,6 @@
assert preamble.operations[-1].getopnum() == rop.LABEL
inliner = Inliner(inputargs, jump_args)
- loop.resume_at_jump_descr = preamble.resume_at_jump_descr
loop.operations = [preamble.operations[-1]] + \
[inliner.inline_op(op, clone=False) for op in cloned_operations] + \
[ResOperation(rop.JUMP, [inliner.inline_arg(a) for a in jump_args],
@@ -450,18 +459,6 @@
def __eq__(self, other):
return isinstance(other, FakeDescr)
-class FakeDescrWithSnapshot(compile.ResumeGuardDescr):
- class rd_snapshot:
- class prev:
- prev = None
- boxes = []
- boxes = []
- def clone_if_mutable(self):
- return FakeDescrWithSnapshot()
- def __eq__(self, other):
- return isinstance(other, Storage) or isinstance(other, FakeDescrWithSnapshot)
-
-
def convert_old_style_to_targets(loop, jump):
newloop = TreeLoop(loop.name)
newloop.inputargs = loop.inputargs
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
@@ -7,7 +7,7 @@
from rpython.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr, ConstInt, ConstPtr
from rpython.rtyper.lltypesystem import lltype, llmemory
from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin, BaseTest, \
- equaloplists, FakeDescrWithSnapshot
+ equaloplists
from rpython.jit.metainterp.optimizeopt.intutils import IntBound
from rpython.jit.metainterp.history import TreeLoop, JitCellToken
from rpython.jit.metainterp.optimizeopt.test.test_optimizeopt import FakeMetaInterpStaticData
@@ -488,7 +488,6 @@
if hasattr(self, 'callinfocollection'):
metainterp_sd.callinfocollection = self.callinfocollection
#
- bridge.resume_at_jump_descr = FakeDescrWithSnapshot()
optimize_trace(metainterp_sd, bridge, self.enable_opts)
@@ -497,6 +496,7 @@
loops = (loops, )
loops = [self.parse(loop) for loop in loops]
bridge = self.parse(bridge)
+ self.add_guard_future_condition(bridge)
for loop in loops:
loop.preamble = self.unroll_and_optimize(loop)
preamble = loops[0].preamble
diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py
--- a/rpython/jit/metainterp/optimizeopt/unroll.py
+++ b/rpython/jit/metainterp/optimizeopt/unroll.py
@@ -77,6 +77,12 @@
else:
start_label = None
+ patchguardop = None
+ if len(loop.operations) > 1:
+ patchguardop = loop.operations[-2]
+ if patchguardop.getopnum() != rop.GUARD_FUTURE_CONDITION:
+ patchguardop = None
+
jumpop = loop.operations[-1]
if jumpop.getopnum() == rop.JUMP or jumpop.getopnum() == rop.LABEL:
loop.operations = loop.operations[:-1]
@@ -94,7 +100,7 @@
stop_label = ResOperation(rop.LABEL, jumpop.getarglist(), None, TargetToken(cell_token))
if jumpop.getopnum() == rop.JUMP:
- if self.jump_to_already_compiled_trace(jumpop):
+ if self.jump_to_already_compiled_trace(jumpop, patchguardop):
# Found a compiled trace to jump to
if self.short:
# Construct our short preamble
@@ -108,7 +114,7 @@
descr=start_label.getdescr())
if self.short:
# Construct our short preamble
- self.close_loop(start_label, jumpop)
+ self.close_loop(start_label, jumpop, patchguardop)
else:
self.optimizer.send_extra_operation(jumpop)
return
@@ -162,11 +168,6 @@
original_jump_args = targetop.getarglist()
jump_args = [self.getvalue(a).get_key_box() for a in original_jump_args]
- assert self.optimizer.loop.resume_at_jump_descr
- resume_at_jump_descr = self.optimizer.loop.resume_at_jump_descr.clone_if_mutable()
- assert isinstance(resume_at_jump_descr, ResumeGuardDescr)
- resume_at_jump_descr.rd_snapshot = self.fix_snapshot(jump_args, resume_at_jump_descr.rd_snapshot)
-
modifier = VirtualStateAdder(self.optimizer)
virtual_state = modifier.get_virtual_state(jump_args)
@@ -195,7 +196,6 @@
targetop.initarglist(inputargs)
target_token.virtual_state = virtual_state
target_token.short_preamble = [ResOperation(rop.LABEL, short_inputargs, None)]
- target_token.resume_at_jump_descr = resume_at_jump_descr
exported_values = {}
for box in inputargs:
@@ -230,7 +230,6 @@
self.short = target_token.short_preamble[:]
self.short_seen = {}
self.short_boxes = exported_state.short_boxes
- self.short_resume_at_jump_descr = target_token.resume_at_jump_descr
self.initial_virtual_state = target_token.virtual_state
seen = {}
@@ -298,7 +297,7 @@
self.short.append(ResOperation(rop.JUMP, short_jumpargs, None, descr=start_label.getdescr()))
self.finalize_short_preamble(start_label)
- def close_loop(self, start_label, jumpop):
+ def close_loop(self, start_label, jumpop, patchguardop):
virtual_state = self.initial_virtual_state
short_inputargs = self.short[0].getarglist()
inputargs = self.inputargs
@@ -335,6 +334,11 @@
# Note that self.short might be extended during this loop
op = self.short[i]
newop = self.short_inliner.inline_op(op)
+ if newop.is_guard():
+ if not patchguardop:
+ raise InvalidLoop("would like to have short preamble, but it has a guard and there's no guard_future_condition")
+ descr = patchguardop.getdescr().clone_if_mutable()
+ newop.setdescr(descr)
self.optimizer.send_extra_operation(newop)
if op.result in self.short_boxes.assumed_classes:
classbox = self.getvalue(newop.result).get_constant_class(self.optimizer.cpu)
@@ -417,8 +421,7 @@
if op.is_guard():
op = op.clone()
op.setfailargs(None)
- descr = target_token.resume_at_jump_descr.clone_if_mutable()
- op.setdescr(descr)
+ op.setdescr(None) # will be set to a proper descr when the preamble is used
short[i] = op
# Clone ops and boxes to get private versions and
@@ -440,8 +443,6 @@
if op.result and op.result in self.short_boxes.assumed_classes:
target_token.assumed_classes[newop.result] = self.short_boxes.assumed_classes[op.result]
short[i] = newop
- target_token.resume_at_jump_descr = target_token.resume_at_jump_descr.clone_if_mutable()
- inliner.inline_descr_inplace(target_token.resume_at_jump_descr)
# Forget the values to allow them to be freed
for box in short[0].getarglist():
@@ -485,8 +486,7 @@
if not isinstance(a, Const) and a not in self.short_seen:
self.add_op_to_short(self.short_boxes.producer(a), emit, guards_needed)
if op.is_guard():
- descr = self.short_resume_at_jump_descr.clone_if_mutable()
- op.setdescr(descr)
+ op.setdescr(None) # will be set to a proper descr when the preamble is used
if guards_needed and self.short_boxes.has_producer(op.result):
value_guards = self.getvalue(op.result).make_guards(op.result)
@@ -528,7 +528,7 @@
box = self.optimizer.values[box].force_box(self.optimizer)
jumpargs.append(box)
- def jump_to_already_compiled_trace(self, jumpop):
+ def jump_to_already_compiled_trace(self, jumpop, patchguardop):
assert jumpop.getopnum() == rop.JUMP
cell_token = jumpop.getdescr()
@@ -570,6 +570,21 @@
debugmsg = 'Guarded to match '
except InvalidLoop:
pass
+ #else:
+ # import pdb; pdb.set_trace()
+ if ok and not patchguardop:
+ # if we can't patch the guards to go to a good target, no use
+ # in jumping to this label
+ for guard in extra_guards:
+ if guard.is_guard():
+ ok = False
+ break
+ else:
+ for shop in target.short_preamble[1:]:
+ if shop.is_guard():
+ ok = False
+ break
+
target.virtual_state.debug_print(debugmsg, bad)
if ok:
@@ -584,14 +599,16 @@
for guard in extra_guards:
if guard.is_guard():
- descr = target.resume_at_jump_descr.clone_if_mutable()
- inliner.inline_descr_inplace(descr)
+ descr = patchguardop.getdescr().clone_if_mutable()
guard.setdescr(descr)
self.optimizer.send_extra_operation(guard)
try:
for shop in target.short_preamble[1:]:
newop = inliner.inline_op(shop)
+ if newop.is_guard():
+ descr = patchguardop.getdescr().clone_if_mutable()
+ newop.setdescr(descr)
self.optimizer.send_extra_operation(newop)
if shop.result in target.assumed_classes:
classbox = self.getvalue(newop.result).get_constant_class(self.optimizer.cpu)
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1049,10 +1049,8 @@
# much less expensive to blackhole out of.
saved_pc = self.pc
self.pc = orgpc
- resumedescr = compile.ResumeAtPositionDescr()
- self.metainterp.capture_resumedata(resumedescr, orgpc)
-
- self.metainterp.reached_loop_header(greenboxes, redboxes, resumedescr)
+ self.metainterp.generate_guard(rop.GUARD_FUTURE_CONDITION, resumepc=orgpc)
+ self.metainterp.reached_loop_header(greenboxes, redboxes)
self.pc = saved_pc
# no exception, which means that the jit_merge_point did not
# close the loop. We have to put the possibly-modified list
@@ -1789,6 +1787,8 @@
self.jitdriver_sd)
elif opnum == rop.GUARD_NOT_INVALIDATED:
resumedescr = compile.ResumeGuardNotInvalidated()
+ elif opnum == rop.GUARD_FUTURE_CONDITION:
+ resumedescr = compile.ResumeAtPositionDescr()
else:
resumedescr = compile.ResumeGuardDescr()
guard_op = self.history.record(opnum, moreargs, None, descr=resumedescr)
@@ -2060,7 +2060,7 @@
else:
duplicates[box] = None
- def reached_loop_header(self, greenboxes, redboxes, resumedescr):
+ def reached_loop_header(self, greenboxes, redboxes):
self.heapcache.reset(reset_virtuals=False)
duplicates = {}
@@ -2085,7 +2085,7 @@
# from the interpreter.
if not self.partial_trace:
# FIXME: Support a retrace to be a bridge as well as a loop
- self.compile_trace(live_arg_boxes, resumedescr)
+ self.compile_trace(live_arg_boxes)
# raises in case it works -- which is the common case, hopefully,
# at least for bridges starting from a guard.
@@ -2110,7 +2110,7 @@
raise SwitchToBlackhole(Counters.ABORT_BAD_LOOP) # For now
# Found! Compile it as a loop.
# raises in case it works -- which is the common case
- self.compile_loop(original_boxes, live_arg_boxes, start, resumedescr)
+ self.compile_loop(original_boxes, live_arg_boxes, start)
# creation of the loop was cancelled!
self.cancel_count += 1
if self.staticdata.warmrunnerdesc:
@@ -2119,7 +2119,7 @@
if self.cancel_count > memmgr.max_unroll_loops:
self.compile_loop_or_abort(original_boxes,
live_arg_boxes,
- start, resumedescr)
+ start)
self.staticdata.log('cancelled, tracing more...')
# Otherwise, no loop found so far, so continue tracing.
@@ -2224,7 +2224,7 @@
return token
def compile_loop(self, original_boxes, live_arg_boxes, start,
- resume_at_jump_descr, try_disabling_unroll=False):
+ try_disabling_unroll=False):
num_green_args = self.jitdriver_sd.num_green_args
greenkey = original_boxes[:num_green_args]
if not self.partial_trace:
@@ -2237,13 +2237,12 @@
target_token = compile.compile_retrace(self, greenkey, start,
original_boxes[num_green_args:],
live_arg_boxes[num_green_args:],
- resume_at_jump_descr, self.partial_trace,
+ self.partial_trace,
self.resumekey)
else:
target_token = compile.compile_loop(self, greenkey, start,
original_boxes[num_green_args:],
live_arg_boxes[num_green_args:],
- resume_at_jump_descr,
try_disabling_unroll=try_disabling_unroll)
if target_token is not None:
assert isinstance(target_token, TargetToken)
@@ -2257,18 +2256,18 @@
self.raise_continue_running_normally(live_arg_boxes, jitcell_token)
def compile_loop_or_abort(self, original_boxes, live_arg_boxes,
- start, resume_at_jump_descr):
+ start):
"""Called after we aborted more than 'max_unroll_loops' times.
As a last attempt, try to compile the loop with unrolling disabled.
"""
if not self.partial_trace:
self.compile_loop(original_boxes, live_arg_boxes, start,
- resume_at_jump_descr, try_disabling_unroll=True)
+ try_disabling_unroll=True)
#
self.staticdata.log('cancelled too many times!')
raise SwitchToBlackhole(Counters.ABORT_BAD_LOOP)
- def compile_trace(self, live_arg_boxes, resume_at_jump_descr):
+ def compile_trace(self, live_arg_boxes):
num_green_args = self.jitdriver_sd.num_green_args
greenkey = live_arg_boxes[:num_green_args]
target_jitcell_token = self.get_procedure_token(greenkey, True)
@@ -2278,7 +2277,7 @@
self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None,
descr=target_jitcell_token)
try:
- target_token = compile.compile_trace(self, self.resumekey, resume_at_jump_descr)
+ target_token = compile.compile_trace(self, self.resumekey)
finally:
self.history.operations.pop() # remove the JUMP
if target_token is not None: # raise if it *worked* correctly
diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -400,6 +400,7 @@
'GUARD_NOT_FORCED/0d', # may be called with an exception currently set
'GUARD_NOT_FORCED_2/0d', # same as GUARD_NOT_FORCED, but for finish()
'GUARD_NOT_INVALIDATED/0d',
+ 'GUARD_FUTURE_CONDITION/0d', # is removable, may be patched by an optimization
'_GUARD_LAST', # ----- end of guard operations -----
'_NOSIDEEFFECT_FIRST', # ----- start of no_side_effect operations -----
More information about the pypy-commit
mailing list