Commit b072e324 authored by Hakan Ardo's avatar Hakan Ardo
Browse files

Merge jit-improve-nested-loops. It allows bridges to end with a jump to the...

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.
......@@ -169,10 +169,10 @@ def compile_loop(metainterp, greenkey, start,
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 @@ def compile_retrace(metainterp, greenkey, start,
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 @@ def patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd):
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 @@ class ResumeGuardDescr(ResumeDescr):
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 @@ class ResumeFromInterpDescr(ResumeDescr):
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
......
......@@ -386,6 +386,17 @@ class OptimizeoptTestMultiLabel(BaseTestMultiLabel):
"""
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):
......
......@@ -409,7 +409,13 @@ class NotVirtualStateInfo(AbstractVirtualStateInfo):
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 @@ class VirtualState(object):
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)):
......
......@@ -976,10 +976,13 @@ class MIFrame(object):
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 @@ class MetaInterp(object):
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 @@ class MetaInterp(object):
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)
......
......@@ -2697,7 +2697,7 @@ class BasicTests:
# 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.
......
......@@ -756,7 +756,7 @@ class LoopTest(object):
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'])
......
......@@ -880,7 +880,7 @@ class VirtualTests:
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 @@ class VirtualTests:
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):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment