[pypy-commit] pypy default: Merge jit-improve-nested-loops. It allows bridges to end with a jump to the the top of a loop and not only to the bottom. While this realy is the same point (since it is a loop) it prevents bridges going from one loop to another from inlining a full iteration of the target loop at the end of the bridge.
hakanardo
noreply at buildbot.pypy.org
Wed Dec 28 21:29:55 CET 2011
Author: Hakan Ardo <hakan at debian.org>
Branch:
Changeset: r50935:69095778cbfd
Date: 2011-12-28 21:28 +0100
http://bitbucket.org/pypy/pypy/changeset/69095778cbfd/
Log: Merge jit-improve-nested-loops. It allows bridges to end with a jump
to the the top of a loop and not only to the bottom. While this
realy is the same point (since it is a loop) it prevents bridges
going from one loop to another from inlining a full iteration of the
target loop at the end of the bridge.
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
@@ -169,10 +169,10 @@
loop.original_jitcell_token = jitcell_token
for label in all_target_tokens:
assert isinstance(label, TargetToken)
- label.original_jitcell_token = jitcell_token
if label.virtual_state and label.short_preamble:
metainterp_sd.logger_ops.log_short_preamble([], label.short_preamble)
jitcell_token.target_tokens = all_target_tokens
+ propagate_original_jitcell_token(loop)
send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop")
record_loop_or_bridge(metainterp_sd, loop)
return all_target_tokens[0]
@@ -240,11 +240,11 @@
for box in loop.inputargs:
assert isinstance(box, Box)
- target_token = loop.operations[-1].getdescr()
+ target_token = loop.operations[-1].getdescr()
resumekey.compile_and_attach(metainterp, loop)
+
target_token = label.getdescr()
assert isinstance(target_token, TargetToken)
- target_token.original_jitcell_token = loop.original_jitcell_token
record_loop_or_bridge(metainterp_sd, loop)
return target_token
@@ -281,6 +281,15 @@
assert i == len(inputargs)
loop.operations = extra_ops + loop.operations
+def propagate_original_jitcell_token(trace):
+ for op in trace.operations:
+ if op.getopnum() == rop.LABEL:
+ token = op.getdescr()
+ assert isinstance(token, TargetToken)
+ assert token.original_jitcell_token is None
+ token.original_jitcell_token = trace.original_jitcell_token
+
+
def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type):
vinfo = jitdriver_sd.virtualizable_info
if vinfo is not None:
@@ -554,6 +563,7 @@
inputargs = metainterp.history.inputargs
if not we_are_translated():
self._debug_suboperations = 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)
@@ -740,6 +750,7 @@
jitdriver_sd = metainterp.jitdriver_sd
redargs = new_loop.inputargs
new_loop.original_jitcell_token = jitcell_token = make_jitcell_token(jitdriver_sd)
+ propagate_original_jitcell_token(new_loop)
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
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
@@ -386,6 +386,17 @@
"""
self.optimize_loop(ops, expected)
+ def test_virtual_as_field_of_forced_box(self):
+ ops = """
+ [p0]
+ pv1 = new_with_vtable(ConstClass(node_vtable))
+ label(pv1, p0)
+ pv2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(pv2, pv1, descr=valuedescr)
+ jump(pv1, pv2)
+ """
+ with raises(InvalidLoop):
+ self.optimize_loop(ops, ops)
class OptRenameStrlen(Optimization):
def propagate_forward(self, op):
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -409,7 +409,13 @@
if self.level == LEVEL_CONSTANT:
return
assert 0 <= self.position_in_notvirtuals
- boxes[self.position_in_notvirtuals] = value.force_box(optimizer)
+ if optimizer:
+ box = value.force_box(optimizer)
+ else:
+ if value.is_virtual():
+ raise BadVirtualState
+ box = value.get_key_box()
+ boxes[self.position_in_notvirtuals] = box
def _enum(self, virtual_state):
if self.level == LEVEL_CONSTANT:
@@ -471,8 +477,14 @@
optimizer = optimizer.optearlyforce
assert len(values) == len(self.state)
inputargs = [None] * len(self.notvirtuals)
+
+ # We try twice. The first time around we allow boxes to be forced
+ # which might change the virtual state if the box appear in more
+ # than one place among the inputargs.
for i in range(len(values)):
self.state[i].enum_forced_boxes(inputargs, values[i], optimizer)
+ for i in range(len(values)):
+ self.state[i].enum_forced_boxes(inputargs, values[i], None)
if keyboxes:
for i in range(len(values)):
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
@@ -976,10 +976,13 @@
self.verify_green_args(jitdriver_sd, greenboxes)
self.debug_merge_point(jitdriver_sd, jdindex, self.metainterp.in_recursion,
greenboxes)
-
+
if self.metainterp.seen_loop_header_for_jdindex < 0:
- if not jitdriver_sd.no_loop_header or not any_operation:
+ if not any_operation:
return
+ if self.metainterp.in_recursion or not self.metainterp.get_procedure_token(greenboxes, True):
+ if not jitdriver_sd.no_loop_header:
+ return
# automatically add a loop_header if there is none
self.metainterp.seen_loop_header_for_jdindex = jdindex
#
@@ -2053,9 +2056,15 @@
from pypy.jit.metainterp.resoperation import opname
raise NotImplementedError(opname[opnum])
- def get_procedure_token(self, greenkey):
+ def get_procedure_token(self, greenkey, with_compiled_targets=False):
cell = self.jitdriver_sd.warmstate.jit_cell_at_key(greenkey)
- return cell.get_procedure_token()
+ token = cell.get_procedure_token()
+ if with_compiled_targets:
+ if not token:
+ return None
+ if not token.target_tokens:
+ return None
+ return token
def compile_loop(self, original_boxes, live_arg_boxes, start, resume_at_jump_descr):
num_green_args = self.jitdriver_sd.num_green_args
@@ -2088,11 +2097,9 @@
def compile_trace(self, live_arg_boxes, resume_at_jump_descr):
num_green_args = self.jitdriver_sd.num_green_args
greenkey = live_arg_boxes[:num_green_args]
- target_jitcell_token = self.get_procedure_token(greenkey)
+ target_jitcell_token = self.get_procedure_token(greenkey, True)
if not target_jitcell_token:
return
- if not target_jitcell_token.target_tokens:
- return
self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None,
descr=target_jitcell_token)
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -2697,7 +2697,7 @@
# bridge back to the preamble of the first loop is produced. A guard in
# this bridge is later traced resulting in a failed attempt of retracing
# the second loop.
- self.check_trace_count(8)
+ self.check_trace_count(9)
# FIXME: Add a gloabl retrace counter and test that we are not trying more than 5 times.
diff --git a/pypy/jit/metainterp/test/test_loop.py b/pypy/jit/metainterp/test/test_loop.py
--- a/pypy/jit/metainterp/test/test_loop.py
+++ b/pypy/jit/metainterp/test/test_loop.py
@@ -756,7 +756,7 @@
res = self.meta_interp(interpret, [1])
assert res == interpret(1)
# XXX it's unsure how many loops should be there
- self.check_trace_count(3)
+ self.check_trace_count(2)
def test_path_with_operations_not_from_start(self):
jitdriver = JitDriver(greens = ['k'], reds = ['n', 'z'])
diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py
--- a/pypy/jit/metainterp/test/test_virtual.py
+++ b/pypy/jit/metainterp/test/test_virtual.py
@@ -880,7 +880,7 @@
elif op == 'j':
j = Int(0)
elif op == '+':
- sa += i.val * j.val
+ sa += (i.val + 2) * (j.val + 2)
elif op == 'a':
i = Int(i.val + 1)
elif op == 'b':
@@ -902,6 +902,7 @@
assert res == f(10)
self.check_aborted_count(0)
self.check_target_token_count(3)
+ self.check_resops(int_mul=2)
def test_nested_loops_bridge(self):
class Int(object):
More information about the pypy-commit
mailing list